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(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 | */ |
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 | */ |
158 | 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 | */ |
169 | bool QAbstractProxyModel::submit() |
170 | { |
171 | Q_D(QAbstractProxyModel); |
172 | return d->model->submit(); |
173 | } |
174 | |
175 | /*! |
176 | \reimp |
177 | */ |
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 | */ |
208 | 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(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 | */ |
226 | 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(sourceIndex: sourceIndexes.at(i)); |
232 | if (!srcIdx.isValid()) |
233 | continue; |
234 | proxySelection << QItemSelectionRange(srcIdx); |
235 | } |
236 | return proxySelection; |
237 | } |
238 | |
239 | /*! |
240 | \reimp |
241 | */ |
242 | QVariant 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 | */ |
251 | QVariant QAbstractProxyModel::(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 | */ |
268 | QMap<int, QVariant> QAbstractProxyModel::itemData(const QModelIndex &proxyIndex) const |
269 | { |
270 | return QAbstractItemModel::itemData(index: proxyIndex); |
271 | } |
272 | |
273 | /*! |
274 | \reimp |
275 | */ |
276 | Qt::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 | */ |
285 | bool 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 | */ |
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 | */ |
302 | bool QAbstractProxyModel::(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 | */ |
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 | */ |
331 | QModelIndex 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 | */ |
340 | bool 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 | */ |
349 | void QAbstractProxyModel::fetchMore(const QModelIndex &parent) |
350 | { |
351 | Q_D(QAbstractProxyModel); |
352 | d->model->fetchMore(parent: mapToSource(proxyIndex: parent)); |
353 | } |
354 | |
355 | /*! |
356 | \reimp |
357 | */ |
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 | */ |
367 | QSize 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 | */ |
376 | bool 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 | */ |
385 | QModelIndex 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 | */ |
393 | QMimeData* 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 | |
403 | 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(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 | */ |
427 | 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, 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 | */ |
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, 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 | */ |
456 | QStringList QAbstractProxyModel::mimeTypes() const |
457 | { |
458 | Q_D(const QAbstractProxyModel); |
459 | return d->model->mimeTypes(); |
460 | } |
461 | |
462 | /*! |
463 | \reimp |
464 | */ |
465 | Qt::DropActions QAbstractProxyModel::supportedDragActions() const |
466 | { |
467 | Q_D(const QAbstractProxyModel); |
468 | return d->model->supportedDragActions(); |
469 | } |
470 | |
471 | /*! |
472 | \reimp |
473 | */ |
474 | 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 | |