1 | // Copyright (C) 2023 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only |
3 | |
4 | #include "abstractitemmodelhandler_p.h" |
5 | |
6 | QT_BEGIN_NAMESPACE |
7 | |
8 | AbstractItemModelHandler::AbstractItemModelHandler(QObject *parent) |
9 | : QObject(parent) |
10 | , resolvePending(0) |
11 | , m_fullReset(true) |
12 | { |
13 | m_resolveTimer.setSingleShot(true); |
14 | QObject::connect(sender: &m_resolveTimer, |
15 | signal: &QTimer::timeout, |
16 | context: this, |
17 | slot: &AbstractItemModelHandler::handlePendingResolve); |
18 | } |
19 | |
20 | AbstractItemModelHandler::~AbstractItemModelHandler() {} |
21 | |
22 | void AbstractItemModelHandler::setItemModel(QAbstractItemModel *itemModel) |
23 | { |
24 | if (itemModel != m_itemModel.data()) { |
25 | if (!m_itemModel.isNull()) |
26 | QObject::disconnect(sender: m_itemModel, signal: 0, receiver: this, member: 0); |
27 | |
28 | m_itemModel = itemModel; |
29 | |
30 | if (!m_itemModel.isNull()) { |
31 | QObject::connect(sender: m_itemModel.data(), |
32 | signal: &QAbstractItemModel::columnsInserted, |
33 | context: this, |
34 | slot: &AbstractItemModelHandler::handleColumnsInserted); |
35 | QObject::connect(sender: m_itemModel.data(), |
36 | signal: &QAbstractItemModel::columnsMoved, |
37 | context: this, |
38 | slot: &AbstractItemModelHandler::handleColumnsMoved); |
39 | QObject::connect(sender: m_itemModel.data(), |
40 | signal: &QAbstractItemModel::columnsRemoved, |
41 | context: this, |
42 | slot: &AbstractItemModelHandler::handleColumnsRemoved); |
43 | QObject::connect(sender: m_itemModel.data(), |
44 | signal: &QAbstractItemModel::dataChanged, |
45 | context: this, |
46 | slot: &AbstractItemModelHandler::handleDataChanged); |
47 | QObject::connect(sender: m_itemModel.data(), |
48 | signal: &QAbstractItemModel::layoutChanged, |
49 | context: this, |
50 | slot: &AbstractItemModelHandler::handleLayoutChanged); |
51 | QObject::connect(sender: m_itemModel.data(), |
52 | signal: &QAbstractItemModel::modelReset, |
53 | context: this, |
54 | slot: &AbstractItemModelHandler::handleModelReset); |
55 | QObject::connect(sender: m_itemModel.data(), |
56 | signal: &QAbstractItemModel::rowsInserted, |
57 | context: this, |
58 | slot: &AbstractItemModelHandler::handleRowsInserted); |
59 | QObject::connect(sender: m_itemModel.data(), |
60 | signal: &QAbstractItemModel::rowsMoved, |
61 | context: this, |
62 | slot: &AbstractItemModelHandler::handleRowsMoved); |
63 | QObject::connect(sender: m_itemModel.data(), |
64 | signal: &QAbstractItemModel::rowsRemoved, |
65 | context: this, |
66 | slot: &AbstractItemModelHandler::handleRowsRemoved); |
67 | } |
68 | if (!m_resolveTimer.isActive()) |
69 | m_resolveTimer.start(msec: 0); |
70 | |
71 | emit itemModelChanged(itemModel); |
72 | } |
73 | } |
74 | |
75 | QAbstractItemModel *AbstractItemModelHandler::itemModel() const |
76 | { |
77 | return m_itemModel.data(); |
78 | } |
79 | |
80 | void AbstractItemModelHandler::handleColumnsInserted(const QModelIndex &parent, int start, int end) |
81 | { |
82 | Q_UNUSED(parent); |
83 | Q_UNUSED(start); |
84 | Q_UNUSED(end); |
85 | |
86 | // Manipulating columns changes all rows in proxies that map rows/columns |
87 | // directly, and its effects are not clearly defined in others -> always do |
88 | // full reset. |
89 | if (!m_resolveTimer.isActive()) { |
90 | m_fullReset = true; |
91 | m_resolveTimer.start(msec: 0); |
92 | } |
93 | } |
94 | |
95 | void AbstractItemModelHandler::handleColumnsMoved(const QModelIndex &sourceParent, |
96 | int sourceStart, |
97 | int sourceEnd, |
98 | const QModelIndex &destinationParent, |
99 | int destinationColumn) |
100 | { |
101 | Q_UNUSED(sourceParent); |
102 | Q_UNUSED(sourceStart); |
103 | Q_UNUSED(sourceEnd); |
104 | Q_UNUSED(destinationParent); |
105 | Q_UNUSED(destinationColumn); |
106 | |
107 | // Manipulating columns changes all rows in proxies that map rows/columns |
108 | // directly, and its effects are not clearly defined in others -> always do |
109 | // full reset. |
110 | if (!m_resolveTimer.isActive()) { |
111 | m_fullReset = true; |
112 | m_resolveTimer.start(msec: 0); |
113 | } |
114 | } |
115 | |
116 | void AbstractItemModelHandler::handleColumnsRemoved(const QModelIndex &parent, int start, int end) |
117 | { |
118 | Q_UNUSED(parent); |
119 | Q_UNUSED(start); |
120 | Q_UNUSED(end); |
121 | |
122 | // Manipulating columns changes all rows in proxies that map rows/columns |
123 | // directly, and its effects are not clearly defined in others -> always do |
124 | // full reset. |
125 | if (!m_resolveTimer.isActive()) { |
126 | m_fullReset = true; |
127 | m_resolveTimer.start(msec: 0); |
128 | } |
129 | } |
130 | |
131 | void AbstractItemModelHandler::handleDataChanged(const QModelIndex &topLeft, |
132 | const QModelIndex &bottomRight, |
133 | const QList<int> &roles) |
134 | { |
135 | Q_UNUSED(topLeft); |
136 | Q_UNUSED(bottomRight); |
137 | Q_UNUSED(roles); |
138 | |
139 | // Default handling for dataChanged is to do full reset, as it cannot be |
140 | // optimized in a general case, where we do not know which row/column/index |
141 | // the item model item actually ended up to in the proxy. |
142 | if (!m_resolveTimer.isActive()) { |
143 | m_fullReset = true; |
144 | m_resolveTimer.start(msec: 0); |
145 | } |
146 | } |
147 | |
148 | void AbstractItemModelHandler::handleLayoutChanged(const QList<QPersistentModelIndex> &parents, |
149 | QAbstractItemModel::LayoutChangeHint hint) |
150 | { |
151 | Q_UNUSED(parents); |
152 | Q_UNUSED(hint); |
153 | |
154 | // Resolve entire model if layout changes |
155 | if (!m_resolveTimer.isActive()) { |
156 | m_fullReset = true; |
157 | m_resolveTimer.start(msec: 0); |
158 | } |
159 | } |
160 | |
161 | void AbstractItemModelHandler::handleModelReset() |
162 | { |
163 | // Data cleared, reset array |
164 | if (!m_resolveTimer.isActive()) { |
165 | m_fullReset = true; |
166 | m_resolveTimer.start(msec: 0); |
167 | } |
168 | } |
169 | |
170 | void AbstractItemModelHandler::handleRowsInserted(const QModelIndex &parent, int start, int end) |
171 | { |
172 | Q_UNUSED(parent); |
173 | Q_UNUSED(start); |
174 | Q_UNUSED(end); |
175 | |
176 | // Default handling for rowsInserted is to do full reset, as it cannot be |
177 | // optimized in a general case, where we do not know which row/column/index |
178 | // the item model item actually ended up to in the proxy. |
179 | if (!m_resolveTimer.isActive()) { |
180 | m_fullReset = true; |
181 | m_resolveTimer.start(msec: 0); |
182 | } |
183 | } |
184 | |
185 | void AbstractItemModelHandler::handleRowsMoved(const QModelIndex &sourceParent, |
186 | int sourceStart, |
187 | int sourceEnd, |
188 | const QModelIndex &destinationParent, |
189 | int destinationRow) |
190 | { |
191 | Q_UNUSED(sourceParent); |
192 | Q_UNUSED(sourceStart); |
193 | Q_UNUSED(sourceEnd); |
194 | Q_UNUSED(destinationParent); |
195 | Q_UNUSED(destinationRow); |
196 | |
197 | // Default handling for rowsMoved is to do full reset, as it cannot be |
198 | // optimized in a general case, where we do not know which row/column/index |
199 | // the item model item actually ended up to in the proxy. |
200 | if (!m_resolveTimer.isActive()) { |
201 | m_fullReset = true; |
202 | m_resolveTimer.start(msec: 0); |
203 | } |
204 | } |
205 | |
206 | void AbstractItemModelHandler::handleRowsRemoved(const QModelIndex &parent, int start, int end) |
207 | { |
208 | Q_UNUSED(parent); |
209 | Q_UNUSED(start); |
210 | Q_UNUSED(end); |
211 | |
212 | // Default handling for rowsRemoved is to do full reset, as it cannot be |
213 | // optimized in a general case, where we do not know which row/column/index |
214 | // the item model item actually ended up to in the proxy. |
215 | if (!m_resolveTimer.isActive()) { |
216 | m_fullReset = true; |
217 | m_resolveTimer.start(msec: 0); |
218 | } |
219 | } |
220 | |
221 | void AbstractItemModelHandler::handleMappingChanged() |
222 | { |
223 | if (!m_resolveTimer.isActive()) |
224 | m_resolveTimer.start(msec: 0); |
225 | } |
226 | |
227 | void AbstractItemModelHandler::handlePendingResolve() |
228 | { |
229 | resolveModel(); |
230 | m_fullReset = false; |
231 | } |
232 | |
233 | QT_END_NAMESPACE |
234 | |