1 | // Copyright (C) 2021 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | #ifndef QQmlTreeModelToTableModel_H |
5 | #define QQmlTreeModelToTableModel_H |
6 | |
7 | // |
8 | // W A R N I N G |
9 | // ------------- |
10 | // |
11 | // This file is not part of the Qt API. It exists purely as an |
12 | // implementation detail. This header file may change from version to |
13 | // version without notice, or even be removed. |
14 | // |
15 | // We mean it. |
16 | // |
17 | |
18 | #include "qtqmlmodelsglobal_p.h" |
19 | |
20 | #include <QtCore/qset.h> |
21 | #include <QtCore/qpointer.h> |
22 | #include <QtCore/qabstractitemmodel.h> |
23 | #include <QtCore/qitemselectionmodel.h> |
24 | |
25 | QT_BEGIN_NAMESPACE |
26 | |
27 | class QAbstractItemModel; |
28 | |
29 | class Q_QMLMODELS_PRIVATE_EXPORT QQmlTreeModelToTableModel : public QAbstractItemModel |
30 | { |
31 | Q_OBJECT |
32 | Q_PROPERTY(QAbstractItemModel *model READ model WRITE setModel NOTIFY modelChanged FINAL) |
33 | Q_PROPERTY(QModelIndex rootIndex READ rootIndex WRITE setRootIndex RESET resetRootIndex NOTIFY rootIndexChanged FINAL) |
34 | |
35 | struct TreeItem; |
36 | |
37 | public: |
38 | explicit QQmlTreeModelToTableModel(QObject *parent = nullptr); |
39 | |
40 | QAbstractItemModel *model() const; |
41 | QModelIndex rootIndex() const; |
42 | void setRootIndex(const QModelIndex &idx); |
43 | void resetRootIndex(); |
44 | |
45 | QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; |
46 | QModelIndex parent(const QModelIndex &child) const override; |
47 | |
48 | int rowCount(const QModelIndex &parent = QModelIndex()) const override; |
49 | int columnCount(const QModelIndex &parent = QModelIndex()) const override; |
50 | |
51 | enum { |
52 | DepthRole = Qt::UserRole - 5, |
53 | ExpandedRole, |
54 | HasChildrenRole, |
55 | HasSiblingRole, |
56 | ModelIndexRole |
57 | }; |
58 | |
59 | QHash<int, QByteArray> roleNames() const override; |
60 | QVariant data(const QModelIndex &, int role) const override; |
61 | bool setData(const QModelIndex &index, const QVariant &value, int role) override; |
62 | QVariant (int section, Qt::Orientation orientation, int role) const override; |
63 | Qt::ItemFlags flags(const QModelIndex &index) const override; |
64 | |
65 | void clearModelData(); |
66 | |
67 | bool isVisible(const QModelIndex &index); |
68 | bool childrenVisible(const QModelIndex &index); |
69 | |
70 | QModelIndex mapToModel(const QModelIndex &index) const; |
71 | QModelIndex mapFromModel(const QModelIndex &index) const; |
72 | QModelIndex mapToModel(int row) const; |
73 | |
74 | Q_INVOKABLE QItemSelection selectionForRowRange(const QModelIndex &fromIndex, const QModelIndex &toIndex) const; |
75 | |
76 | void showModelTopLevelItems(bool doInsertRows = true); |
77 | void showModelChildItems(const TreeItem &parent, int start, int end, bool doInsertRows = true, bool doExpandPendingRows = true); |
78 | |
79 | int itemIndex(const QModelIndex &index) const; |
80 | void expandPendingRows(bool doInsertRows = true); |
81 | int lastChildIndex(const QModelIndex &index) const; |
82 | void removeVisibleRows(int startIndex, int endIndex, bool doRemoveRows = true); |
83 | |
84 | void dump() const; |
85 | bool testConsistency(bool dumpOnFail = false) const; |
86 | |
87 | using QAbstractItemModel::hasChildren; |
88 | |
89 | Q_SIGNALS: |
90 | void modelChanged(QAbstractItemModel *model); |
91 | void rootIndexChanged(); |
92 | void expanded(const QModelIndex &index); |
93 | void collapsed(const QModelIndex &index); |
94 | |
95 | public Q_SLOTS: |
96 | void expand(const QModelIndex &); |
97 | void collapse(const QModelIndex &); |
98 | void setModel(QAbstractItemModel *model); |
99 | bool isExpanded(const QModelIndex &) const; |
100 | bool isExpanded(int row) const; |
101 | bool hasChildren(int row) const; |
102 | bool hasSiblings(int row) const; |
103 | int depthAtRow(int row) const; |
104 | void expandRow(int n); |
105 | void expandRecursively(int row, int depth); |
106 | void collapseRow(int n); |
107 | void collapseRecursively(int row); |
108 | |
109 | private Q_SLOTS: |
110 | void modelHasBeenDestroyed(); |
111 | void modelHasBeenReset(); |
112 | void modelDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles); |
113 | void modelLayoutAboutToBeChanged(const QList<QPersistentModelIndex> &parents, QAbstractItemModel::LayoutChangeHint hint); |
114 | void modelLayoutChanged(const QList<QPersistentModelIndex> &parents, QAbstractItemModel::LayoutChangeHint hint); |
115 | void modelRowsAboutToBeInserted(const QModelIndex & parent, int start, int end); |
116 | void modelRowsAboutToBeMoved(const QModelIndex & sourceParent, int sourceStart, int sourceEnd, const QModelIndex & destinationParent, int destinationRow); |
117 | void modelRowsAboutToBeRemoved(const QModelIndex & parent, int start, int end); |
118 | void modelRowsInserted(const QModelIndex & parent, int start, int end); |
119 | void modelRowsMoved(const QModelIndex & sourceParent, int sourceStart, int sourceEnd, const QModelIndex & destinationParent, int destinationRow); |
120 | void modelRowsRemoved(const QModelIndex & parent, int start, int end); |
121 | |
122 | private: |
123 | struct TreeItem { |
124 | QPersistentModelIndex index; |
125 | int depth; |
126 | bool expanded; |
127 | |
128 | explicit TreeItem(const QModelIndex &idx = QModelIndex(), int d = 0, int e = false) |
129 | : index(idx), depth(d), expanded(e) |
130 | { } |
131 | |
132 | inline bool operator== (const TreeItem &other) const |
133 | { |
134 | return this->index == other.index; |
135 | } |
136 | }; |
137 | |
138 | struct DataChangedParams { |
139 | QModelIndex topLeft; |
140 | QModelIndex bottomRight; |
141 | QVector<int> roles; |
142 | }; |
143 | |
144 | struct SignalFreezer { |
145 | SignalFreezer(QQmlTreeModelToTableModel *parent) : m_parent(parent) { |
146 | m_parent->enableSignalAggregation(); |
147 | } |
148 | ~SignalFreezer() { m_parent->disableSignalAggregation(); } |
149 | |
150 | private: |
151 | QQmlTreeModelToTableModel *m_parent; |
152 | }; |
153 | |
154 | void enableSignalAggregation(); |
155 | void disableSignalAggregation(); |
156 | bool isAggregatingSignals() const { return m_signalAggregatorStack > 0; } |
157 | void queueDataChanged(const QModelIndex &topLeft, |
158 | const QModelIndex &bottomRight, |
159 | const QVector<int> &roles); |
160 | void emitQueuedSignals(); |
161 | |
162 | QPointer<QAbstractItemModel> m_model = nullptr; |
163 | QPersistentModelIndex m_rootIndex; |
164 | QList<TreeItem> m_items; |
165 | QSet<QPersistentModelIndex> m_expandedItems; |
166 | QList<TreeItem> m_itemsToExpand; |
167 | mutable int m_lastItemIndex = 0; |
168 | bool m_visibleRowsMoved = false; |
169 | bool m_modelLayoutChanged = false; |
170 | int m_signalAggregatorStack = 0; |
171 | QVector<DataChangedParams> m_queuedDataChanged; |
172 | int m_column = 0; |
173 | }; |
174 | |
175 | QT_END_NAMESPACE |
176 | |
177 | #endif // QQmlTreeModelToTableModel_H |
178 | |