1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtCore module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qabstractproxymodel.h"
41#include "qitemselectionmodel.h"
42#include <private/qabstractproxymodel_p.h>
43#include <QtCore/QSize>
44#include <QtCore/QStringList>
45
46
47QT_BEGIN_NAMESPACE
48
49/*!
50 \since 4.1
51 \class QAbstractProxyModel
52 \brief The QAbstractProxyModel class provides a base class for proxy item
53 models that can do sorting, filtering or other data processing tasks.
54 \ingroup model-view
55 \inmodule QtCore
56
57 This class defines the standard interface that proxy models must use to be
58 able to interoperate correctly with other model/view components. It is not
59 supposed to be instantiated directly.
60
61 All standard proxy models are derived from the QAbstractProxyModel class.
62 If you need to create a new proxy model class, it is usually better to
63 subclass an existing class that provides the closest behavior to the one
64 you want to provide.
65
66 Proxy models that filter or sort items of data from a source model should
67 be created by using or subclassing QSortFilterProxyModel.
68
69 To subclass QAbstractProxyModel, you need to implement mapFromSource() and
70 mapToSource(). The mapSelectionFromSource() and mapSelectionToSource()
71 functions only need to be reimplemented if you need a behavior different
72 from the default behavior.
73
74 \note If the source model is deleted or no source model is specified, the
75 proxy model operates on a empty placeholder model.
76
77 \sa QSortFilterProxyModel, QAbstractItemModel, {Model/View Programming}
78*/
79
80/*!
81 \property QAbstractProxyModel::sourceModel
82
83 \brief the source model of this proxy model.
84*/
85
86//detects the deletion of the source model
87void QAbstractProxyModelPrivate::_q_sourceModelDestroyed()
88{
89 invalidatePersistentIndexes();
90 model = QAbstractItemModelPrivate::staticEmptyModel();
91}
92
93/*!
94 Constructs a proxy model with the given \a parent.
95*/
96
97QAbstractProxyModel::QAbstractProxyModel(QObject *parent)
98 :QAbstractItemModel(*new QAbstractProxyModelPrivate, parent)
99{
100 setSourceModel(QAbstractItemModelPrivate::staticEmptyModel());
101}
102
103/*!
104 \internal
105*/
106
107QAbstractProxyModel::QAbstractProxyModel(QAbstractProxyModelPrivate &dd, QObject *parent)
108 : QAbstractItemModel(dd, parent)
109{
110 setSourceModel(QAbstractItemModelPrivate::staticEmptyModel());
111}
112
113/*!
114 Destroys the proxy model.
115*/
116QAbstractProxyModel::~QAbstractProxyModel()
117{
118
119}
120
121/*!
122 Sets the given \a sourceModel to be processed by the proxy model.
123
124 Subclasses should call beginResetModel() at the beginning of the method,
125 disconnect from the old model, call this method, connect to the new model,
126 and call endResetModel().
127*/
128void QAbstractProxyModel::setSourceModel(QAbstractItemModel *sourceModel)
129{
130 Q_D(QAbstractProxyModel);
131 if (sourceModel != d->model) {
132 if (d->model)
133 disconnect(sender: d->model, SIGNAL(destroyed()), receiver: this, SLOT(_q_sourceModelDestroyed()));
134
135 if (sourceModel) {
136 d->model = sourceModel;
137 connect(sender: d->model, SIGNAL(destroyed()), receiver: this, SLOT(_q_sourceModelDestroyed()));
138 } else {
139 d->model = QAbstractItemModelPrivate::staticEmptyModel();
140 }
141 d->roleNames = d->model->roleNames();
142 emit sourceModelChanged(QPrivateSignal());
143 }
144}
145
146/*!
147 Clears the roleNames of this proxy model.
148*/
149void QAbstractProxyModel::resetInternalData()
150{
151 Q_D(QAbstractProxyModel);
152 d->roleNames = d->model->roleNames();
153}
154
155/*!
156 Returns the model that contains the data that is available through the proxy model.
157*/
158QAbstractItemModel *QAbstractProxyModel::sourceModel() const
159{
160 Q_D(const QAbstractProxyModel);
161 if (d->model == QAbstractItemModelPrivate::staticEmptyModel())
162 return nullptr;
163 return d->model;
164}
165
166/*!
167 \reimp
168 */
169bool QAbstractProxyModel::submit()
170{
171 Q_D(QAbstractProxyModel);
172 return d->model->submit();
173}
174
175/*!
176 \reimp
177 */
178void QAbstractProxyModel::revert()
179{
180 Q_D(QAbstractProxyModel);
181 d->model->revert();
182}
183
184
185/*!
186 \fn QModelIndex QAbstractProxyModel::mapToSource(const QModelIndex &proxyIndex) const
187
188 Reimplement this function to return the model index in the source model that
189 corresponds to the \a proxyIndex in the proxy model.
190
191 \sa mapFromSource()
192*/
193
194/*!
195 \fn QModelIndex QAbstractProxyModel::mapFromSource(const QModelIndex &sourceIndex) const
196
197 Reimplement this function to return the model index in the proxy model that
198 corresponds to the \a sourceIndex from the source model.
199
200 \sa mapToSource()
201*/
202
203/*!
204 Returns a source selection mapped from the specified \a proxySelection.
205
206 Reimplement this method to map proxy selections to source selections.
207 */
208QItemSelection QAbstractProxyModel::mapSelectionToSource(const QItemSelection &proxySelection) const
209{
210 QModelIndexList proxyIndexes = proxySelection.indexes();
211 QItemSelection sourceSelection;
212 for (int i = 0; i < proxyIndexes.size(); ++i) {
213 const QModelIndex proxyIdx = mapToSource(proxyIndex: proxyIndexes.at(i));
214 if (!proxyIdx.isValid())
215 continue;
216 sourceSelection << QItemSelectionRange(proxyIdx);
217 }
218 return sourceSelection;
219}
220
221/*!
222 Returns a proxy selection mapped from the specified \a sourceSelection.
223
224 Reimplement this method to map source selections to proxy selections.
225*/
226QItemSelection QAbstractProxyModel::mapSelectionFromSource(const QItemSelection &sourceSelection) const
227{
228 QModelIndexList sourceIndexes = sourceSelection.indexes();
229 QItemSelection proxySelection;
230 for (int i = 0; i < sourceIndexes.size(); ++i) {
231 const QModelIndex srcIdx = mapFromSource(sourceIndex: sourceIndexes.at(i));
232 if (!srcIdx.isValid())
233 continue;
234 proxySelection << QItemSelectionRange(srcIdx);
235 }
236 return proxySelection;
237}
238
239/*!
240 \reimp
241 */
242QVariant QAbstractProxyModel::data(const QModelIndex &proxyIndex, int role) const
243{
244 Q_D(const QAbstractProxyModel);
245 return d->model->data(index: mapToSource(proxyIndex), role);
246}
247
248/*!
249 \reimp
250 */
251QVariant QAbstractProxyModel::headerData(int section, Qt::Orientation orientation, int role) const
252{
253 Q_D(const QAbstractProxyModel);
254 int sourceSection;
255 if (orientation == Qt::Horizontal) {
256 const QModelIndex proxyIndex = index(row: 0, column: section);
257 sourceSection = mapToSource(proxyIndex).column();
258 } else {
259 const QModelIndex proxyIndex = index(row: section, column: 0);
260 sourceSection = mapToSource(proxyIndex).row();
261 }
262 return d->model->headerData(section: sourceSection, orientation, role);
263}
264
265/*!
266 \reimp
267 */
268QMap<int, QVariant> QAbstractProxyModel::itemData(const QModelIndex &proxyIndex) const
269{
270 return QAbstractItemModel::itemData(index: proxyIndex);
271}
272
273/*!
274 \reimp
275 */
276Qt::ItemFlags QAbstractProxyModel::flags(const QModelIndex &index) const
277{
278 Q_D(const QAbstractProxyModel);
279 return d->model->flags(index: mapToSource(proxyIndex: index));
280}
281
282/*!
283 \reimp
284 */
285bool QAbstractProxyModel::setData(const QModelIndex &index, const QVariant &value, int role)
286{
287 Q_D(QAbstractProxyModel);
288 return d->model->setData(index: mapToSource(proxyIndex: index), value, role);
289}
290
291/*!
292 \reimp
293 */
294bool QAbstractProxyModel::setItemData(const QModelIndex &index, const QMap< int, QVariant >& roles)
295{
296 return QAbstractItemModel::setItemData(index, roles);
297}
298
299/*!
300 \reimp
301 */
302bool QAbstractProxyModel::setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role)
303{
304 Q_D(QAbstractProxyModel);
305 int sourceSection;
306 if (orientation == Qt::Horizontal) {
307 const QModelIndex proxyIndex = index(row: 0, column: section);
308 sourceSection = mapToSource(proxyIndex).column();
309 } else {
310 const QModelIndex proxyIndex = index(row: section, column: 0);
311 sourceSection = mapToSource(proxyIndex).row();
312 }
313 return d->model->setHeaderData(section: sourceSection, orientation, value, role);
314}
315
316#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
317/*!
318 \reimp
319 \since 6.0
320 */
321bool QAbstractProxyModel::clearItemData(const QModelIndex &index)
322{
323 Q_D(QAbstractProxyModel);
324 return d->model->clearItemData(mapToSource(index));
325}
326#endif
327
328/*!
329 \reimp
330 */
331QModelIndex QAbstractProxyModel::buddy(const QModelIndex &index) const
332{
333 Q_D(const QAbstractProxyModel);
334 return mapFromSource(sourceIndex: d->model->buddy(index: mapToSource(proxyIndex: index)));
335}
336
337/*!
338 \reimp
339 */
340bool QAbstractProxyModel::canFetchMore(const QModelIndex &parent) const
341{
342 Q_D(const QAbstractProxyModel);
343 return d->model->canFetchMore(parent: mapToSource(proxyIndex: parent));
344}
345
346/*!
347 \reimp
348 */
349void QAbstractProxyModel::fetchMore(const QModelIndex &parent)
350{
351 Q_D(QAbstractProxyModel);
352 d->model->fetchMore(parent: mapToSource(proxyIndex: parent));
353}
354
355/*!
356 \reimp
357 */
358void QAbstractProxyModel::sort(int column, Qt::SortOrder order)
359{
360 Q_D(QAbstractProxyModel);
361 d->model->sort(column, order);
362}
363
364/*!
365 \reimp
366 */
367QSize QAbstractProxyModel::span(const QModelIndex &index) const
368{
369 Q_D(const QAbstractProxyModel);
370 return d->model->span(index: mapToSource(proxyIndex: index));
371}
372
373/*!
374 \reimp
375 */
376bool QAbstractProxyModel::hasChildren(const QModelIndex &parent) const
377{
378 Q_D(const QAbstractProxyModel);
379 return d->model->hasChildren(parent: mapToSource(proxyIndex: parent));
380}
381
382/*!
383 \reimp
384 */
385QModelIndex QAbstractProxyModel::sibling(int row, int column, const QModelIndex &idx) const
386{
387 return index(row, column, parent: idx.parent());
388}
389
390/*!
391 \reimp
392 */
393QMimeData* QAbstractProxyModel::mimeData(const QModelIndexList &indexes) const
394{
395 Q_D(const QAbstractProxyModel);
396 QModelIndexList list;
397 list.reserve(alloc: indexes.count());
398 for (const QModelIndex &index : indexes)
399 list << mapToSource(proxyIndex: index);
400 return d->model->mimeData(indexes: list);
401}
402
403void QAbstractProxyModelPrivate::mapDropCoordinatesToSource(int row, int column, const QModelIndex &parent,
404 int *sourceRow, int *sourceColumn, QModelIndex *sourceParent) const
405{
406 Q_Q(const QAbstractProxyModel);
407 *sourceRow = -1;
408 *sourceColumn = -1;
409 if (row == -1 && column == -1) {
410 *sourceParent = q->mapToSource(proxyIndex: parent);
411 } else if (row == q->rowCount(parent)) {
412 *sourceParent = q->mapToSource(proxyIndex: parent);
413 *sourceRow = model->rowCount(parent: *sourceParent);
414 } else {
415 QModelIndex proxyIndex = q->index(row, column, parent);
416 QModelIndex sourceIndex = q->mapToSource(proxyIndex);
417 *sourceRow = sourceIndex.row();
418 *sourceColumn = sourceIndex.column();
419 *sourceParent = sourceIndex.parent();
420 }
421}
422
423/*!
424 \reimp
425 \since 5.4
426 */
427bool QAbstractProxyModel::canDropMimeData(const QMimeData *data, Qt::DropAction action,
428 int row, int column, const QModelIndex &parent) const
429{
430 Q_D(const QAbstractProxyModel);
431 int sourceDestinationRow;
432 int sourceDestinationColumn;
433 QModelIndex sourceParent;
434 d->mapDropCoordinatesToSource(row, column, parent, sourceRow: &sourceDestinationRow, sourceColumn: &sourceDestinationColumn, sourceParent: &sourceParent);
435 return d->model->canDropMimeData(data, action, row: sourceDestinationRow, column: sourceDestinationColumn, parent: sourceParent);
436}
437
438/*!
439 \reimp
440 \since 5.4
441 */
442bool QAbstractProxyModel::dropMimeData(const QMimeData *data, Qt::DropAction action,
443 int row, int column, const QModelIndex &parent)
444{
445 Q_D(QAbstractProxyModel);
446 int sourceDestinationRow;
447 int sourceDestinationColumn;
448 QModelIndex sourceParent;
449 d->mapDropCoordinatesToSource(row, column, parent, sourceRow: &sourceDestinationRow, sourceColumn: &sourceDestinationColumn, sourceParent: &sourceParent);
450 return d->model->dropMimeData(data, action, row: sourceDestinationRow, column: sourceDestinationColumn, parent: sourceParent);
451}
452
453/*!
454 \reimp
455 */
456QStringList QAbstractProxyModel::mimeTypes() const
457{
458 Q_D(const QAbstractProxyModel);
459 return d->model->mimeTypes();
460}
461
462/*!
463 \reimp
464 */
465Qt::DropActions QAbstractProxyModel::supportedDragActions() const
466{
467 Q_D(const QAbstractProxyModel);
468 return d->model->supportedDragActions();
469}
470
471/*!
472 \reimp
473 */
474Qt::DropActions QAbstractProxyModel::supportedDropActions() const
475{
476 Q_D(const QAbstractProxyModel);
477 return d->model->supportedDropActions();
478}
479
480QT_END_NAMESPACE
481
482#include "moc_qabstractproxymodel.cpp"
483

source code of qtbase/src/corelib/itemmodels/qabstractproxymodel.cpp