File indexing completed on 2024-04-14 04:45:52
0001 /* 0002 SPDX-FileCopyrightText: 2017 Nicolas Carion 0003 SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0004 */ 0005 0006 #pragma once 0007 0008 #include "definitions.h" 0009 #include <QList> 0010 #include <QVariant> 0011 #include <memory> 0012 #include <unordered_map> 0013 0014 class AbstractTreeModel; 0015 0016 /** @class TreeItem 0017 @brief This class is a generic class to represent items of a tree-like model. 0018 It works in tandem with AbstractTreeModel or one of its derived classes. 0019 There is a registration mechanism that takes place: each TreeItem holds a unique Id 0020 that can allow to retrieve it directly from the model. 0021 0022 A TreeItem registers itself to the model as soon as it gets a proper parent (the node 0023 above it in the hierarchy). This means that upon creation, the TreeItem is NOT 0024 registered, because at this point it doesn't belong to any parent. 0025 The only exception is for the rootItem, which is always registered. 0026 0027 Note that the root is a special object. In particular, it must stay at the root and 0028 must not be declared as the child of any other item. 0029 */ 0030 class TreeItem : public enable_shared_from_this_virtual<TreeItem> 0031 { 0032 public: 0033 /** @brief Construct a TreeItem 0034 @param data List of data elements (columns) of the created item 0035 @param model Pointer to the model to which this elem belongs to 0036 @param parentItem address of the parent if the child is not orphan 0037 @param isRoot is true if the object is the topmost item of the tree 0038 @param id of the newly created item. If left to -1, the id is assigned automatically 0039 @return a ptr to the constructed item 0040 */ 0041 static std::shared_ptr<TreeItem> construct(const QList<QVariant> &data, const std::shared_ptr<AbstractTreeModel> &model, bool isRoot, int id = -1); 0042 0043 friend class AbstractTreeModel; 0044 0045 protected: 0046 // This is protected. Call construct instead 0047 explicit TreeItem(QList<QVariant> data, const std::shared_ptr<AbstractTreeModel> &model, bool isRoot, int id = -1); 0048 0049 public: 0050 virtual ~TreeItem(); 0051 0052 /** @brief Creates a child of the current item 0053 @param data: List of data elements (columns) to init the child with. 0054 */ 0055 std::shared_ptr<TreeItem> appendChild(const QList<QVariant> &data); 0056 0057 /** @brief Appends an already created child 0058 Useful for example if the child should be a subclass of TreeItem 0059 @return true on success. Otherwise, nothing is modified. 0060 */ 0061 bool appendChild(const std::shared_ptr<TreeItem> &child); 0062 void moveChild(int ix, const std::shared_ptr<TreeItem> &child); 0063 0064 /** @brief Remove given child from children list. The parent of the child is updated 0065 accordingly 0066 */ 0067 void removeChild(const std::shared_ptr<TreeItem> &child); 0068 0069 /** @brief Change the parent of the current item. Structures are modified accordingly 0070 */ 0071 virtual bool changeParent(std::shared_ptr<TreeItem> newParent); 0072 0073 /** @brief Retrieves a child of the current item 0074 @param row is the index of the child to retrieve 0075 */ 0076 std::shared_ptr<TreeItem> child(int row) const; 0077 0078 /** @brief Returns a vector containing a pointer to all the leaves in the subtree rooted in this element */ 0079 std::vector<std::shared_ptr<TreeItem>> getLeaves(); 0080 0081 /** @brief Return the number of children */ 0082 int childCount() const; 0083 0084 /** @brief Return the number of data fields (columns) */ 0085 int columnCount() const; 0086 0087 /** @brief Return the content of a column 0088 @param column Index of the column to look-up 0089 */ 0090 QVariant dataColumn(int column) const; 0091 void setData(int column, const QVariant &dataColumn); 0092 0093 /** @brief Return the index of current item amongst father's children 0094 Returns -1 on error (eg: no parent set) 0095 */ 0096 int row() const; 0097 0098 /** @brief Return a ptr to the parent item 0099 */ 0100 std::weak_ptr<TreeItem> parentItem() const; 0101 0102 /** @brief Return the depth of the current item*/ 0103 int depth() const; 0104 0105 /** @brief Return the id of the current item*/ 0106 int getId() const; 0107 0108 /** @brief Return true if the current item has been registered */ 0109 bool isInModel() const; 0110 0111 /** @brief This is similar to the std::accumulate function, except that it 0112 operates on the whole subtree 0113 @param init is the initial value of the operation 0114 @param is the binary op to apply (signature should be (T, shared_ptr<TreeItem>)->T) 0115 */ 0116 template <class T, class BinaryOperation> T accumulate(T init, BinaryOperation op); 0117 template <class T, class BinaryOperation> T accumulate_const(T init, BinaryOperation op) const; 0118 0119 /** @brief Return true if the current item has the item with given id as an ancestor */ 0120 bool hasAncestor(int id); 0121 0122 /** @brief Return true if the item thinks it is a root. 0123 Note that it should be consistent with what the model thinks, but it may have been 0124 messed up at some point if someone wrongly constructed the object with isRoot = true */ 0125 bool isRoot() const; 0126 0127 protected: 0128 /** @brief Finish construction of object given its pointer 0129 This is a separated function so that it can be called from derived classes */ 0130 static void baseFinishConstruct(const std::shared_ptr<TreeItem> &self); 0131 0132 /** @brief Helper functions to handle registration / deregistration to the model */ 0133 static void registerSelf(const std::shared_ptr<TreeItem> &self); 0134 void deregisterSelf(); 0135 0136 /** @brief Reflect update of the parent ptr (for example set the correct depth) 0137 This is meant to be overridden in derived classes 0138 @param ptr is the pointer to the new parent 0139 */ 0140 virtual void updateParent(std::shared_ptr<TreeItem> parent); 0141 0142 std::list<std::shared_ptr<TreeItem>> m_childItems; 0143 std::unordered_map<int, std::list<std::shared_ptr<TreeItem>>::iterator> 0144 m_iteratorTable; // this logs the iterator associated which each child id. This allows easy access of a child based on its id. 0145 0146 QList<QVariant> m_itemData; 0147 std::weak_ptr<TreeItem> m_parentItem; 0148 0149 std::weak_ptr<AbstractTreeModel> m_model; 0150 int m_depth; 0151 int m_id; 0152 bool m_isInModel; 0153 bool m_isRoot; 0154 bool m_isInvalid; 0155 }; 0156 0157 template <class T, class BinaryOperation> T TreeItem::accumulate(T init, BinaryOperation op) 0158 { 0159 T res = op(init, shared_from_this()); 0160 for (const auto &c : m_childItems) { 0161 res = c->accumulate(res, op); 0162 } 0163 return res; 0164 } 0165 template <class T, class BinaryOperation> T TreeItem::accumulate_const(T init, BinaryOperation op) const 0166 { 0167 T res = op(init, shared_from_this()); 0168 for (const auto &c : m_childItems) { 0169 res = c->accumulate_const(res, op); 0170 } 0171 return res; 0172 }