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 
47 QT_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
_q_sourceModelDestroyed()87 void 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 
QAbstractProxyModel(QObject * parent)97 QAbstractProxyModel::QAbstractProxyModel(QObject *parent)
98     :QAbstractItemModel(*new QAbstractProxyModelPrivate, parent)
99 {
100     setSourceModel(QAbstractItemModelPrivate::staticEmptyModel());
101 }
102 
103 /*!
104     \internal
105 */
106 
QAbstractProxyModel(QAbstractProxyModelPrivate & dd,QObject * parent)107 QAbstractProxyModel::QAbstractProxyModel(QAbstractProxyModelPrivate &dd, QObject *parent)
108     : QAbstractItemModel(dd, parent)
109 {
110     setSourceModel(QAbstractItemModelPrivate::staticEmptyModel());
111 }
112 
113 /*!
114     Destroys the proxy model.
115 */
~QAbstractProxyModel()116 QAbstractProxyModel::~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 */
setSourceModel(QAbstractItemModel * sourceModel)128 void QAbstractProxyModel::setSourceModel(QAbstractItemModel *sourceModel)
129 {
130     Q_D(QAbstractProxyModel);
131     if (sourceModel != d->model) {
132         if (d->model)
133             disconnect(d->model, SIGNAL(destroyed()), this, SLOT(_q_sourceModelDestroyed()));
134 
135         if (sourceModel) {
136             d->model = sourceModel;
137             connect(d->model, SIGNAL(destroyed()), 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 */
resetInternalData()149 void 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 */
sourceModel() const158 QAbstractItemModel *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  */
submit()169 bool QAbstractProxyModel::submit()
170 {
171     Q_D(QAbstractProxyModel);
172     return d->model->submit();
173 }
174 
175 /*!
176     \reimp
177  */
revert()178 void 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  */
mapSelectionToSource(const QItemSelection & proxySelection) const208 QItemSelection 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(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 */
mapSelectionFromSource(const QItemSelection & sourceSelection) const226 QItemSelection 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(sourceIndexes.at(i));
232         if (!srcIdx.isValid())
233             continue;
234         proxySelection << QItemSelectionRange(srcIdx);
235     }
236     return proxySelection;
237 }
238 
239 /*!
240     \reimp
241  */
data(const QModelIndex & proxyIndex,int role) const242 QVariant QAbstractProxyModel::data(const QModelIndex &proxyIndex, int role) const
243 {
244     Q_D(const QAbstractProxyModel);
245     return d->model->data(mapToSource(proxyIndex), role);
246 }
247 
248 /*!
249     \reimp
250  */
headerData(int section,Qt::Orientation orientation,int role) const251 QVariant 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(0, section);
257         sourceSection = mapToSource(proxyIndex).column();
258     } else {
259         const QModelIndex proxyIndex = index(section, 0);
260         sourceSection = mapToSource(proxyIndex).row();
261     }
262     return d->model->headerData(sourceSection, orientation, role);
263 }
264 
265 /*!
266     \reimp
267  */
itemData(const QModelIndex & proxyIndex) const268 QMap<int, QVariant> QAbstractProxyModel::itemData(const QModelIndex &proxyIndex) const
269 {
270     return QAbstractItemModel::itemData(proxyIndex);
271 }
272 
273 /*!
274     \reimp
275  */
flags(const QModelIndex & index) const276 Qt::ItemFlags QAbstractProxyModel::flags(const QModelIndex &index) const
277 {
278     Q_D(const QAbstractProxyModel);
279     return d->model->flags(mapToSource(index));
280 }
281 
282 /*!
283     \reimp
284  */
setData(const QModelIndex & index,const QVariant & value,int role)285 bool QAbstractProxyModel::setData(const QModelIndex &index, const QVariant &value, int role)
286 {
287     Q_D(QAbstractProxyModel);
288     return d->model->setData(mapToSource(index), value, role);
289 }
290 
291 /*!
292     \reimp
293  */
setItemData(const QModelIndex & index,const QMap<int,QVariant> & roles)294 bool QAbstractProxyModel::setItemData(const QModelIndex &index, const QMap< int, QVariant >& roles)
295 {
296     return QAbstractItemModel::setItemData(index, roles);
297 }
298 
299 /*!
300     \reimp
301  */
setHeaderData(int section,Qt::Orientation orientation,const QVariant & value,int role)302 bool 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(0, section);
308         sourceSection = mapToSource(proxyIndex).column();
309     } else {
310         const QModelIndex proxyIndex = index(section, 0);
311         sourceSection = mapToSource(proxyIndex).row();
312     }
313     return d->model->setHeaderData(sourceSection, orientation, value, role);
314 }
315 
316 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
317 /*!
318     \reimp
319     \since 6.0
320  */
clearItemData(const QModelIndex & index)321 bool 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  */
buddy(const QModelIndex & index) const331 QModelIndex QAbstractProxyModel::buddy(const QModelIndex &index) const
332 {
333     Q_D(const QAbstractProxyModel);
334     return mapFromSource(d->model->buddy(mapToSource(index)));
335 }
336 
337 /*!
338     \reimp
339  */
canFetchMore(const QModelIndex & parent) const340 bool QAbstractProxyModel::canFetchMore(const QModelIndex &parent) const
341 {
342     Q_D(const QAbstractProxyModel);
343     return d->model->canFetchMore(mapToSource(parent));
344 }
345 
346 /*!
347     \reimp
348  */
fetchMore(const QModelIndex & parent)349 void QAbstractProxyModel::fetchMore(const QModelIndex &parent)
350 {
351     Q_D(QAbstractProxyModel);
352     d->model->fetchMore(mapToSource(parent));
353 }
354 
355 /*!
356     \reimp
357  */
sort(int column,Qt::SortOrder order)358 void QAbstractProxyModel::sort(int column, Qt::SortOrder order)
359 {
360     Q_D(QAbstractProxyModel);
361     d->model->sort(column, order);
362 }
363 
364 /*!
365     \reimp
366  */
span(const QModelIndex & index) const367 QSize QAbstractProxyModel::span(const QModelIndex &index) const
368 {
369     Q_D(const QAbstractProxyModel);
370     return d->model->span(mapToSource(index));
371 }
372 
373 /*!
374     \reimp
375  */
hasChildren(const QModelIndex & parent) const376 bool QAbstractProxyModel::hasChildren(const QModelIndex &parent) const
377 {
378     Q_D(const QAbstractProxyModel);
379     return d->model->hasChildren(mapToSource(parent));
380 }
381 
382 /*!
383     \reimp
384  */
sibling(int row,int column,const QModelIndex & idx) const385 QModelIndex QAbstractProxyModel::sibling(int row, int column, const QModelIndex &idx) const
386 {
387     return index(row, column, idx.parent());
388 }
389 
390 /*!
391     \reimp
392  */
mimeData(const QModelIndexList & indexes) const393 QMimeData* QAbstractProxyModel::mimeData(const QModelIndexList &indexes) const
394 {
395     Q_D(const QAbstractProxyModel);
396     QModelIndexList list;
397     list.reserve(indexes.count());
398     for (const QModelIndex &index : indexes)
399         list << mapToSource(index);
400     return d->model->mimeData(list);
401 }
402 
mapDropCoordinatesToSource(int row,int column,const QModelIndex & parent,int * sourceRow,int * sourceColumn,QModelIndex * sourceParent) const403 void 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(parent);
411     } else if (row == q->rowCount(parent)) {
412         *sourceParent = q->mapToSource(parent);
413         *sourceRow = model->rowCount(*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  */
canDropMimeData(const QMimeData * data,Qt::DropAction action,int row,int column,const QModelIndex & parent) const427 bool 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, &sourceDestinationRow, &sourceDestinationColumn, &sourceParent);
435     return d->model->canDropMimeData(data, action, sourceDestinationRow, sourceDestinationColumn, sourceParent);
436 }
437 
438 /*!
439     \reimp
440     \since 5.4
441  */
dropMimeData(const QMimeData * data,Qt::DropAction action,int row,int column,const QModelIndex & parent)442 bool 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, &sourceDestinationRow, &sourceDestinationColumn, &sourceParent);
450     return d->model->dropMimeData(data, action, sourceDestinationRow, sourceDestinationColumn, sourceParent);
451 }
452 
453 /*!
454     \reimp
455  */
mimeTypes() const456 QStringList QAbstractProxyModel::mimeTypes() const
457 {
458     Q_D(const QAbstractProxyModel);
459     return d->model->mimeTypes();
460 }
461 
462 /*!
463     \reimp
464  */
supportedDragActions() const465 Qt::DropActions QAbstractProxyModel::supportedDragActions() const
466 {
467     Q_D(const QAbstractProxyModel);
468     return d->model->supportedDragActions();
469 }
470 
471 /*!
472     \reimp
473  */
supportedDropActions() const474 Qt::DropActions QAbstractProxyModel::supportedDropActions() const
475 {
476     Q_D(const QAbstractProxyModel);
477     return d->model->supportedDropActions();
478 }
479 
480 QT_END_NAMESPACE
481 
482 #include "moc_qabstractproxymodel.cpp"
483