1// Copyright (C) 2017 Ford Motor Company
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
5#include "qremoteobjectabstractitemmodeladapter_p.h"
6
7#include <QtCore/qitemselectionmodel.h>
8
9inline QList<QModelRoleData> createModelRoleData(const QList<int> &roles)
10{
11 QList<QModelRoleData> roleData;
12 roleData.reserve(asize: roles.size());
13 for (int role : roles)
14 roleData.emplace_back(args&: role);
15 return roleData;
16}
17
18// consider evaluating performance difference with item data
19inline QVariantList collectData(const QModelIndex &index, const QAbstractItemModel *model,
20 QModelRoleDataSpan roleDataSpan)
21{
22 model->multiData(index, roleDataSpan);
23
24 QVariantList result;
25 result.reserve(asize: roleDataSpan.size());
26 for (auto &roleData : roleDataSpan)
27 result.push_back(t: std::move(roleData.data()));
28
29 return result;
30}
31
32inline QList<int> filterRoles(const QList<int> &roles, const QList<int> &availableRoles)
33{
34 if (roles.isEmpty())
35 return availableRoles;
36
37 QList<int> neededRoles;
38 for (int inRole : roles) {
39 for (int availableRole : availableRoles)
40 if (inRole == availableRole) {
41 neededRoles << inRole;
42 continue;
43 }
44 }
45 return neededRoles;
46}
47
48QAbstractItemModelSourceAdapter::QAbstractItemModelSourceAdapter(QAbstractItemModel *obj, QItemSelectionModel *sel, const QList<int> &roles)
49 : QObject(obj),
50 m_model(obj),
51 m_availableRoles(roles)
52{
53 QAbstractItemModelSourceAdapter::registerTypes();
54 m_selectionModel = sel;
55 connect(sender: m_model, signal: &QAbstractItemModel::dataChanged, context: this, slot: &QAbstractItemModelSourceAdapter::sourceDataChanged);
56 connect(sender: m_model, signal: &QAbstractItemModel::rowsInserted, context: this, slot: &QAbstractItemModelSourceAdapter::sourceRowsInserted);
57 connect(sender: m_model, signal: &QAbstractItemModel::columnsInserted, context: this, slot: &QAbstractItemModelSourceAdapter::sourceColumnsInserted);
58 connect(sender: m_model, signal: &QAbstractItemModel::rowsRemoved, context: this, slot: &QAbstractItemModelSourceAdapter::sourceRowsRemoved);
59 connect(sender: m_model, signal: &QAbstractItemModel::rowsMoved, context: this, slot: &QAbstractItemModelSourceAdapter::sourceRowsMoved);
60 connect(sender: m_model, signal: &QAbstractItemModel::layoutChanged, context: this, slot: &QAbstractItemModelSourceAdapter::sourceLayoutChanged);
61 if (m_selectionModel)
62 connect(sender: m_selectionModel, signal: &QItemSelectionModel::currentChanged, context: this, slot: &QAbstractItemModelSourceAdapter::sourceCurrentChanged);
63}
64
65void QAbstractItemModelSourceAdapter::registerTypes()
66{
67 static bool alreadyRegistered = false;
68 if (alreadyRegistered)
69 return;
70
71 alreadyRegistered = true;
72 qRegisterMetaType<QAbstractItemModel*>();
73 qRegisterMetaType<Qt::Orientation>();
74 qRegisterMetaType<QList<Qt::Orientation>>();
75 qRegisterMetaType<QtPrivate::ModelIndex>();
76 qRegisterMetaType<QtPrivate::IndexList>();
77 qRegisterMetaType<QtPrivate::DataEntries>();
78 qRegisterMetaType<QtPrivate::MetaAndDataEntries>();
79 qRegisterMetaType<QItemSelectionModel::SelectionFlags>();
80 qRegisterMetaType<QSize>();
81 qRegisterMetaType<QIntHash>();
82 qRegisterMetaType<QList<int>>();
83}
84
85QItemSelectionModel* QAbstractItemModelSourceAdapter::selectionModel() const
86{
87 return m_selectionModel;
88}
89
90QSize QAbstractItemModelSourceAdapter::replicaSizeRequest(QtPrivate::IndexList parentList)
91{
92 QModelIndex parent = toQModelIndex(list: parentList, model: m_model);
93 const int rowCount = m_model->rowCount(parent);
94 const int columnCount = m_model->columnCount(parent);
95 const QSize size(columnCount, rowCount);
96 qCDebug(QT_REMOTEOBJECT_MODELS) << "parent" << parentList << "size=" << size;
97 return size;
98}
99
100void QAbstractItemModelSourceAdapter::replicaSetData(const QtPrivate::IndexList &index, const QVariant &value, int role)
101{
102 const QModelIndex modelIndex = toQModelIndex(list: index, model: m_model);
103 Q_ASSERT(modelIndex.isValid());
104 const bool result = m_model->setData(index: modelIndex, value, role);
105 Q_ASSERT(result);
106 Q_UNUSED(result)
107}
108
109QtPrivate::DataEntries QAbstractItemModelSourceAdapter::replicaRowRequest(QtPrivate::IndexList start, QtPrivate::IndexList end, QList<int> roles)
110{
111 qCDebug(QT_REMOTEOBJECT_MODELS) << "Requested rows" << "start=" << start << "end=" << end << "roles=" << roles;
112
113 Q_ASSERT(start.size() == end.size());
114 Q_ASSERT(!start.isEmpty());
115
116 if (roles.isEmpty())
117 roles << m_availableRoles;
118
119 QtPrivate::IndexList parentList = start;
120 Q_ASSERT(!parentList.isEmpty());
121 parentList.pop_back();
122 QModelIndex parent = toQModelIndex(list: parentList, model: m_model);
123
124 const int startRow = start.last().row;
125 const int startColumn = start.last().column;
126 const int rowCount = m_model->rowCount(parent);
127 const int columnCount = m_model->columnCount(parent);
128
129 QtPrivate::DataEntries entries;
130 if (rowCount <= 0)
131 return entries;
132 const int endRow = std::min(a: end.last().row, b: rowCount - 1);
133 const int endColumn = std::min(a: end.last().column, b: columnCount - 1);
134 Q_ASSERT_X(endRow >= 0 && endRow < rowCount, __FUNCTION__, qPrintable(QString(QLatin1String("0 <= %1 < %2")).arg(endRow).arg(rowCount)));
135 Q_ASSERT_X(endColumn >= 0 && endColumn < columnCount, __FUNCTION__, qPrintable(QString(QLatin1String("0 <= %1 < %2")).arg(endColumn).arg(columnCount)));
136
137 auto roleData = createModelRoleData(roles);
138 for (int row = startRow; row <= endRow; ++row) {
139 for (int column = startColumn; column <= endColumn; ++column) {
140 const QModelIndex current = m_model->index(row, column, parent);
141 Q_ASSERT(current.isValid());
142 const QtPrivate::IndexList currentList = QtPrivate::toModelIndexList(index: current, model: m_model);
143 const QVariantList data = collectData(index: current, model: m_model, roleDataSpan: roleData);
144 const bool hasChildren = m_model->hasChildren(parent: current);
145 const Qt::ItemFlags flags = m_model->flags(index: current);
146 qCDebug(QT_REMOTEOBJECT_MODELS) << Q_FUNC_INFO << "current=" << currentList << "data=" << data;
147 entries.data << QtPrivate::IndexValuePair(currentList, data, hasChildren, flags);
148 }
149 }
150 return entries;
151}
152
153QtPrivate::MetaAndDataEntries QAbstractItemModelSourceAdapter::replicaCacheRequest(size_t size, const QList<int> &roles)
154{
155 QtPrivate::MetaAndDataEntries res;
156 res.roles = roles.isEmpty() ? m_availableRoles : roles;
157 res.data = fetchTree(parent: QModelIndex {}, size, roles: res.roles);
158 const int rowCount = m_model->rowCount(parent: QModelIndex{});
159 const int columnCount = m_model->columnCount(parent: QModelIndex{});
160 res.size = QSize{columnCount, rowCount};
161 return res;
162}
163
164QVariantList QAbstractItemModelSourceAdapter::replicaHeaderRequest(QList<Qt::Orientation> orientations, QList<int> sections, QList<int> roles)
165{
166 qCDebug(QT_REMOTEOBJECT_MODELS) << Q_FUNC_INFO << "orientations=" << orientations << "sections=" << sections << "roles=" << roles;
167 QVariantList data;
168 Q_ASSERT(roles.size() == sections.size());
169 Q_ASSERT(roles.size() == orientations.size());
170 for (int i = 0; i < roles.size(); ++i) {
171 data << m_model->headerData(section: sections[i], orientation: orientations[i], role: roles[i]);
172 }
173 return data;
174}
175
176void QAbstractItemModelSourceAdapter::replicaSetCurrentIndex(QtPrivate::IndexList index, QItemSelectionModel::SelectionFlags command)
177{
178 if (m_selectionModel)
179 m_selectionModel->setCurrentIndex(index: toQModelIndex(list: index, model: m_model), command);
180}
181
182void QAbstractItemModelSourceAdapter::sourceDataChanged(const QModelIndex & topLeft, const QModelIndex & bottomRight, const QList<int> & roles) const
183{
184 QList<int> neededRoles = filterRoles(roles, availableRoles: availableRoles());
185 if (neededRoles.isEmpty()) {
186 qCDebug(QT_REMOTEOBJECT_MODELS) << Q_FUNC_INFO << "Needed roles is empty!";
187 return;
188 }
189 Q_ASSERT(topLeft.isValid());
190 Q_ASSERT(bottomRight.isValid());
191 QtPrivate::IndexList start = QtPrivate::toModelIndexList(index: topLeft, model: m_model);
192 QtPrivate::IndexList end = QtPrivate::toModelIndexList(index: bottomRight, model: m_model);
193 qCDebug(QT_REMOTEOBJECT_MODELS) << Q_FUNC_INFO << "start=" << start << "end=" << end << "neededRoles=" << neededRoles;
194 emit dataChanged(topLeft: start, bottomRight: end, roles: neededRoles);
195}
196
197void QAbstractItemModelSourceAdapter::sourceRowsInserted(const QModelIndex & parent, int start, int end)
198{
199 QtPrivate::IndexList parentList = QtPrivate::toModelIndexList(index: parent, model: m_model);
200 emit rowsInserted(parent: parentList, start, end);
201}
202
203void QAbstractItemModelSourceAdapter::sourceColumnsInserted(const QModelIndex & parent, int start, int end)
204{
205 QtPrivate::IndexList parentList = QtPrivate::toModelIndexList(index: parent, model: m_model);
206 emit columnsInserted(parent: parentList, start, end);
207}
208
209void QAbstractItemModelSourceAdapter::sourceRowsRemoved(const QModelIndex & parent, int start, int end)
210{
211 QtPrivate::IndexList parentList = QtPrivate::toModelIndexList(index: parent, model: m_model);
212 emit rowsRemoved(parent: parentList, start, end);
213}
214
215void QAbstractItemModelSourceAdapter::sourceRowsMoved(const QModelIndex & sourceParent, int sourceRow, int count, const QModelIndex & destinationParent, int destinationChild) const
216{
217 emit rowsMoved(sourceParent: QtPrivate::toModelIndexList(index: sourceParent, model: m_model), sourceRow, count, destinationParent: QtPrivate::toModelIndexList(index: destinationParent, model: m_model), destinationChild);
218}
219
220void QAbstractItemModelSourceAdapter::sourceCurrentChanged(const QModelIndex & current, const QModelIndex & previous)
221{
222 QtPrivate::IndexList currentIndex = QtPrivate::toModelIndexList(index: current, model: m_model);
223 QtPrivate::IndexList previousIndex = QtPrivate::toModelIndexList(index: previous, model: m_model);
224 qCDebug(QT_REMOTEOBJECT_MODELS) << Q_FUNC_INFO << "current=" << currentIndex << "previous=" << previousIndex;
225 emit currentChanged(current: currentIndex, previous: previousIndex);
226}
227
228void QAbstractItemModelSourceAdapter::sourceLayoutChanged(const QList<QPersistentModelIndex> &parents, QAbstractItemModel::LayoutChangeHint hint)
229{
230 QtPrivate::IndexList indexes;
231 for (const QPersistentModelIndex &idx : parents)
232 indexes << QtPrivate::toModelIndexList(index: (QModelIndex)idx, model: m_model);
233 emit layoutChanged(parents: indexes, hint);
234}
235
236QList<QtPrivate::IndexValuePair> QAbstractItemModelSourceAdapter::fetchTree(const QModelIndex &parent, size_t &size, const QList<int> &roles)
237{
238 QList<QtPrivate::IndexValuePair> entries;
239 const int rowCount = m_model->rowCount(parent);
240 const int columnCount = m_model->columnCount(parent);
241 if (!columnCount || !rowCount)
242 return entries;
243 entries.reserve(asize: std::min(a: rowCount * columnCount, b: int(size)));
244 auto roleData = createModelRoleData(roles);
245 for (int row = 0; row < rowCount && size > 0; ++row)
246 for (int column = 0; column < columnCount && size > 0; ++column) {
247 const auto index = m_model->index(row, column, parent);
248 const QtPrivate::IndexList currentList = QtPrivate::toModelIndexList(index, model: m_model);
249 const QVariantList data = collectData(index, model: m_model, roleDataSpan: roleData);
250 const bool hasChildren = m_model->hasChildren(parent: index);
251 const Qt::ItemFlags flags = m_model->flags(index);
252 int rc = m_model->rowCount(parent: index);
253 int cc = m_model->columnCount(parent: index);
254 QtPrivate::IndexValuePair rowData(currentList, data, hasChildren, flags, QSize{cc, rc});
255 --size;
256 if (hasChildren)
257 rowData.children = fetchTree(parent: index, size, roles);
258 entries.push_back(t: rowData);
259 }
260 return entries;
261}
262

source code of qtremoteobjects/src/remoteobjects/qremoteobjectabstractitemmodeladapter.cpp