Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qtransposeproxymodel.cpp
Go to the documentation of this file.
1// Copyright (C) 2018 Luca Beldi <v.ronin@yahoo.it>
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
6#include <private/qtransposeproxymodel_p.h>
7#include <QtCore/qlist.h>
8#include <QtCore/qmetaobject.h>
9#include <QtCore/qsize.h>
10#include <QtCore/qmap.h>
11
13
14QModelIndex QTransposeProxyModelPrivate::uncheckedMapToSource(const QModelIndex &proxyIndex) const
15{
16 if (!model || !proxyIndex.isValid())
17 return QModelIndex();
18 Q_Q(const QTransposeProxyModel);
19 return q->createSourceIndex(proxyIndex.column(), proxyIndex.row(), proxyIndex.internalPointer());
20}
21
22QModelIndex QTransposeProxyModelPrivate::uncheckedMapFromSource(const QModelIndex &sourceIndex) const
23{
24 if (!model || !sourceIndex.isValid())
25 return QModelIndex();
26 Q_Q(const QTransposeProxyModel);
27 return q->createIndex(sourceIndex.column(), sourceIndex.row(), sourceIndex.internalPointer());
28}
29
30void QTransposeProxyModelPrivate::onLayoutChanged(const QList<QPersistentModelIndex> &parents, QAbstractItemModel::LayoutChangeHint hint)
31{
32 Q_Q(QTransposeProxyModel);
33 Q_ASSERT(layoutChangeProxyIndexes.size() == layoutChangePersistentIndexes.size());
34 QModelIndexList toList;
35 toList.reserve(layoutChangePersistentIndexes.size());
36 for (const QPersistentModelIndex &persistIdx : std::as_const(layoutChangePersistentIndexes))
37 toList << q->mapFromSource(persistIdx);
38 q->changePersistentIndexList(layoutChangeProxyIndexes, toList);
39 layoutChangeProxyIndexes.clear();
40 layoutChangePersistentIndexes.clear();
41 QList<QPersistentModelIndex> proxyParents;
42 proxyParents.reserve(parents.size());
43 for (const QPersistentModelIndex &srcParent : parents)
44 proxyParents << q->mapFromSource(srcParent);
45 QAbstractItemModel::LayoutChangeHint proxyHint = QAbstractItemModel::NoLayoutChangeHint;
46 if (hint == QAbstractItemModel::VerticalSortHint)
47 proxyHint = QAbstractItemModel::HorizontalSortHint;
48 else if (hint == QAbstractItemModel::HorizontalSortHint)
49 proxyHint = QAbstractItemModel::VerticalSortHint;
50 emit q->layoutChanged(proxyParents, proxyHint);
51}
52
53void QTransposeProxyModelPrivate::onLayoutAboutToBeChanged(const QList<QPersistentModelIndex> &sourceParents, QAbstractItemModel::LayoutChangeHint hint)
54{
55 Q_Q(QTransposeProxyModel);
56 QList<QPersistentModelIndex> proxyParents;
57 proxyParents.reserve(sourceParents.size());
58 for (const QPersistentModelIndex &parent : sourceParents) {
59 if (!parent.isValid()) {
60 proxyParents << QPersistentModelIndex();
61 continue;
62 }
63 const QModelIndex mappedParent = q->mapFromSource(parent);
64 Q_ASSERT(mappedParent.isValid());
65 proxyParents << mappedParent;
66 }
67 QAbstractItemModel::LayoutChangeHint proxyHint = QAbstractItemModel::NoLayoutChangeHint;
68 if (hint == QAbstractItemModel::VerticalSortHint)
69 proxyHint = QAbstractItemModel::HorizontalSortHint;
70 else if (hint == QAbstractItemModel::HorizontalSortHint)
71 proxyHint = QAbstractItemModel::VerticalSortHint;
72 emit q->layoutAboutToBeChanged(proxyParents, proxyHint);
73 const QModelIndexList proxyPersistentIndexes = q->persistentIndexList();
74 layoutChangeProxyIndexes.clear();
75 layoutChangePersistentIndexes.clear();
76 layoutChangeProxyIndexes.reserve(proxyPersistentIndexes.size());
77 layoutChangePersistentIndexes.reserve(proxyPersistentIndexes.size());
78 for (const QModelIndex &proxyPersistentIndex : proxyPersistentIndexes) {
79 layoutChangeProxyIndexes << proxyPersistentIndex;
80 Q_ASSERT(proxyPersistentIndex.isValid());
81 const QPersistentModelIndex srcPersistentIndex = q->mapToSource(proxyPersistentIndex);
82 Q_ASSERT(srcPersistentIndex.isValid());
83 layoutChangePersistentIndexes << srcPersistentIndex;
84 }
85}
86
87void QTransposeProxyModelPrivate::onDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight,
88 const QList<int> &roles)
89{
90 Q_Q(QTransposeProxyModel);
91 emit q->dataChanged(q->mapFromSource(topLeft), q->mapFromSource(bottomRight), roles);
92}
93
94void QTransposeProxyModelPrivate::onHeaderDataChanged(Qt::Orientation orientation, int first, int last)
95{
96 Q_Q(QTransposeProxyModel);
97 emit q->headerDataChanged(orientation == Qt::Horizontal ? Qt::Vertical : Qt::Horizontal, first, last);
98}
99
100void QTransposeProxyModelPrivate::onColumnsAboutToBeInserted(const QModelIndex &parent, int first, int last)
101{
102 Q_Q(QTransposeProxyModel);
103 q->beginInsertRows(q->mapFromSource(parent), first, last);
104}
105
106void QTransposeProxyModelPrivate::onColumnsAboutToBeRemoved(const QModelIndex &parent, int first, int last)
107{
108 Q_Q(QTransposeProxyModel);
109 q->beginRemoveRows(q->mapFromSource(parent), first, last);
110}
111
112void QTransposeProxyModelPrivate::onColumnsAboutToBeMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationColumn)
113{
114 Q_Q(QTransposeProxyModel);
115 q->beginMoveRows(q->mapFromSource(sourceParent), sourceStart, sourceEnd, q->mapFromSource(destinationParent), destinationColumn);
116}
117
118void QTransposeProxyModelPrivate::onRowsAboutToBeInserted(const QModelIndex &parent, int first, int last)
119{
120 Q_Q(QTransposeProxyModel);
121 q->beginInsertColumns(q->mapFromSource(parent), first, last);
122}
123
124void QTransposeProxyModelPrivate::onRowsAboutToBeRemoved(const QModelIndex &parent, int first, int last)
125{
126 Q_Q(QTransposeProxyModel);
127 q->beginRemoveColumns(q->mapFromSource(parent), first, last);
128}
129
130void QTransposeProxyModelPrivate::onRowsAboutToBeMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationRow)
131{
132 Q_Q(QTransposeProxyModel);
133 q->beginMoveColumns(q->mapFromSource(sourceParent), sourceStart, sourceEnd, q->mapFromSource(destinationParent), destinationRow);
134}
135
136/*!
137 \since 5.13
138 \class QTransposeProxyModel
139 \inmodule QtCore
140 \brief This proxy transposes the source model.
141
142 This model will make the rows of the source model become columns of the proxy model and vice-versa.
143
144 If the model is a tree, the parents will be transposed as well. For example, if an index in the source model had parent `index(2,0)`, it will have parent `index(0,2)` in the proxy.
145*/
146
147/*!
148 Constructs a new proxy model with the given \a parent.
149*/
150QTransposeProxyModel::QTransposeProxyModel(QObject* parent)
151 : QAbstractProxyModel(*new QTransposeProxyModelPrivate, parent)
152{}
153
154/*!
155 Destructs the proxy model.
156*/
157QTransposeProxyModel::~QTransposeProxyModel() = default;
158
159/*!
160 \internal
161*/
162QTransposeProxyModel::QTransposeProxyModel(QTransposeProxyModelPrivate &dd, QObject *parent)
163 : QAbstractProxyModel(dd, parent)
164{}
165
166/*!
167 \reimp
168*/
169void QTransposeProxyModel::setSourceModel(QAbstractItemModel* newSourceModel)
170{
171 Q_D(QTransposeProxyModel);
172 if (newSourceModel == d->model)
173 return;
174 beginResetModel();
175 if (d->model) {
176 for (const QMetaObject::Connection& discIter : std::as_const(d->sourceConnections))
177 disconnect(discIter);
178 }
179 d->sourceConnections.clear();
180 QAbstractProxyModel::setSourceModel(newSourceModel);
181 if (d->model) {
182 using namespace std::placeholders;
183 d->sourceConnections = QList<QMetaObject::Connection>{
184 connect(d->model, &QAbstractItemModel::modelAboutToBeReset, this, &QTransposeProxyModel::beginResetModel),
185 connect(d->model, &QAbstractItemModel::modelReset, this, &QTransposeProxyModel::endResetModel),
186 connect(d->model, &QAbstractItemModel::dataChanged, this, std::bind(&QTransposeProxyModelPrivate::onDataChanged, d, _1, _2, _3)),
187 connect(d->model, &QAbstractItemModel::headerDataChanged, this, std::bind(&QTransposeProxyModelPrivate::onHeaderDataChanged, d, _1, _2, _3)),
188 connect(d->model, &QAbstractItemModel::columnsAboutToBeInserted, this, std::bind(&QTransposeProxyModelPrivate::onColumnsAboutToBeInserted, d, _1, _2, _3)),
189 connect(d->model, &QAbstractItemModel::columnsAboutToBeMoved, this, std::bind(&QTransposeProxyModelPrivate::onColumnsAboutToBeMoved, d, _1, _2, _3, _4, _5)),
190 connect(d->model, &QAbstractItemModel::columnsAboutToBeRemoved, this, std::bind(&QTransposeProxyModelPrivate::onColumnsAboutToBeRemoved, d, _1, _2, _3)),
191 connect(d->model, &QAbstractItemModel::columnsInserted, this, &QTransposeProxyModel::endInsertRows),
192 connect(d->model, &QAbstractItemModel::columnsRemoved, this, &QTransposeProxyModel::endRemoveRows),
193 connect(d->model, &QAbstractItemModel::columnsMoved, this, &QTransposeProxyModel::endMoveRows),
194 connect(d->model, &QAbstractItemModel::rowsAboutToBeInserted, this, std::bind(&QTransposeProxyModelPrivate::onRowsAboutToBeInserted, d, _1, _2, _3)),
195 connect(d->model, &QAbstractItemModel::rowsAboutToBeMoved, this, std::bind(&QTransposeProxyModelPrivate::onRowsAboutToBeMoved, d, _1, _2, _3, _4, _5)),
196 connect(d->model, &QAbstractItemModel::rowsAboutToBeRemoved, this, std::bind(&QTransposeProxyModelPrivate::onRowsAboutToBeRemoved, d, _1, _2, _3)),
197 connect(d->model, &QAbstractItemModel::rowsInserted, this, &QTransposeProxyModel::endInsertColumns),
198 connect(d->model, &QAbstractItemModel::rowsRemoved, this, &QTransposeProxyModel::endRemoveColumns),
199 connect(d->model, &QAbstractItemModel::rowsMoved, this, &QTransposeProxyModel::endMoveColumns),
200 connect(d->model, &QAbstractItemModel::layoutAboutToBeChanged, this, std::bind(&QTransposeProxyModelPrivate::onLayoutAboutToBeChanged, d, _1, _2)),
201 connect(d->model, &QAbstractItemModel::layoutChanged, this, std::bind(&QTransposeProxyModelPrivate::onLayoutChanged, d, _1, _2))
202 };
203 }
204 endResetModel();
205}
206
207/*!
208 \reimp
209*/
210int QTransposeProxyModel::rowCount(const QModelIndex &parent) const
211{
212 Q_D(const QTransposeProxyModel);
213 if (!d->model)
214 return 0;
215 Q_ASSERT(checkIndex(parent));
216 return d->model->columnCount(mapToSource(parent));
217}
218
219/*!
220 \reimp
221*/
222int QTransposeProxyModel::columnCount(const QModelIndex &parent) const
223{
224 Q_D(const QTransposeProxyModel);
225 if (!d->model)
226 return 0;
227 Q_ASSERT(checkIndex(parent));
228 return d->model->rowCount(mapToSource(parent));
229}
230
231/*!
232 \reimp
233*/
234QVariant QTransposeProxyModel::headerData(int section, Qt::Orientation orientation, int role) const
235{
236 Q_D(const QTransposeProxyModel);
237 if (!d->model)
238 return QVariant();
239 return d->model->headerData(section, orientation == Qt::Horizontal ? Qt::Vertical : Qt::Horizontal, role);
240}
241
242/*!
243 \reimp
244*/
245bool QTransposeProxyModel::setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role)
246{
247 Q_D(QTransposeProxyModel);
248 if (!d->model)
249 return false;
250 return d->model->setHeaderData(section, orientation == Qt::Horizontal ? Qt::Vertical : Qt::Horizontal, value, role);
251}
252
253/*!
254 \reimp
255*/
256bool QTransposeProxyModel::setItemData(const QModelIndex &index, const QMap<int, QVariant> &roles)
257{
258 Q_D(QTransposeProxyModel);
259 Q_ASSERT(checkIndex(index));
260 if (!d->model || !index.isValid())
261 return false;
262 return d->model->setItemData(mapToSource(index), roles);
263}
264
265/*!
266 \reimp
267*/
268QSize QTransposeProxyModel::span(const QModelIndex &index) const
269{
270 Q_D(const QTransposeProxyModel);
271 Q_ASSERT(checkIndex(index));
272 if (!d->model || !index.isValid())
273 return QSize();
274 return d->model->span(mapToSource(index)).transposed();
275}
276
277/*!
278 \reimp
279*/
280QMap<int, QVariant> QTransposeProxyModel::itemData(const QModelIndex &index) const
281{
282 Q_D(const QTransposeProxyModel);
283 if (!d->model)
284 return QMap<int, QVariant>();
285 Q_ASSERT(checkIndex(index));
286 return d->model->itemData(mapToSource(index));
287}
288
289/*!
290 \reimp
291*/
292QModelIndex QTransposeProxyModel::mapFromSource(const QModelIndex &sourceIndex) const
293{
294 Q_D(const QTransposeProxyModel);
295 if (!d->model || !sourceIndex.isValid())
296 return QModelIndex();
297 Q_ASSERT(d->model->checkIndex(sourceIndex));
298 return d->uncheckedMapFromSource(sourceIndex);
299}
300
301/*!
302 \reimp
303*/
304QModelIndex QTransposeProxyModel::mapToSource(const QModelIndex &proxyIndex) const
305{
306 Q_D(const QTransposeProxyModel);
307 Q_ASSERT(checkIndex(proxyIndex));
308 if (!d->model || !proxyIndex.isValid())
309 return QModelIndex();
310 return d->uncheckedMapToSource(proxyIndex);
311}
312
313/*!
314 \reimp
315*/
316QModelIndex QTransposeProxyModel::parent(const QModelIndex &index) const
317{
318 Q_D(const QTransposeProxyModel);
319 Q_ASSERT(checkIndex(index, CheckIndexOption::DoNotUseParent));
320 if (!d->model || !index.isValid())
321 return QModelIndex();
322 return d->uncheckedMapFromSource(d->uncheckedMapToSource(index).parent());
323}
324
325/*!
326 \reimp
327*/
328QModelIndex QTransposeProxyModel::index(int row, int column, const QModelIndex &parent) const
329{
330 Q_D(const QTransposeProxyModel);
331 Q_ASSERT(checkIndex(parent));
332 if (!d->model)
333 return QModelIndex();
334 return mapFromSource(d->model->index(column, row, mapToSource(parent)));
335}
336
337/*!
338 \reimp
339*/
340bool QTransposeProxyModel::insertRows(int row, int count, const QModelIndex &parent)
341{
342 Q_D(QTransposeProxyModel);
343 Q_ASSERT(checkIndex(parent));
344 if (!d->model)
345 return false;
346 return d->model->insertColumns(row, count, mapToSource(parent));
347}
348
349/*!
350 \reimp
351*/
352bool QTransposeProxyModel::removeRows(int row, int count, const QModelIndex &parent)
353{
354 Q_D(QTransposeProxyModel);
355 Q_ASSERT(checkIndex(parent));
356 if (!d->model)
357 return false;
358 return d->model->removeColumns(row, count, mapToSource(parent));
359}
360
361/*!
362 \reimp
363*/
364bool QTransposeProxyModel::moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationChild)
365{
366 Q_D(QTransposeProxyModel);
367 Q_ASSERT(checkIndex(sourceParent));
368 Q_ASSERT(checkIndex(destinationParent));
369 if (!d->model)
370 return false;
371 return d->model->moveColumns(mapToSource(sourceParent), sourceRow, count, mapToSource(destinationParent), destinationChild);
372}
373
374/*!
375 \reimp
376*/
377bool QTransposeProxyModel::insertColumns(int column, int count, const QModelIndex &parent)
378{
379 Q_D(QTransposeProxyModel);
380 Q_ASSERT(checkIndex(parent));
381 if (!d->model)
382 return false;
383 return d->model->insertRows(column, count, mapToSource(parent));
384}
385
386/*!
387 \reimp
388*/
389bool QTransposeProxyModel::removeColumns(int column, int count, const QModelIndex &parent)
390{
391 Q_D(QTransposeProxyModel);
392 Q_ASSERT(checkIndex(parent));
393 if (!d->model)
394 return false;
395 return d->model->removeRows(column, count, mapToSource(parent));
396}
397
398/*!
399 \reimp
400*/
401bool QTransposeProxyModel::moveColumns(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationChild)
402{
403 Q_D(QTransposeProxyModel);
404 Q_ASSERT(checkIndex(sourceParent));
405 Q_ASSERT(checkIndex(destinationParent));
406 if (!d->model)
407 return false;
408 return d->model->moveRows(mapToSource(sourceParent), sourceRow, count, mapToSource(destinationParent), destinationChild);
409}
410
411/*!
412 \reimp
413 This method will perform no action. Use a QSortFilterProxyModel on top of this one if you require sorting.
414*/
415void QTransposeProxyModel::sort(int column, Qt::SortOrder order)
416{
417 Q_UNUSED(column);
418 Q_UNUSED(order);
419 return;
420}
421
422QT_END_NAMESPACE
423
424#include "moc_qtransposeproxymodel.cpp"