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 }