1 /*
2  * SPDX-FileCopyrightText: 2014 Christian Mollekopf <mollekopf@kolabsys.com>
3  *
4  * SPDX-License-Identifier: GPL-2.0-or-later WITH Qt-Commercial-exception-1.0
5  */
6 
7 #pragma once
8 
9 #include <QAbstractProxyModel>
10 #include <QSharedPointer>
11 #include <QVector>
12 
13 /**
14  * A model that can hold an extra set of nodes which can "adopt" (reparent),
15  * source nodes.
16  */
17 class ReparentingModel : public QAbstractProxyModel
18 {
19     Q_OBJECT
20 public:
21     struct Node {
22         using Ptr = QSharedPointer<Node>;
23         virtual ~Node();
24         virtual bool operator==(const Node &) const;
25 
26     protected:
27         Node(ReparentingModel &personModel);
28 
29     private:
30         friend class ReparentingModel;
31         Node(ReparentingModel &personModel, Node *parent, const QModelIndex &sourceIndex);
32         virtual QVariant data(int role) const;
33         virtual bool setData(const QVariant &variant, int role);
34         virtual bool adopts(const QModelIndex &sourceIndex);
35         virtual bool isDuplicateOf(const QModelIndex &sourceIndex);
36         virtual void update(const Node::Ptr &node);
37 
38         bool isSourceNode() const;
39         Node::Ptr searchNode(Node *node);
40         void reparent(Node *node);
41         void addChild(const Node::Ptr &node);
42         int row() const;
43         void clearHierarchy();
44 
45         QPersistentModelIndex sourceIndex;
46         QVector<Ptr> children;
47         Node *parent = nullptr;
48         ReparentingModel &personModel;
49         const bool mIsSourceNode = false;
50     };
51 
52     struct NodeManager {
53         using Ptr = QSharedPointer<NodeManager>;
54 
NodeManagerNodeManager55         NodeManager(ReparentingModel &m)
56             : model(m)
57         {
58         }
59 
~NodeManagerNodeManager60         virtual ~NodeManager()
61         {
62         }
63 
64     protected:
65         ReparentingModel &model;
66 
67     private:
68         friend class ReparentingModel;
69 
70         // Allows the implementation to create proxy nodes as necessary
checkSourceIndexNodeManager71         virtual void checkSourceIndex(const QModelIndex & /* sourceIndex */)
72         {
73         }
74 
checkSourceIndexRemovalNodeManager75         virtual void checkSourceIndexRemoval(const QModelIndex & /* sourceIndex */)
76         {
77         }
78 
updateSourceIndexNodeManager79         virtual void updateSourceIndex(const QModelIndex &sourceIndex)
80         {
81             checkSourceIndex(sourceIndex);
82         }
83     };
84 
85 public:
86     explicit ReparentingModel(QObject *parent = nullptr);
87     ~ReparentingModel() override;
88 
89     void setNodeManager(const NodeManager::Ptr &nodeManager);
90     void addNode(const Node::Ptr &node);
91     void updateNode(const Node::Ptr &node);
92     void removeNode(const Node &node);
93     void setNodes(const QList<Node::Ptr> &nodes);
94     void clear();
95 
96     int rowCount(const QModelIndex &parent = QModelIndex()) const override;
97     int columnCount(const QModelIndex &parent = QModelIndex()) const override;
98     QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
99     QModelIndex parent(const QModelIndex &child) const override;
100     QVariant data(const QModelIndex &proxyIndex, int role = Qt::DisplayRole) const override;
101     bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
102     Qt::ItemFlags flags(const QModelIndex &index) const override;
103     bool hasChildren(const QModelIndex &parent = QModelIndex()) const override;
104     QModelIndex buddy(const QModelIndex &index) const override;
105 
106     void setSourceModel(QAbstractItemModel *sourceModel) override;
107     QModelIndex mapFromSource(const QModelIndex &sourceIndex) const override;
108     QModelIndex mapToSource(const QModelIndex &proxyIndex) const override;
109 
110 private Q_SLOTS:
111     void onSourceRowsAboutToBeInserted(const QModelIndex &, int, int);
112     void onSourceRowsInserted(const QModelIndex &, int, int);
113     void onSourceRowsAboutToBeRemoved(const QModelIndex &, int, int);
114     void onSourceRowsRemoved(const QModelIndex &, int, int);
115     void onSourceRowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int);
116     void onSourceRowsMoved(const QModelIndex &, int, int, const QModelIndex &, int);
117     void onSourceDataChanged(const QModelIndex &, const QModelIndex &);
118     void onSourceLayoutAboutToBeChanged();
119     void onSourceLayoutChanged();
120     void onSourceModelAboutToBeReset();
121     void onSourceModelReset();
122     void doAddNode(const Node::Ptr &node);
123 
124 private:
125     void rebuildFromSource(Node *parentNode, const QModelIndex &idx, const QModelIndexList &skip = QModelIndexList());
126     bool isDuplicate(const Node::Ptr &proxyNode) const;
127     void insertProxyNode(const Node::Ptr &proxyNode);
128     void reparentSourceNodes(const Node::Ptr &proxyNode);
129     void rebuildAll();
130     QModelIndex index(Node *node) const;
131     int row(Node *node) const;
132     Node *getReparentNode(const QModelIndex &sourceIndex);
133     Node *getParentNode(const QModelIndex &sourceIndex);
134     bool validateNode(const Node *node) const;
135     Node *extractNode(const QModelIndex &index) const;
136     void appendSourceNode(Node *parentNode, const QModelIndex &sourceIndex, const QModelIndexList &skip = QModelIndexList());
137     QModelIndexList descendants(const QModelIndex &sourceIndex);
138     void removeDuplicates(const QModelIndex &sourceIndex);
139     Node *getSourceNode(const QModelIndex &sourceIndex) const;
140 
141     Node mRootNode;
142     QList<Node *> mSourceNodes;
143     QVector<Node::Ptr> mProxyNodes;
144     QVector<Node::Ptr> mNodesToAdd;
145     NodeManager::Ptr mNodeManager;
146 };
147 
148