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 |
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 | |
97 | QAbstractProxyModel::QAbstractProxyModel(QObject *parent) |
98 | :QAbstractItemModel(*new QAbstractProxyModelPrivate, parent) |
99 | { |
100 | setSourceModel(QAbstractItemModelPrivate::staticEmptyModel()); |
101 | } |
102 | |
103 | /*! |
104 | \internal |
105 | */ |
106 | |
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 | */ |
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 | */ |
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 | emit sourceModelChanged(QPrivateSignal()); |
142 | } |
143 | } |
144 | |
145 | /*! |
146 | Returns the model that contains the data that is available through the proxy model. |
147 | */ |
148 | QAbstractItemModel *QAbstractProxyModel::sourceModel() const |
149 | { |
150 | Q_D(const QAbstractProxyModel); |
151 | if (d->model == QAbstractItemModelPrivate::staticEmptyModel()) |
152 | return nullptr; |
153 | return d->model; |
154 | } |
155 | |
156 | /*! |
157 | \reimp |
158 | */ |
159 | bool QAbstractProxyModel::submit() |
160 | { |
161 | Q_D(QAbstractProxyModel); |
162 | return d->model->submit(); |
163 | } |
164 | |
165 | /*! |
166 | \reimp |
167 | */ |
168 | void QAbstractProxyModel::revert() |
169 | { |
170 | Q_D(QAbstractProxyModel); |
171 | d->model->revert(); |
172 | } |
173 | |
174 | |
175 | /*! |
176 | \fn QModelIndex QAbstractProxyModel::mapToSource(const QModelIndex &proxyIndex) const |
177 | |
178 | Reimplement this function to return the model index in the source model that |
179 | corresponds to the \a proxyIndex in the proxy model. |
180 | |
181 | \sa mapFromSource() |
182 | */ |
183 | |
184 | /*! |
185 | \fn QModelIndex QAbstractProxyModel::mapFromSource(const QModelIndex &sourceIndex) const |
186 | |
187 | Reimplement this function to return the model index in the proxy model that |
188 | corresponds to the \a sourceIndex from the source model. |
189 | |
190 | \sa mapToSource() |
191 | */ |
192 | |
193 | /*! |
194 | Returns a source selection mapped from the specified \a proxySelection. |
195 | |
196 | Reimplement this method to map proxy selections to source selections. |
197 | */ |
198 | QItemSelection QAbstractProxyModel::mapSelectionToSource(const QItemSelection &proxySelection) const |
199 | { |
200 | QModelIndexList proxyIndexes = proxySelection.indexes(); |
201 | QItemSelection sourceSelection; |
202 | for (int i = 0; i < proxyIndexes.size(); ++i) { |
203 | const QModelIndex proxyIdx = mapToSource(proxyIndexes.at(i)); |
204 | if (!proxyIdx.isValid()) |
205 | continue; |
206 | sourceSelection << QItemSelectionRange(proxyIdx); |
207 | } |
208 | return sourceSelection; |
209 | } |
210 | |
211 | /*! |
212 | Returns a proxy selection mapped from the specified \a sourceSelection. |
213 | |
214 | Reimplement this method to map source selections to proxy selections. |
215 | */ |
216 | QItemSelection QAbstractProxyModel::mapSelectionFromSource(const QItemSelection &sourceSelection) const |
217 | { |
218 | QModelIndexList sourceIndexes = sourceSelection.indexes(); |
219 | QItemSelection proxySelection; |
220 | for (int i = 0; i < sourceIndexes.size(); ++i) { |
221 | const QModelIndex srcIdx = mapFromSource(sourceIndexes.at(i)); |
222 | if (!srcIdx.isValid()) |
223 | continue; |
224 | proxySelection << QItemSelectionRange(srcIdx); |
225 | } |
226 | return proxySelection; |
227 | } |
228 | |
229 | /*! |
230 | \reimp |
231 | */ |
232 | QVariant QAbstractProxyModel::data(const QModelIndex &proxyIndex, int role) const |
233 | { |
234 | Q_D(const QAbstractProxyModel); |
235 | return d->model->data(mapToSource(proxyIndex), role); |
236 | } |
237 | |
238 | /*! |
239 | \reimp |
240 | */ |
241 | QVariant QAbstractProxyModel::(int section, Qt::Orientation orientation, int role) const |
242 | { |
243 | Q_D(const QAbstractProxyModel); |
244 | int sourceSection; |
245 | if (orientation == Qt::Horizontal) { |
246 | const QModelIndex proxyIndex = index(0, section); |
247 | sourceSection = mapToSource(proxyIndex).column(); |
248 | } else { |
249 | const QModelIndex proxyIndex = index(section, 0); |
250 | sourceSection = mapToSource(proxyIndex).row(); |
251 | } |
252 | return d->model->headerData(sourceSection, orientation, role); |
253 | } |
254 | |
255 | /*! |
256 | \reimp |
257 | */ |
258 | QMap<int, QVariant> QAbstractProxyModel::itemData(const QModelIndex &proxyIndex) const |
259 | { |
260 | return QAbstractItemModel::itemData(proxyIndex); |
261 | } |
262 | |
263 | /*! |
264 | \reimp |
265 | */ |
266 | Qt::ItemFlags QAbstractProxyModel::flags(const QModelIndex &index) const |
267 | { |
268 | Q_D(const QAbstractProxyModel); |
269 | return d->model->flags(mapToSource(index)); |
270 | } |
271 | |
272 | /*! |
273 | \reimp |
274 | */ |
275 | bool QAbstractProxyModel::setData(const QModelIndex &index, const QVariant &value, int role) |
276 | { |
277 | Q_D(QAbstractProxyModel); |
278 | return d->model->setData(mapToSource(index), value, role); |
279 | } |
280 | |
281 | /*! |
282 | \reimp |
283 | */ |
284 | bool QAbstractProxyModel::setItemData(const QModelIndex &index, const QMap< int, QVariant >& roles) |
285 | { |
286 | return QAbstractItemModel::setItemData(index, roles); |
287 | } |
288 | |
289 | /*! |
290 | \reimp |
291 | */ |
292 | bool QAbstractProxyModel::(int section, Qt::Orientation orientation, const QVariant &value, int role) |
293 | { |
294 | Q_D(QAbstractProxyModel); |
295 | int sourceSection; |
296 | if (orientation == Qt::Horizontal) { |
297 | const QModelIndex proxyIndex = index(0, section); |
298 | sourceSection = mapToSource(proxyIndex).column(); |
299 | } else { |
300 | const QModelIndex proxyIndex = index(section, 0); |
301 | sourceSection = mapToSource(proxyIndex).row(); |
302 | } |
303 | return d->model->setHeaderData(sourceSection, orientation, value, role); |
304 | } |
305 | |
306 | /*! |
307 | \reimp |
308 | \since 6.0 |
309 | */ |
310 | bool QAbstractProxyModel::clearItemData(const QModelIndex &index) |
311 | { |
312 | Q_D(QAbstractProxyModel); |
313 | return d->model->clearItemData(mapToSource(index)); |
314 | } |
315 | |
316 | /*! |
317 | \reimp |
318 | */ |
319 | QModelIndex QAbstractProxyModel::buddy(const QModelIndex &index) const |
320 | { |
321 | Q_D(const QAbstractProxyModel); |
322 | return mapFromSource(d->model->buddy(mapToSource(index))); |
323 | } |
324 | |
325 | /*! |
326 | \reimp |
327 | */ |
328 | bool QAbstractProxyModel::canFetchMore(const QModelIndex &parent) const |
329 | { |
330 | Q_D(const QAbstractProxyModel); |
331 | return d->model->canFetchMore(mapToSource(parent)); |
332 | } |
333 | |
334 | /*! |
335 | \reimp |
336 | */ |
337 | void QAbstractProxyModel::fetchMore(const QModelIndex &parent) |
338 | { |
339 | Q_D(QAbstractProxyModel); |
340 | d->model->fetchMore(mapToSource(parent)); |
341 | } |
342 | |
343 | /*! |
344 | \reimp |
345 | */ |
346 | void QAbstractProxyModel::sort(int column, Qt::SortOrder order) |
347 | { |
348 | Q_D(QAbstractProxyModel); |
349 | d->model->sort(column, order); |
350 | } |
351 | |
352 | /*! |
353 | \reimp |
354 | */ |
355 | QSize QAbstractProxyModel::span(const QModelIndex &index) const |
356 | { |
357 | Q_D(const QAbstractProxyModel); |
358 | return d->model->span(mapToSource(index)); |
359 | } |
360 | |
361 | /*! |
362 | \reimp |
363 | */ |
364 | bool QAbstractProxyModel::hasChildren(const QModelIndex &parent) const |
365 | { |
366 | Q_D(const QAbstractProxyModel); |
367 | return d->model->hasChildren(mapToSource(parent)); |
368 | } |
369 | |
370 | /*! |
371 | \reimp |
372 | */ |
373 | QModelIndex QAbstractProxyModel::sibling(int row, int column, const QModelIndex &idx) const |
374 | { |
375 | return index(row, column, idx.parent()); |
376 | } |
377 | |
378 | /*! |
379 | \reimp |
380 | */ |
381 | QMimeData* QAbstractProxyModel::mimeData(const QModelIndexList &indexes) const |
382 | { |
383 | Q_D(const QAbstractProxyModel); |
384 | QModelIndexList list; |
385 | list.reserve(indexes.count()); |
386 | for (const QModelIndex &index : indexes) |
387 | list << mapToSource(index); |
388 | return d->model->mimeData(list); |
389 | } |
390 | |
391 | void QAbstractProxyModelPrivate::mapDropCoordinatesToSource(int row, int column, const QModelIndex &parent, |
392 | int *sourceRow, int *sourceColumn, QModelIndex *sourceParent) const |
393 | { |
394 | Q_Q(const QAbstractProxyModel); |
395 | *sourceRow = -1; |
396 | *sourceColumn = -1; |
397 | if (row == -1 && column == -1) { |
398 | *sourceParent = q->mapToSource(parent); |
399 | } else if (row == q->rowCount(parent)) { |
400 | *sourceParent = q->mapToSource(parent); |
401 | *sourceRow = model->rowCount(*sourceParent); |
402 | } else { |
403 | QModelIndex proxyIndex = q->index(row, column, parent); |
404 | QModelIndex sourceIndex = q->mapToSource(proxyIndex); |
405 | *sourceRow = sourceIndex.row(); |
406 | *sourceColumn = sourceIndex.column(); |
407 | *sourceParent = sourceIndex.parent(); |
408 | } |
409 | } |
410 | |
411 | /*! |
412 | \reimp |
413 | \since 5.4 |
414 | */ |
415 | bool QAbstractProxyModel::canDropMimeData(const QMimeData *data, Qt::DropAction action, |
416 | int row, int column, const QModelIndex &parent) const |
417 | { |
418 | Q_D(const QAbstractProxyModel); |
419 | int sourceDestinationRow; |
420 | int sourceDestinationColumn; |
421 | QModelIndex sourceParent; |
422 | d->mapDropCoordinatesToSource(row, column, parent, &sourceDestinationRow, &sourceDestinationColumn, &sourceParent); |
423 | return d->model->canDropMimeData(data, action, sourceDestinationRow, sourceDestinationColumn, sourceParent); |
424 | } |
425 | |
426 | /*! |
427 | \reimp |
428 | \since 5.4 |
429 | */ |
430 | bool QAbstractProxyModel::dropMimeData(const QMimeData *data, Qt::DropAction action, |
431 | int row, int column, const QModelIndex &parent) |
432 | { |
433 | Q_D(QAbstractProxyModel); |
434 | int sourceDestinationRow; |
435 | int sourceDestinationColumn; |
436 | QModelIndex sourceParent; |
437 | d->mapDropCoordinatesToSource(row, column, parent, &sourceDestinationRow, &sourceDestinationColumn, &sourceParent); |
438 | return d->model->dropMimeData(data, action, sourceDestinationRow, sourceDestinationColumn, sourceParent); |
439 | } |
440 | |
441 | /*! |
442 | \reimp |
443 | */ |
444 | QStringList QAbstractProxyModel::mimeTypes() const |
445 | { |
446 | Q_D(const QAbstractProxyModel); |
447 | return d->model->mimeTypes(); |
448 | } |
449 | |
450 | /*! |
451 | \reimp |
452 | */ |
453 | Qt::DropActions QAbstractProxyModel::supportedDragActions() const |
454 | { |
455 | Q_D(const QAbstractProxyModel); |
456 | return d->model->supportedDragActions(); |
457 | } |
458 | |
459 | /*! |
460 | \reimp |
461 | */ |
462 | Qt::DropActions QAbstractProxyModel::supportedDropActions() const |
463 | { |
464 | Q_D(const QAbstractProxyModel); |
465 | return d->model->supportedDropActions(); |
466 | } |
467 | |
468 | /*! |
469 | \reimp |
470 | */ |
471 | QHash<int,QByteArray> QAbstractProxyModel::roleNames() const |
472 | { |
473 | Q_D(const QAbstractProxyModel); |
474 | return d->model->roleNames(); |
475 | } |
476 | |
477 | |
478 | QT_END_NAMESPACE |
479 | |
480 | #include "moc_qabstractproxymodel.cpp" |
481 | |