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

source code of qtgraphs/src/graphs/data/abstractitemmodelhandler.cpp