1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtGui module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qsortfilterproxymodel.h"
44 #ifndef QT_NO_SORTFILTERPROXYMODEL
46 #include "qitemselectionmodel.h"
49 #include <qdatetime.h>
51 #include <qstringlist.h>
52 #include <private/qabstractitemmodel_p.h>
53 #include <private/qabstractproxymodel_p.h>
57 typedef QList<QPair<QModelIndex, QPersistentModelIndex> > QModelIndexPairList;
59 static inline QSet<int> qVectorToSet(const QVector<int> &vector)
62 set.reserve(vector.size());
63 for(int i=0; i < vector.size(); ++i)
68 class QSortFilterProxyModelLessThan
71 inline QSortFilterProxyModelLessThan(int column, const QModelIndex &parent,
72 const QAbstractItemModel *source,
73 const QSortFilterProxyModel *proxy)
74 : sort_column(column), source_parent(parent), source_model(source), proxy_model(proxy) {}
76 inline bool operator()(int r1, int r2) const
78 QModelIndex i1 = source_model->index(r1, sort_column, source_parent);
79 QModelIndex i2 = source_model->index(r2, sort_column, source_parent);
80 return proxy_model->lessThan(i1, i2);
85 QModelIndex source_parent;
86 const QAbstractItemModel *source_model;
87 const QSortFilterProxyModel *proxy_model;
90 class QSortFilterProxyModelGreaterThan
93 inline QSortFilterProxyModelGreaterThan(int column, const QModelIndex &parent,
94 const QAbstractItemModel *source,
95 const QSortFilterProxyModel *proxy)
96 : sort_column(column), source_parent(parent),
97 source_model(source), proxy_model(proxy) {}
99 inline bool operator()(int r1, int r2) const
101 QModelIndex i1 = source_model->index(r1, sort_column, source_parent);
102 QModelIndex i2 = source_model->index(r2, sort_column, source_parent);
103 return proxy_model->lessThan(i2, i1);
108 QModelIndex source_parent;
109 const QAbstractItemModel *source_model;
110 const QSortFilterProxyModel *proxy_model;
114 //this struct is used to store what are the rows that are removed
115 //between a call to rowsAboutToBeRemoved and rowsRemoved
116 //it avoids readding rows to the mapping that are currently being removed
119 QRowsRemoval(const QModelIndex &parent_source, int start, int end) : parent_source(parent_source), start(start), end(end)
123 QRowsRemoval() : start(-1), end(-1)
127 bool contains(QModelIndex parent, int row)
130 if (parent == parent_source)
131 return row >= start && row <= end;
133 parent = parent.parent();
138 QModelIndex parent_source;
143 class QSortFilterProxyModelPrivate : public QAbstractProxyModelPrivate
145 Q_DECLARE_PUBLIC(QSortFilterProxyModel)
149 QVector<int> source_rows;
150 QVector<int> source_columns;
151 QVector<int> proxy_rows;
152 QVector<int> proxy_columns;
153 QVector<QModelIndex> mapped_children;
154 QHash<QModelIndex, Mapping *>::const_iterator map_iter;
157 mutable QHash<QModelIndex, Mapping*> source_index_mapping;
159 int source_sort_column;
160 int proxy_sort_column;
161 Qt::SortOrder sort_order;
162 Qt::CaseSensitivity sort_casesensitivity;
164 bool sort_localeaware;
167 QRegExp filter_regexp;
170 bool dynamic_sortfilter;
171 QRowsRemoval itemsBeingRemoved;
173 QModelIndexPairList saved_persistent_indexes;
175 QHash<QModelIndex, Mapping *>::const_iterator create_mapping(
176 const QModelIndex &source_parent) const;
177 QModelIndex proxy_to_source(const QModelIndex &proxyIndex) const;
178 QModelIndex source_to_proxy(const QModelIndex &sourceIndex) const;
179 bool can_create_mapping(const QModelIndex &source_parent) const;
181 void remove_from_mapping(const QModelIndex &source_parent);
183 inline QHash<QModelIndex, Mapping *>::const_iterator index_to_iterator(
184 const QModelIndex &proxy_index) const
186 Q_ASSERT(proxy_index.isValid());
187 Q_ASSERT(proxy_index.model() == q_func());
188 const void *p = proxy_index.internalPointer();
190 QHash<QModelIndex, Mapping *>::const_iterator it =
191 static_cast<const Mapping*>(p)->map_iter;
192 Q_ASSERT(it != source_index_mapping.constEnd());
193 Q_ASSERT(it.value());
197 inline QModelIndex create_index(int row, int column,
198 QHash<QModelIndex, Mapping*>::const_iterator it) const
200 return q_func()->createIndex(row, column, *it);
203 void _q_sourceDataChanged(const QModelIndex &source_top_left,
204 const QModelIndex &source_bottom_right);
205 void _q_sourceHeaderDataChanged(Qt::Orientation orientation, int start, int end);
207 void _q_sourceAboutToBeReset();
208 void _q_sourceReset();
210 void _q_sourceLayoutAboutToBeChanged(const QList<QPersistentModelIndex> &sourceParents);
211 void _q_sourceLayoutChanged(const QList<QPersistentModelIndex> &sourceParents);
213 void _q_sourceRowsAboutToBeInserted(const QModelIndex &source_parent,
215 void _q_sourceRowsInserted(const QModelIndex &source_parent,
217 void _q_sourceRowsAboutToBeRemoved(const QModelIndex &source_parent,
219 void _q_sourceRowsRemoved(const QModelIndex &source_parent,
221 void _q_sourceRowsAboutToBeMoved(const QModelIndex &sourceParent,
222 int sourceStart, int sourceEnd,
223 const QModelIndex &destParent, int dest);
224 void _q_sourceRowsMoved(const QModelIndex &sourceParent,
225 int sourceStart, int sourceEnd,
226 const QModelIndex &destParent, int dest);
227 void _q_sourceColumnsAboutToBeInserted(const QModelIndex &source_parent,
229 void _q_sourceColumnsInserted(const QModelIndex &source_parent,
231 void _q_sourceColumnsAboutToBeRemoved(const QModelIndex &source_parent,
233 void _q_sourceColumnsRemoved(const QModelIndex &source_parent,
235 void _q_sourceColumnsAboutToBeMoved(const QModelIndex &sourceParent,
236 int sourceStart, int sourceEnd,
237 const QModelIndex &destParent, int dest);
238 void _q_sourceColumnsMoved(const QModelIndex &sourceParent,
239 int sourceStart, int sourceEnd,
240 const QModelIndex &destParent, int dest);
242 void _q_clearMapping();
245 bool update_source_sort_column();
246 void sort_source_rows(QVector<int> &source_rows,
247 const QModelIndex &source_parent) const;
248 QVector<QPair<int, QVector<int > > > proxy_intervals_for_source_items_to_add(
249 const QVector<int> &proxy_to_source, const QVector<int> &source_items,
250 const QModelIndex &source_parent, Qt::Orientation orient) const;
251 QVector<QPair<int, int > > proxy_intervals_for_source_items(
252 const QVector<int> &source_to_proxy, const QVector<int> &source_items) const;
253 void insert_source_items(
254 QVector<int> &source_to_proxy, QVector<int> &proxy_to_source,
255 const QVector<int> &source_items, const QModelIndex &source_parent,
256 Qt::Orientation orient, bool emit_signal = true);
257 void remove_source_items(
258 QVector<int> &source_to_proxy, QVector<int> &proxy_to_source,
259 const QVector<int> &source_items, const QModelIndex &source_parent,
260 Qt::Orientation orient, bool emit_signal = true);
261 void remove_proxy_interval(
262 QVector<int> &source_to_proxy, QVector<int> &proxy_to_source,
263 int proxy_start, int proxy_end, const QModelIndex &proxy_parent,
264 Qt::Orientation orient, bool emit_signal = true);
265 void build_source_to_proxy_mapping(
266 const QVector<int> &proxy_to_source, QVector<int> &source_to_proxy) const;
267 void source_items_inserted(const QModelIndex &source_parent,
268 int start, int end, Qt::Orientation orient);
269 void source_items_about_to_be_removed(const QModelIndex &source_parent,
270 int start, int end, Qt::Orientation orient);
271 void source_items_removed(const QModelIndex &source_parent,
272 int start, int end, Qt::Orientation orient);
273 void proxy_item_range(
274 const QVector<int> &source_to_proxy, const QVector<int> &source_items,
275 int &proxy_low, int &proxy_high) const;
277 QModelIndexPairList store_persistent_indexes();
278 void update_persistent_indexes(const QModelIndexPairList &source_indexes);
280 void filter_changed(const QModelIndex &source_parent = QModelIndex());
281 QSet<int> handle_filter_changed(
282 QVector<int> &source_to_proxy, QVector<int> &proxy_to_source,
283 const QModelIndex &source_parent, Qt::Orientation orient);
285 void updateChildrenMapping(const QModelIndex &source_parent, Mapping *parent_mapping,
286 Qt::Orientation orient, int start, int end, int delta_item_count, bool remove);
288 virtual void _q_sourceModelDestroyed();
291 typedef QHash<QModelIndex, QSortFilterProxyModelPrivate::Mapping *> IndexMap;
293 void QSortFilterProxyModelPrivate::_q_sourceModelDestroyed()
295 QAbstractProxyModelPrivate::_q_sourceModelDestroyed();
299 void QSortFilterProxyModelPrivate::remove_from_mapping(const QModelIndex &source_parent)
301 if (Mapping *m = source_index_mapping.take(source_parent)) {
302 for (int i = 0; i < m->mapped_children.size(); ++i)
303 remove_from_mapping(m->mapped_children.at(i));
308 void QSortFilterProxyModelPrivate::_q_clearMapping()
310 // store the persistent indexes
311 QModelIndexPairList source_indexes = store_persistent_indexes();
313 qDeleteAll(source_index_mapping);
314 source_index_mapping.clear();
315 if (dynamic_sortfilter && update_source_sort_column()) {
316 //update_source_sort_column might have created wrong mapping so we have to clear it again
317 qDeleteAll(source_index_mapping);
318 source_index_mapping.clear();
321 // update the persistent indexes
322 update_persistent_indexes(source_indexes);
325 IndexMap::const_iterator QSortFilterProxyModelPrivate::create_mapping(
326 const QModelIndex &source_parent) const
328 Q_Q(const QSortFilterProxyModel);
330 IndexMap::const_iterator it = source_index_mapping.constFind(source_parent);
331 if (it != source_index_mapping.constEnd()) // was mapped already
334 Mapping *m = new Mapping;
336 int source_rows = model->rowCount(source_parent);
337 m->source_rows.reserve(source_rows);
338 for (int i = 0; i < source_rows; ++i) {
339 if (q->filterAcceptsRow(i, source_parent))
340 m->source_rows.append(i);
342 int source_cols = model->columnCount(source_parent);
343 m->source_columns.reserve(source_cols);
344 for (int i = 0; i < source_cols; ++i) {
345 if (q->filterAcceptsColumn(i, source_parent))
346 m->source_columns.append(i);
349 sort_source_rows(m->source_rows, source_parent);
350 m->proxy_rows.resize(source_rows);
351 build_source_to_proxy_mapping(m->source_rows, m->proxy_rows);
352 m->proxy_columns.resize(source_cols);
353 build_source_to_proxy_mapping(m->source_columns, m->proxy_columns);
355 it = IndexMap::const_iterator(source_index_mapping.insert(source_parent, m));
358 if (source_parent.isValid()) {
359 QModelIndex source_grand_parent = source_parent.parent();
360 IndexMap::const_iterator it2 = create_mapping(source_grand_parent);
361 Q_ASSERT(it2 != source_index_mapping.constEnd());
362 it2.value()->mapped_children.append(source_parent);
365 Q_ASSERT(it != source_index_mapping.constEnd());
366 Q_ASSERT(it.value());
371 QModelIndex QSortFilterProxyModelPrivate::proxy_to_source(const QModelIndex &proxy_index) const
373 if (!proxy_index.isValid())
374 return QModelIndex(); // for now; we may want to be able to set a root index later
375 if (proxy_index.model() != q_func()) {
376 qWarning() << "QSortFilterProxyModel: index from wrong model passed to mapToSource";
377 Q_ASSERT(!"QSortFilterProxyModel: index from wrong model passed to mapToSource");
378 return QModelIndex();
380 IndexMap::const_iterator it = index_to_iterator(proxy_index);
381 Mapping *m = it.value();
382 if ((proxy_index.row() >= m->source_rows.size()) || (proxy_index.column() >= m->source_columns.size()))
383 return QModelIndex();
384 int source_row = m->source_rows.at(proxy_index.row());
385 int source_col = m->source_columns.at(proxy_index.column());
386 return model->index(source_row, source_col, it.key());
389 QModelIndex QSortFilterProxyModelPrivate::source_to_proxy(const QModelIndex &source_index) const
391 if (!source_index.isValid())
392 return QModelIndex(); // for now; we may want to be able to set a root index later
393 if (source_index.model() != model) {
394 qWarning() << "QSortFilterProxyModel: index from wrong model passed to mapFromSource";
395 Q_ASSERT(!"QSortFilterProxyModel: index from wrong model passed to mapFromSource");
396 return QModelIndex();
398 QModelIndex source_parent = source_index.parent();
399 IndexMap::const_iterator it = create_mapping(source_parent);
400 Mapping *m = it.value();
401 if ((source_index.row() >= m->proxy_rows.size()) || (source_index.column() >= m->proxy_columns.size()))
402 return QModelIndex();
403 int proxy_row = m->proxy_rows.at(source_index.row());
404 int proxy_column = m->proxy_columns.at(source_index.column());
405 if (proxy_row == -1 || proxy_column == -1)
406 return QModelIndex();
407 return create_index(proxy_row, proxy_column, it);
410 bool QSortFilterProxyModelPrivate::can_create_mapping(const QModelIndex &source_parent) const
412 if (source_parent.isValid()) {
413 QModelIndex source_grand_parent = source_parent.parent();
414 IndexMap::const_iterator it = source_index_mapping.constFind(source_grand_parent);
415 if (it == source_index_mapping.constEnd()) {
416 // Don't care, since we don't have mapping for the grand parent
419 Mapping *gm = it.value();
420 if (gm->proxy_rows.at(source_parent.row()) == -1 ||
421 gm->proxy_columns.at(source_parent.column()) == -1) {
422 // Don't care, since parent is filtered
432 Sorts the existing mappings.
434 void QSortFilterProxyModelPrivate::sort()
436 Q_Q(QSortFilterProxyModel);
437 emit q->layoutAboutToBeChanged();
438 QModelIndexPairList source_indexes = store_persistent_indexes();
439 IndexMap::const_iterator it = source_index_mapping.constBegin();
440 for (; it != source_index_mapping.constEnd(); ++it) {
441 QModelIndex source_parent = it.key();
442 Mapping *m = it.value();
443 sort_source_rows(m->source_rows, source_parent);
444 build_source_to_proxy_mapping(m->source_rows, m->proxy_rows);
446 update_persistent_indexes(source_indexes);
447 emit q->layoutChanged();
453 update the source_sort_column according to the proxy_sort_column
454 return true if the column was changed
456 bool QSortFilterProxyModelPrivate::update_source_sort_column()
458 Q_Q(QSortFilterProxyModel);
459 QModelIndex proxy_index = q->index(0, proxy_sort_column, QModelIndex());
460 int old_source_sort_colum = source_sort_column;
461 source_sort_column = q->mapToSource(proxy_index).column();
462 return old_source_sort_colum != source_sort_column;
469 Sorts the given \a source_rows according to current sort column and order.
471 void QSortFilterProxyModelPrivate::sort_source_rows(
472 QVector<int> &source_rows, const QModelIndex &source_parent) const
474 Q_Q(const QSortFilterProxyModel);
475 if (source_sort_column >= 0) {
476 if (sort_order == Qt::AscendingOrder) {
477 QSortFilterProxyModelLessThan lt(source_sort_column, source_parent, model, q);
478 qStableSort(source_rows.begin(), source_rows.end(), lt);
480 QSortFilterProxyModelGreaterThan gt(source_sort_column, source_parent, model, q);
481 qStableSort(source_rows.begin(), source_rows.end(), gt);
483 } else { // restore the source model order
484 qStableSort(source_rows.begin(), source_rows.end());
491 Given source-to-proxy mapping \a source_to_proxy and the set of
492 source items \a source_items (which are part of that mapping),
493 determines the corresponding proxy item intervals that should
494 be removed from the proxy model.
496 The result is a vector of pairs, where each pair represents a
497 (start, end) tuple, sorted in ascending order.
499 QVector<QPair<int, int > > QSortFilterProxyModelPrivate::proxy_intervals_for_source_items(
500 const QVector<int> &source_to_proxy, const QVector<int> &source_items) const
502 QVector<QPair<int, int> > proxy_intervals;
503 if (source_items.isEmpty())
504 return proxy_intervals;
506 int source_items_index = 0;
507 while (source_items_index < source_items.size()) {
508 int first_proxy_item = source_to_proxy.at(source_items.at(source_items_index));
509 Q_ASSERT(first_proxy_item != -1);
510 int last_proxy_item = first_proxy_item;
511 ++source_items_index;
512 // Find end of interval
513 while ((source_items_index < source_items.size())
514 && (source_to_proxy.at(source_items.at(source_items_index)) == last_proxy_item + 1)) {
516 ++source_items_index;
518 // Add interval to result
519 proxy_intervals.append(QPair<int, int>(first_proxy_item, last_proxy_item));
521 qStableSort(proxy_intervals.begin(), proxy_intervals.end());
522 return proxy_intervals;
528 Given source-to-proxy mapping \a src_to_proxy and proxy-to-source mapping
529 \a proxy_to_source, removes \a source_items from this proxy model.
530 The corresponding proxy items are removed in intervals, so that the proper
531 rows/columnsRemoved(start, end) signals will be generated.
533 void QSortFilterProxyModelPrivate::remove_source_items(
534 QVector<int> &source_to_proxy, QVector<int> &proxy_to_source,
535 const QVector<int> &source_items, const QModelIndex &source_parent,
536 Qt::Orientation orient, bool emit_signal)
538 Q_Q(QSortFilterProxyModel);
539 QModelIndex proxy_parent = q->mapFromSource(source_parent);
540 if (!proxy_parent.isValid() && source_parent.isValid())
541 return; // nothing to do (already removed)
543 QVector<QPair<int, int> > proxy_intervals;
544 proxy_intervals = proxy_intervals_for_source_items(source_to_proxy, source_items);
546 for (int i = proxy_intervals.size()-1; i >= 0; --i) {
547 QPair<int, int> interval = proxy_intervals.at(i);
548 int proxy_start = interval.first;
549 int proxy_end = interval.second;
550 remove_proxy_interval(source_to_proxy, proxy_to_source, proxy_start, proxy_end,
551 proxy_parent, orient, emit_signal);
558 Given source-to-proxy mapping \a source_to_proxy and proxy-to-source mapping
559 \a proxy_to_source, removes items from \a proxy_start to \a proxy_end
560 (inclusive) from this proxy model.
562 void QSortFilterProxyModelPrivate::remove_proxy_interval(
563 QVector<int> &source_to_proxy, QVector<int> &proxy_to_source, int proxy_start, int proxy_end,
564 const QModelIndex &proxy_parent, Qt::Orientation orient, bool emit_signal)
566 Q_Q(QSortFilterProxyModel);
568 if (orient == Qt::Vertical)
569 q->beginRemoveRows(proxy_parent, proxy_start, proxy_end);
571 q->beginRemoveColumns(proxy_parent, proxy_start, proxy_end);
574 // Remove items from proxy-to-source mapping
575 proxy_to_source.remove(proxy_start, proxy_end - proxy_start + 1);
577 build_source_to_proxy_mapping(proxy_to_source, source_to_proxy);
580 if (orient == Qt::Vertical)
583 q->endRemoveColumns();
590 Given proxy-to-source mapping \a proxy_to_source and a set of
591 unmapped source items \a source_items, determines the proxy item
592 intervals at which the subsets of source items should be inserted
593 (but does not actually add them to the mapping).
595 The result is a vector of pairs, each pair representing a tuple (start,
596 items), where items is a vector containing the (sorted) source items that
597 should be inserted at that proxy model location.
599 QVector<QPair<int, QVector<int > > > QSortFilterProxyModelPrivate::proxy_intervals_for_source_items_to_add(
600 const QVector<int> &proxy_to_source, const QVector<int> &source_items,
601 const QModelIndex &source_parent, Qt::Orientation orient) const
603 Q_Q(const QSortFilterProxyModel);
604 QVector<QPair<int, QVector<int> > > proxy_intervals;
605 if (source_items.isEmpty())
606 return proxy_intervals;
610 int source_items_index = 0;
611 QVector<int> source_items_in_interval;
612 bool compare = (orient == Qt::Vertical && source_sort_column >= 0 && dynamic_sortfilter);
613 while (source_items_index < source_items.size()) {
614 source_items_in_interval.clear();
615 int first_new_source_item = source_items.at(source_items_index);
616 source_items_in_interval.append(first_new_source_item);
617 ++source_items_index;
619 // Find proxy item at which insertion should be started
620 int proxy_high = proxy_to_source.size() - 1;
621 QModelIndex i1 = compare ? model->index(first_new_source_item, source_sort_column, source_parent) : QModelIndex();
622 while (proxy_low <= proxy_high) {
623 proxy_item = (proxy_low + proxy_high) / 2;
625 QModelIndex i2 = model->index(proxy_to_source.at(proxy_item), source_sort_column, source_parent);
626 if ((sort_order == Qt::AscendingOrder) ? q->lessThan(i1, i2) : q->lessThan(i2, i1))
627 proxy_high = proxy_item - 1;
629 proxy_low = proxy_item + 1;
631 if (first_new_source_item < proxy_to_source.at(proxy_item))
632 proxy_high = proxy_item - 1;
634 proxy_low = proxy_item + 1;
637 proxy_item = proxy_low;
639 // Find the sequence of new source items that should be inserted here
640 if (proxy_item >= proxy_to_source.size()) {
641 for ( ; source_items_index < source_items.size(); ++source_items_index)
642 source_items_in_interval.append(source_items.at(source_items_index));
644 i1 = compare ? model->index(proxy_to_source.at(proxy_item), source_sort_column, source_parent) : QModelIndex();
645 for ( ; source_items_index < source_items.size(); ++source_items_index) {
646 int new_source_item = source_items.at(source_items_index);
648 QModelIndex i2 = model->index(new_source_item, source_sort_column, source_parent);
649 if ((sort_order == Qt::AscendingOrder) ? q->lessThan(i1, i2) : q->lessThan(i2, i1))
652 if (proxy_to_source.at(proxy_item) < new_source_item)
655 source_items_in_interval.append(new_source_item);
659 // Add interval to result
660 proxy_intervals.append(QPair<int, QVector<int> >(proxy_item, source_items_in_interval));
662 return proxy_intervals;
668 Given source-to-proxy mapping \a source_to_proxy and proxy-to-source mapping
669 \a proxy_to_source, inserts the given \a source_items into this proxy model.
670 The source items are inserted in intervals (based on some sorted order), so
671 that the proper rows/columnsInserted(start, end) signals will be generated.
673 void QSortFilterProxyModelPrivate::insert_source_items(
674 QVector<int> &source_to_proxy, QVector<int> &proxy_to_source,
675 const QVector<int> &source_items, const QModelIndex &source_parent,
676 Qt::Orientation orient, bool emit_signal)
678 Q_Q(QSortFilterProxyModel);
679 QModelIndex proxy_parent = q->mapFromSource(source_parent);
680 if (!proxy_parent.isValid() && source_parent.isValid())
681 return; // nothing to do (source_parent is not mapped)
683 QVector<QPair<int, QVector<int> > > proxy_intervals;
684 proxy_intervals = proxy_intervals_for_source_items_to_add(
685 proxy_to_source, source_items, source_parent, orient);
687 for (int i = proxy_intervals.size()-1; i >= 0; --i) {
688 QPair<int, QVector<int> > interval = proxy_intervals.at(i);
689 int proxy_start = interval.first;
690 QVector<int> source_items = interval.second;
691 int proxy_end = proxy_start + source_items.size() - 1;
694 if (orient == Qt::Vertical)
695 q->beginInsertRows(proxy_parent, proxy_start, proxy_end);
697 q->beginInsertColumns(proxy_parent, proxy_start, proxy_end);
700 for (int i = 0; i < source_items.size(); ++i)
701 proxy_to_source.insert(proxy_start + i, source_items.at(i));
703 build_source_to_proxy_mapping(proxy_to_source, source_to_proxy);
706 if (orient == Qt::Vertical)
709 q->endInsertColumns();
717 Handles source model items insertion (columnsInserted(), rowsInserted()).
719 1) which of the inserted items to also insert into proxy model (filtering),
720 2) where to insert the items into the proxy model (sorting),
721 then inserts those items.
722 The items are inserted into the proxy model in intervals (based on
723 sorted order), so that the proper rows/columnsInserted(start, end)
724 signals will be generated.
726 void QSortFilterProxyModelPrivate::source_items_inserted(
727 const QModelIndex &source_parent, int start, int end, Qt::Orientation orient)
729 Q_Q(QSortFilterProxyModel);
730 if ((start < 0) || (end < 0))
732 IndexMap::const_iterator it = source_index_mapping.constFind(source_parent);
733 if (it == source_index_mapping.constEnd()) {
734 if (!can_create_mapping(source_parent))
736 it = create_mapping(source_parent);
737 Mapping *m = it.value();
738 QModelIndex proxy_parent = q->mapFromSource(source_parent);
739 if (m->source_rows.count() > 0) {
740 q->beginInsertRows(proxy_parent, 0, m->source_rows.count() - 1);
743 if (m->source_columns.count() > 0) {
744 q->beginInsertColumns(proxy_parent, 0, m->source_columns.count() - 1);
745 q->endInsertColumns();
750 Mapping *m = it.value();
751 QVector<int> &source_to_proxy = (orient == Qt::Vertical) ? m->proxy_rows : m->proxy_columns;
752 QVector<int> &proxy_to_source = (orient == Qt::Vertical) ? m->source_rows : m->source_columns;
754 int delta_item_count = end - start + 1;
755 int old_item_count = source_to_proxy.size();
757 updateChildrenMapping(source_parent, m, orient, start, end, delta_item_count, false);
759 // Expand source-to-proxy mapping to account for new items
760 if (start < 0 || start > source_to_proxy.size()) {
761 qWarning("QSortFilterProxyModel: invalid inserted rows reported by source model");
762 remove_from_mapping(source_parent);
765 source_to_proxy.insert(start, delta_item_count, -1);
767 if (start < old_item_count) {
768 // Adjust existing "stale" indexes in proxy-to-source mapping
769 int proxy_count = proxy_to_source.size();
770 for (int proxy_item = 0; proxy_item < proxy_count; ++proxy_item) {
771 int source_item = proxy_to_source.at(proxy_item);
772 if (source_item >= start)
773 proxy_to_source.replace(proxy_item, source_item + delta_item_count);
775 build_source_to_proxy_mapping(proxy_to_source, source_to_proxy);
778 // Figure out which items to add to mapping based on filter
779 QVector<int> source_items;
780 for (int i = start; i <= end; ++i) {
781 if ((orient == Qt::Vertical)
782 ? q->filterAcceptsRow(i, source_parent)
783 : q->filterAcceptsColumn(i, source_parent)) {
784 source_items.append(i);
788 if (model->rowCount(source_parent) == delta_item_count) {
789 // Items were inserted where there were none before.
790 // If it was new rows make sure to create mappings for columns so that a
791 // valid mapping can be retrieved later and vice-versa.
793 QVector<int> &orthogonal_proxy_to_source = (orient == Qt::Horizontal) ? m->source_rows : m->source_columns;
794 QVector<int> &orthogonal_source_to_proxy = (orient == Qt::Horizontal) ? m->proxy_rows : m->proxy_columns;
796 if (orthogonal_source_to_proxy.isEmpty()) {
797 const int ortho_end = (orient == Qt::Horizontal) ? model->rowCount(source_parent) : model->columnCount(source_parent);
799 orthogonal_source_to_proxy.resize(ortho_end);
801 for (int ortho_item = 0; ortho_item < ortho_end; ++ortho_item) {
802 if ((orient == Qt::Horizontal) ? q->filterAcceptsRow(ortho_item, source_parent)
803 : q->filterAcceptsColumn(ortho_item, source_parent)) {
804 orthogonal_proxy_to_source.append(ortho_item);
807 if (orient == Qt::Horizontal) {
808 // We're reacting to columnsInserted, but we've just inserted new rows. Sort them.
809 sort_source_rows(orthogonal_proxy_to_source, source_parent);
811 build_source_to_proxy_mapping(orthogonal_proxy_to_source, orthogonal_source_to_proxy);
815 // Sort and insert the items
816 if (orient == Qt::Vertical) // Only sort rows
817 sort_source_rows(source_items, source_parent);
818 insert_source_items(source_to_proxy, proxy_to_source, source_items, source_parent, orient);
824 Handles source model items removal
825 (columnsAboutToBeRemoved(), rowsAboutToBeRemoved()).
827 void QSortFilterProxyModelPrivate::source_items_about_to_be_removed(
828 const QModelIndex &source_parent, int start, int end, Qt::Orientation orient)
830 if ((start < 0) || (end < 0))
832 IndexMap::const_iterator it = source_index_mapping.constFind(source_parent);
833 if (it == source_index_mapping.constEnd()) {
834 // Don't care, since we don't have mapping for this index
838 Mapping *m = it.value();
839 QVector<int> &source_to_proxy = (orient == Qt::Vertical) ? m->proxy_rows : m->proxy_columns;
840 QVector<int> &proxy_to_source = (orient == Qt::Vertical) ? m->source_rows : m->source_columns;
842 // figure out which items to remove
843 QVector<int> source_items_to_remove;
844 int proxy_count = proxy_to_source.size();
845 for (int proxy_item = 0; proxy_item < proxy_count; ++proxy_item) {
846 int source_item = proxy_to_source.at(proxy_item);
847 if ((source_item >= start) && (source_item <= end))
848 source_items_to_remove.append(source_item);
851 remove_source_items(source_to_proxy, proxy_to_source, source_items_to_remove,
852 source_parent, orient);
858 Handles source model items removal (columnsRemoved(), rowsRemoved()).
860 void QSortFilterProxyModelPrivate::source_items_removed(
861 const QModelIndex &source_parent, int start, int end, Qt::Orientation orient)
863 if ((start < 0) || (end < 0))
865 IndexMap::const_iterator it = source_index_mapping.constFind(source_parent);
866 if (it == source_index_mapping.constEnd()) {
867 // Don't care, since we don't have mapping for this index
871 Mapping *m = it.value();
872 QVector<int> &source_to_proxy = (orient == Qt::Vertical) ? m->proxy_rows : m->proxy_columns;
873 QVector<int> &proxy_to_source = (orient == Qt::Vertical) ? m->source_rows : m->source_columns;
875 if (end >= source_to_proxy.size())
876 end = source_to_proxy.size() - 1;
878 // Shrink the source-to-proxy mapping to reflect the new item count
879 int delta_item_count = end - start + 1;
880 source_to_proxy.remove(start, delta_item_count);
882 int proxy_count = proxy_to_source.size();
883 if (proxy_count > source_to_proxy.size()) {
884 // mapping is in an inconsistent state -- redo the whole mapping
885 qWarning("QSortFilterProxyModel: inconsistent changes reported by source model");
886 Q_Q(QSortFilterProxyModel);
887 q->beginResetModel();
888 remove_from_mapping(source_parent);
893 // Adjust "stale" indexes in proxy-to-source mapping
894 for (int proxy_item = 0; proxy_item < proxy_count; ++proxy_item) {
895 int source_item = proxy_to_source.at(proxy_item);
896 if (source_item >= start) {
897 Q_ASSERT(source_item - delta_item_count >= 0);
898 proxy_to_source.replace(proxy_item, source_item - delta_item_count);
901 build_source_to_proxy_mapping(proxy_to_source, source_to_proxy);
903 updateChildrenMapping(source_parent, m, orient, start, end, delta_item_count, true);
910 updates the mapping of the children when inserting or removing items
912 void QSortFilterProxyModelPrivate::updateChildrenMapping(const QModelIndex &source_parent, Mapping *parent_mapping,
913 Qt::Orientation orient, int start, int end, int delta_item_count, bool remove)
915 // see if any mapped children should be (re)moved
916 QVector<QPair<QModelIndex, Mapping*> > moved_source_index_mappings;
917 QVector<QModelIndex>::iterator it2 = parent_mapping->mapped_children.begin();
918 for ( ; it2 != parent_mapping->mapped_children.end();) {
919 const QModelIndex source_child_index = *it2;
920 const int pos = (orient == Qt::Vertical)
921 ? source_child_index.row()
922 : source_child_index.column();
926 } else if (remove && pos <= end) {
927 // in the removed interval
928 it2 = parent_mapping->mapped_children.erase(it2);
929 remove_from_mapping(source_child_index);
931 // below the removed items -- recompute the index
932 QModelIndex new_index;
933 const int newpos = remove ? pos - delta_item_count : pos + delta_item_count;
934 if (orient == Qt::Vertical) {
935 new_index = model->index(newpos,
936 source_child_index.column(),
939 new_index = model->index(source_child_index.row(),
947 Mapping *cm = source_index_mapping.take(source_child_index);
949 // we do not reinsert right away, because the new index might be identical with another, old index
950 moved_source_index_mappings.append(QPair<QModelIndex, Mapping*>(new_index, cm));
954 // reinsert moved, mapped indexes
955 QVector<QPair<QModelIndex, Mapping*> >::iterator it = moved_source_index_mappings.begin();
956 for (; it != moved_source_index_mappings.end(); ++it) {
957 #ifdef QT_STRICT_ITERATORS
958 source_index_mapping.insert((*it).first, (*it).second);
959 (*it).second->map_iter = source_index_mapping.constFind((*it).first);
961 (*it).second->map_iter = source_index_mapping.insert((*it).first, (*it).second);
969 void QSortFilterProxyModelPrivate::proxy_item_range(
970 const QVector<int> &source_to_proxy, const QVector<int> &source_items,
971 int &proxy_low, int &proxy_high) const
974 proxy_high = INT_MIN;
975 for (int i = 0; i < source_items.count(); ++i) {
976 int proxy_item = source_to_proxy.at(source_items.at(i));
977 Q_ASSERT(proxy_item != -1);
978 if (proxy_item < proxy_low)
979 proxy_low = proxy_item;
980 if (proxy_item > proxy_high)
981 proxy_high = proxy_item;
988 void QSortFilterProxyModelPrivate::build_source_to_proxy_mapping(
989 const QVector<int> &proxy_to_source, QVector<int> &source_to_proxy) const
991 source_to_proxy.fill(-1);
992 int proxy_count = proxy_to_source.size();
993 for (int i = 0; i < proxy_count; ++i)
994 source_to_proxy[proxy_to_source.at(i)] = i;
1000 Maps the persistent proxy indexes to source indexes and
1001 returns the list of source indexes.
1003 QModelIndexPairList QSortFilterProxyModelPrivate::store_persistent_indexes()
1005 Q_Q(QSortFilterProxyModel);
1006 QModelIndexPairList source_indexes;
1007 foreach (QPersistentModelIndexData *data, persistent.indexes) {
1008 QModelIndex proxy_index = data->index;
1009 QModelIndex source_index = q->mapToSource(proxy_index);
1010 source_indexes.append(qMakePair(proxy_index, QPersistentModelIndex(source_index)));
1012 return source_indexes;
1018 Maps \a source_indexes to proxy indexes and stores those
1019 as persistent indexes.
1021 void QSortFilterProxyModelPrivate::update_persistent_indexes(
1022 const QModelIndexPairList &source_indexes)
1024 Q_Q(QSortFilterProxyModel);
1025 QModelIndexList from, to;
1026 for (int i = 0; i < source_indexes.count(); ++i) {
1027 QModelIndex source_index = source_indexes.at(i).second;
1028 QModelIndex old_proxy_index = source_indexes.at(i).first;
1029 create_mapping(source_index.parent());
1030 QModelIndex proxy_index = q->mapFromSource(source_index);
1031 from << old_proxy_index;
1034 q->changePersistentIndexList(from, to);
1041 Updates the proxy model (adds/removes rows) based on the
1044 void QSortFilterProxyModelPrivate::filter_changed(const QModelIndex &source_parent)
1046 IndexMap::const_iterator it = source_index_mapping.constFind(source_parent);
1047 if (it == source_index_mapping.constEnd())
1049 Mapping *m = it.value();
1050 QSet<int> rows_removed = handle_filter_changed(m->proxy_rows, m->source_rows, source_parent, Qt::Vertical);
1051 QSet<int> columns_removed = handle_filter_changed(m->proxy_columns, m->source_columns, source_parent, Qt::Horizontal);
1053 // We need to iterate over a copy of m->mapped_children because otherwise it may be changed by other code, invalidating
1054 // the iterator it2.
1055 // The m->mapped_children vector can be appended to with indexes which are no longer filtered
1056 // out (in create_mapping) when this function recurses for child indexes.
1057 const QVector<QModelIndex> mappedChildren = m->mapped_children;
1058 QVector<int> indexesToRemove;
1059 for (int i = 0; i < mappedChildren.size(); ++i) {
1060 const QModelIndex source_child_index = mappedChildren.at(i);
1061 if (rows_removed.contains(source_child_index.row()) || columns_removed.contains(source_child_index.column())) {
1062 indexesToRemove.push_back(i);
1063 remove_from_mapping(source_child_index);
1065 filter_changed(source_child_index);
1068 QVector<int>::const_iterator removeIt = indexesToRemove.constEnd();
1069 const QVector<int>::const_iterator removeBegin = indexesToRemove.constBegin();
1071 // We can't just remove these items from mappedChildren while iterating above and then
1072 // do something like m->mapped_children = mappedChildren, because mapped_children might
1073 // be appended to in create_mapping, and we would lose those new items.
1074 // Because they are always appended in create_mapping, we can still remove them by
1076 while (removeIt != removeBegin) {
1078 m->mapped_children.remove(*removeIt);
1084 returns the removed items indexes
1086 QSet<int> QSortFilterProxyModelPrivate::handle_filter_changed(
1087 QVector<int> &source_to_proxy, QVector<int> &proxy_to_source,
1088 const QModelIndex &source_parent, Qt::Orientation orient)
1090 Q_Q(QSortFilterProxyModel);
1091 // Figure out which mapped items to remove
1092 QVector<int> source_items_remove;
1093 for (int i = 0; i < proxy_to_source.count(); ++i) {
1094 const int source_item = proxy_to_source.at(i);
1095 if ((orient == Qt::Vertical)
1096 ? !q->filterAcceptsRow(source_item, source_parent)
1097 : !q->filterAcceptsColumn(source_item, source_parent)) {
1098 // This source item does not satisfy the filter, so it must be removed
1099 source_items_remove.append(source_item);
1102 // Figure out which non-mapped items to insert
1103 QVector<int> source_items_insert;
1104 int source_count = source_to_proxy.size();
1105 for (int source_item = 0; source_item < source_count; ++source_item) {
1106 if (source_to_proxy.at(source_item) == -1) {
1107 if ((orient == Qt::Vertical)
1108 ? q->filterAcceptsRow(source_item, source_parent)
1109 : q->filterAcceptsColumn(source_item, source_parent)) {
1110 // This source item satisfies the filter, so it must be added
1111 source_items_insert.append(source_item);
1115 if (!source_items_remove.isEmpty() || !source_items_insert.isEmpty()) {
1116 // Do item removal and insertion
1117 remove_source_items(source_to_proxy, proxy_to_source,
1118 source_items_remove, source_parent, orient);
1119 if (orient == Qt::Vertical)
1120 sort_source_rows(source_items_insert, source_parent);
1121 insert_source_items(source_to_proxy, proxy_to_source,
1122 source_items_insert, source_parent, orient);
1124 return qVectorToSet(source_items_remove);
1127 void QSortFilterProxyModelPrivate::_q_sourceDataChanged(const QModelIndex &source_top_left,
1128 const QModelIndex &source_bottom_right)
1130 Q_Q(QSortFilterProxyModel);
1131 if (!source_top_left.isValid() || !source_bottom_right.isValid())
1133 QModelIndex source_parent = source_top_left.parent();
1134 IndexMap::const_iterator it = source_index_mapping.constFind(source_parent);
1135 if (it == source_index_mapping.constEnd()) {
1136 // Don't care, since we don't have mapping for this index
1139 Mapping *m = it.value();
1141 // Figure out how the source changes affect us
1142 QVector<int> source_rows_remove;
1143 QVector<int> source_rows_insert;
1144 QVector<int> source_rows_change;
1145 QVector<int> source_rows_resort;
1146 int end = qMin(source_bottom_right.row(), m->proxy_rows.count() - 1);
1147 for (int source_row = source_top_left.row(); source_row <= end; ++source_row) {
1148 if (dynamic_sortfilter) {
1149 if (m->proxy_rows.at(source_row) != -1) {
1150 if (!q->filterAcceptsRow(source_row, source_parent)) {
1151 // This source row no longer satisfies the filter, so it must be removed
1152 source_rows_remove.append(source_row);
1153 } else if (source_sort_column >= source_top_left.column() && source_sort_column <= source_bottom_right.column()) {
1154 // This source row has changed in a way that may affect sorted order
1155 source_rows_resort.append(source_row);
1157 // This row has simply changed, without affecting filtering nor sorting
1158 source_rows_change.append(source_row);
1161 if (!itemsBeingRemoved.contains(source_parent, source_row) && q->filterAcceptsRow(source_row, source_parent)) {
1162 // This source row now satisfies the filter, so it must be added
1163 source_rows_insert.append(source_row);
1167 if (m->proxy_rows.at(source_row) != -1)
1168 source_rows_change.append(source_row);
1172 if (!source_rows_remove.isEmpty()) {
1173 remove_source_items(m->proxy_rows, m->source_rows,
1174 source_rows_remove, source_parent, Qt::Vertical);
1175 QSet<int> source_rows_remove_set = qVectorToSet(source_rows_remove);
1176 QVector<QModelIndex>::iterator it = m->mapped_children.end();
1177 while (it != m->mapped_children.begin()) {
1179 const QModelIndex source_child_index = *it;
1180 if (source_rows_remove_set.contains(source_child_index.row())) {
1181 it = m->mapped_children.erase(it);
1182 remove_from_mapping(source_child_index);
1187 if (!source_rows_resort.isEmpty()) {
1188 // Re-sort the rows of this level
1189 QList<QPersistentModelIndex> parents;
1190 parents << q->mapFromSource(source_parent);
1191 emit q->layoutAboutToBeChanged(parents);
1192 QModelIndexPairList source_indexes = store_persistent_indexes();
1193 remove_source_items(m->proxy_rows, m->source_rows, source_rows_resort,
1194 source_parent, Qt::Vertical, false);
1195 sort_source_rows(source_rows_resort, source_parent);
1196 insert_source_items(m->proxy_rows, m->source_rows, source_rows_resort,
1197 source_parent, Qt::Vertical, false);
1198 update_persistent_indexes(source_indexes);
1199 emit q->layoutChanged(parents);
1200 // Make sure we also emit dataChanged for the rows
1201 source_rows_change += source_rows_resort;
1204 if (!source_rows_change.isEmpty()) {
1205 // Find the proxy row range
1206 int proxy_start_row;
1208 proxy_item_range(m->proxy_rows, source_rows_change,
1209 proxy_start_row, proxy_end_row);
1210 // ### Find the proxy column range also
1211 if (proxy_end_row >= 0) {
1212 // the row was accepted, but some columns might still be filtered out
1213 int source_left_column = source_top_left.column();
1214 while (source_left_column < source_bottom_right.column()
1215 && m->proxy_columns.at(source_left_column) == -1)
1216 ++source_left_column;
1217 const QModelIndex proxy_top_left = create_index(
1218 proxy_start_row, m->proxy_columns.at(source_left_column), it);
1219 int source_right_column = source_bottom_right.column();
1220 while (source_right_column > source_top_left.column()
1221 && m->proxy_columns.at(source_right_column) == -1)
1222 --source_right_column;
1223 const QModelIndex proxy_bottom_right = create_index(
1224 proxy_end_row, m->proxy_columns.at(source_right_column), it);
1225 emit q->dataChanged(proxy_top_left, proxy_bottom_right);
1229 if (!source_rows_insert.isEmpty()) {
1230 sort_source_rows(source_rows_insert, source_parent);
1231 insert_source_items(m->proxy_rows, m->source_rows,
1232 source_rows_insert, source_parent, Qt::Vertical);
1236 void QSortFilterProxyModelPrivate::_q_sourceHeaderDataChanged(Qt::Orientation orientation,
1239 Q_ASSERT(start <= end);
1241 Q_Q(QSortFilterProxyModel);
1242 Mapping *m = create_mapping(QModelIndex()).value();
1244 const QVector<int> &source_to_proxy = (orientation == Qt::Vertical) ? m->proxy_rows : m->proxy_columns;
1246 QVector<int> proxy_positions;
1247 proxy_positions.reserve(end - start + 1);
1249 Q_ASSERT(source_to_proxy.size() > end);
1250 QVector<int>::const_iterator it = source_to_proxy.constBegin() + start;
1251 const QVector<int>::const_iterator endIt = source_to_proxy.constBegin() + end + 1;
1252 for ( ; it != endIt; ++it) {
1254 proxy_positions.push_back(*it);
1258 qSort(proxy_positions);
1261 const int numItems = proxy_positions.size();
1262 while (last_index < numItems) {
1263 const int proxyStart = proxy_positions.at(last_index);
1264 int proxyEnd = proxyStart;
1266 for (int i = last_index; i < numItems; ++i) {
1267 if (proxy_positions.at(i) == proxyEnd + 1) {
1274 emit q->headerDataChanged(orientation, proxyStart, proxyEnd);
1278 void QSortFilterProxyModelPrivate::_q_sourceAboutToBeReset()
1280 Q_Q(QSortFilterProxyModel);
1281 q->beginResetModel();
1284 void QSortFilterProxyModelPrivate::_q_sourceReset()
1286 Q_Q(QSortFilterProxyModel);
1287 invalidatePersistentIndexes();
1289 // All internal structures are deleted in clear()
1291 update_source_sort_column();
1292 if (dynamic_sortfilter)
1296 void QSortFilterProxyModelPrivate::_q_sourceLayoutAboutToBeChanged(const QList<QPersistentModelIndex> &sourceParents)
1298 Q_Q(QSortFilterProxyModel);
1299 saved_persistent_indexes.clear();
1301 QList<QPersistentModelIndex> parents;
1302 foreach (const QPersistentModelIndex &parent, sourceParents) {
1303 if (!parent.isValid()) {
1304 parents << QModelIndex();
1307 const QModelIndex mappedParent = q->mapFromSource(parent);
1308 // Might be filtered out.
1309 if (mappedParent.isValid())
1310 parents << mappedParent;
1313 // All parents filtered out.
1314 if (!sourceParents.isEmpty() && parents.isEmpty())
1317 emit q->layoutAboutToBeChanged(parents);
1318 if (persistent.indexes.isEmpty())
1321 saved_persistent_indexes = store_persistent_indexes();
1324 void QSortFilterProxyModelPrivate::_q_sourceLayoutChanged(const QList<QPersistentModelIndex> &sourceParents)
1326 Q_Q(QSortFilterProxyModel);
1328 // Optimize: We only actually have to clear the mapping related to the contents of
1329 // sourceParents, not everything.
1330 qDeleteAll(source_index_mapping);
1331 source_index_mapping.clear();
1333 update_persistent_indexes(saved_persistent_indexes);
1334 saved_persistent_indexes.clear();
1336 if (dynamic_sortfilter && update_source_sort_column()) {
1337 //update_source_sort_column might have created wrong mapping so we have to clear it again
1338 qDeleteAll(source_index_mapping);
1339 source_index_mapping.clear();
1342 QList<QPersistentModelIndex> parents;
1343 foreach (const QPersistentModelIndex &parent, sourceParents) {
1344 if (!parent.isValid()) {
1345 parents << QModelIndex();
1348 const QModelIndex mappedParent = q->mapFromSource(parent);
1349 if (mappedParent.isValid())
1350 parents << mappedParent;
1353 if (!sourceParents.isEmpty() && parents.isEmpty())
1356 emit q->layoutChanged(parents);
1359 void QSortFilterProxyModelPrivate::_q_sourceRowsAboutToBeInserted(
1360 const QModelIndex &source_parent, int start, int end)
1364 //Force the creation of a mapping now, even if its empty.
1365 //We need it because the proxy can be acessed at the moment it emits rowsAboutToBeInserted in insert_source_items
1366 if (can_create_mapping(source_parent))
1367 create_mapping(source_parent);
1370 void QSortFilterProxyModelPrivate::_q_sourceRowsInserted(
1371 const QModelIndex &source_parent, int start, int end)
1373 source_items_inserted(source_parent, start, end, Qt::Vertical);
1374 if (update_source_sort_column() && dynamic_sortfilter) //previous call to update_source_sort_column may fail if the model has no column.
1375 sort(); // now it should succeed so we need to make sure to sort again
1378 void QSortFilterProxyModelPrivate::_q_sourceRowsAboutToBeRemoved(
1379 const QModelIndex &source_parent, int start, int end)
1381 itemsBeingRemoved = QRowsRemoval(source_parent, start, end);
1382 source_items_about_to_be_removed(source_parent, start, end,
1386 void QSortFilterProxyModelPrivate::_q_sourceRowsRemoved(
1387 const QModelIndex &source_parent, int start, int end)
1389 itemsBeingRemoved = QRowsRemoval();
1390 source_items_removed(source_parent, start, end, Qt::Vertical);
1393 void QSortFilterProxyModelPrivate::_q_sourceRowsAboutToBeMoved(
1394 const QModelIndex &sourceParent, int /* sourceStart */, int /* sourceEnd */, const QModelIndex &destParent, int /* dest */)
1396 Q_Q(QSortFilterProxyModel);
1397 // Because rows which are contiguous in the source model might not be contiguous
1398 // in the proxy due to sorting, the best thing we can do here is be specific about what
1399 // parents are having their children changed.
1400 // Optimize: Emit move signals if the proxy is not sorted. Will need to account for rows
1401 // being filtered out though.
1403 saved_persistent_indexes.clear();
1405 QList<QPersistentModelIndex> parents;
1406 parents << q->mapFromSource(sourceParent);
1407 if (sourceParent != destParent)
1408 parents << q->mapFromSource(destParent);
1409 emit q->layoutAboutToBeChanged(parents);
1410 if (persistent.indexes.isEmpty())
1412 saved_persistent_indexes = store_persistent_indexes();
1415 void QSortFilterProxyModelPrivate::_q_sourceRowsMoved(
1416 const QModelIndex &sourceParent, int /* sourceStart */, int /* sourceEnd */, const QModelIndex &destParent, int /* dest */)
1418 Q_Q(QSortFilterProxyModel);
1420 // Optimize: We only need to clear and update the persistent indexes which are children of
1421 // sourceParent or destParent
1422 qDeleteAll(source_index_mapping);
1423 source_index_mapping.clear();
1425 update_persistent_indexes(saved_persistent_indexes);
1426 saved_persistent_indexes.clear();
1428 if (dynamic_sortfilter && update_source_sort_column()) {
1429 //update_source_sort_column might have created wrong mapping so we have to clear it again
1430 qDeleteAll(source_index_mapping);
1431 source_index_mapping.clear();
1434 QList<QPersistentModelIndex> parents;
1435 parents << q->mapFromSource(sourceParent);
1436 if (sourceParent != destParent)
1437 parents << q->mapFromSource(destParent);
1438 emit q->layoutChanged(parents);
1441 void QSortFilterProxyModelPrivate::_q_sourceColumnsAboutToBeInserted(
1442 const QModelIndex &source_parent, int start, int end)
1446 //Force the creation of a mapping now, even if its empty.
1447 //We need it because the proxy can be acessed at the moment it emits columnsAboutToBeInserted in insert_source_items
1448 if (can_create_mapping(source_parent))
1449 create_mapping(source_parent);
1452 void QSortFilterProxyModelPrivate::_q_sourceColumnsInserted(
1453 const QModelIndex &source_parent, int start, int end)
1455 Q_Q(const QSortFilterProxyModel);
1456 source_items_inserted(source_parent, start, end, Qt::Horizontal);
1458 if (source_parent.isValid())
1459 return; //we sort according to the root column only
1460 if (source_sort_column == -1) {
1461 //we update the source_sort_column depending on the proxy_sort_column
1462 if (update_source_sort_column() && dynamic_sortfilter)
1465 if (start <= source_sort_column)
1466 source_sort_column += end - start + 1;
1468 proxy_sort_column = q->mapFromSource(model->index(0,source_sort_column, source_parent)).column();
1472 void QSortFilterProxyModelPrivate::_q_sourceColumnsAboutToBeRemoved(
1473 const QModelIndex &source_parent, int start, int end)
1475 source_items_about_to_be_removed(source_parent, start, end,
1479 void QSortFilterProxyModelPrivate::_q_sourceColumnsRemoved(
1480 const QModelIndex &source_parent, int start, int end)
1482 Q_Q(const QSortFilterProxyModel);
1483 source_items_removed(source_parent, start, end, Qt::Horizontal);
1485 if (source_parent.isValid())
1486 return; //we sort according to the root column only
1487 if (start <= source_sort_column) {
1488 if (end < source_sort_column)
1489 source_sort_column -= end - start + 1;
1491 source_sort_column = -1;
1494 proxy_sort_column = q->mapFromSource(model->index(0,source_sort_column, source_parent)).column();
1497 void QSortFilterProxyModelPrivate::_q_sourceColumnsAboutToBeMoved(
1498 const QModelIndex &sourceParent, int /* sourceStart */, int /* sourceEnd */, const QModelIndex &destParent, int /* dest */)
1500 Q_Q(QSortFilterProxyModel);
1502 saved_persistent_indexes.clear();
1504 QList<QPersistentModelIndex> parents;
1505 parents << q->mapFromSource(sourceParent);
1506 if (sourceParent != destParent)
1507 parents << q->mapFromSource(destParent);
1508 emit q->layoutAboutToBeChanged(parents);
1510 if (persistent.indexes.isEmpty())
1512 saved_persistent_indexes = store_persistent_indexes();
1515 void QSortFilterProxyModelPrivate::_q_sourceColumnsMoved(
1516 const QModelIndex &sourceParent, int /* sourceStart */, int /* sourceEnd */, const QModelIndex &destParent, int /* dest */)
1518 Q_Q(QSortFilterProxyModel);
1520 qDeleteAll(source_index_mapping);
1521 source_index_mapping.clear();
1523 update_persistent_indexes(saved_persistent_indexes);
1524 saved_persistent_indexes.clear();
1526 if (dynamic_sortfilter && update_source_sort_column()) {
1527 qDeleteAll(source_index_mapping);
1528 source_index_mapping.clear();
1531 QList<QPersistentModelIndex> parents;
1532 parents << q->mapFromSource(sourceParent);
1533 if (sourceParent != destParent)
1534 parents << q->mapFromSource(destParent);
1535 emit q->layoutChanged(parents);
1540 \class QSortFilterProxyModel
1542 \brief The QSortFilterProxyModel class provides support for sorting and
1543 filtering data passed between another model and a view.
1547 QSortFilterProxyModel can be used for sorting items, filtering out items,
1548 or both. The model transforms the structure of a source model by mapping
1549 the model indexes it supplies to new indexes, corresponding to different
1550 locations, for views to use. This approach allows a given source model to
1551 be restructured as far as views are concerned without requiring any
1552 transformations on the underlying data, and without duplicating the data in
1555 Let's assume that we want to sort and filter the items provided by a custom
1556 model. The code to set up the model and the view, \e without sorting and
1557 filtering, would look like this:
1559 \snippet qsortfilterproxymodel-details/main.cpp 1
1561 To add sorting and filtering support to \c MyItemModel, we need to create
1562 a QSortFilterProxyModel, call setSourceModel() with the \c MyItemModel as
1563 argument, and install the QSortFilterProxyModel on the view:
1565 \snippet qsortfilterproxymodel-details/main.cpp 0
1566 \snippet qsortfilterproxymodel-details/main.cpp 2
1568 At this point, neither sorting nor filtering is enabled; the original data
1569 is displayed in the view. Any changes made through the
1570 QSortFilterProxyModel are applied to the original model.
1572 The QSortFilterProxyModel acts as a wrapper for the original model. If you
1573 need to convert source \l{QModelIndex}es to sorted/filtered model indexes
1574 or vice versa, use mapToSource(), mapFromSource(), mapSelectionToSource(),
1575 and mapSelectionFromSource().
1577 \note By default, the model dynamically re-sorts and re-filters data
1578 whenever the original model changes. This behavior can be changed by
1579 setting the \l{QSortFilterProxyModel::dynamicSortFilter}{dynamicSortFilter}
1582 The \l{itemviews/basicsortfiltermodel}{Basic Sort/Filter Model} and
1583 \l{itemviews/customsortfiltermodel}{Custom Sort/Filter Model} examples
1584 illustrate how to use QSortFilterProxyModel to perform basic sorting and
1585 filtering and how to subclass it to implement custom behavior.
1589 QTableView and QTreeView have a
1590 \l{QTreeView::sortingEnabled}{sortingEnabled} property that controls
1591 whether the user can sort the view by clicking the view's horizontal
1592 header. For example:
1594 \snippet qsortfilterproxymodel-details/main.cpp 3
1596 When this feature is on (the default is off), clicking on a header section
1597 sorts the items according to that column. By clicking repeatedly, the user
1598 can alternate between ascending and descending order.
1600 \image qsortfilterproxymodel-sorting.png A sorted QTreeView
1602 Behind the scene, the view calls the sort() virtual function on the model
1603 to reorder the data in the model. To make your data sortable, you can
1604 either implement sort() in your model, or use a QSortFilterProxyModel to
1605 wrap your model -- QSortFilterProxyModel provides a generic sort()
1606 reimplementation that operates on the sortRole() (Qt::DisplayRole by
1607 default) of the items and that understands several data types, including
1608 \c int, QString, and QDateTime. For hierarchical models, sorting is applied
1609 recursively to all child items. String comparisons are case sensitive by
1610 default; this can be changed by setting the \l{QSortFilterProxyModel::}
1611 {sortCaseSensitivity} property.
1613 Custom sorting behavior is achieved by subclassing
1614 QSortFilterProxyModel and reimplementing lessThan(), which is
1615 used to compare items. For example:
1617 \snippet itemviews/customsortfiltermodel/mysortfilterproxymodel.cpp 5
1619 (This code snippet comes from the
1620 \l{itemviews/customsortfiltermodel}{Custom Sort/Filter Model}
1623 An alternative approach to sorting is to disable sorting on the view and to
1624 impose a certain order to the user. This is done by explicitly calling
1625 sort() with the desired column and order as arguments on the
1626 QSortFilterProxyModel (or on the original model if it implements sort()).
1629 \snippet qsortfilterproxymodel-details/main.cpp 4
1631 QSortFilterProxyModel can be sorted by column -1, in which case it returns
1632 to the sort order of the underlying source model.
1636 In addition to sorting, QSortFilterProxyModel can be used to hide items
1637 that do not match a certain filter. The filter is specified using a QRegExp
1638 object and is applied to the filterRole() (Qt::DisplayRole by default) of
1639 each item, for a given column. The QRegExp object can be used to match a
1640 regular expression, a wildcard pattern, or a fixed string. For example:
1642 \snippet qsortfilterproxymodel-details/main.cpp 5
1644 For hierarchical models, the filter is applied recursively to all children.
1645 If a parent item doesn't match the filter, none of its children will be
1648 A common use case is to let the user specify the filter regexp, wildcard
1649 pattern, or fixed string in a QLineEdit and to connect the
1650 \l{QLineEdit::textChanged()}{textChanged()} signal to setFilterRegExp(),
1651 setFilterWildcard(), or setFilterFixedString() to reapply the filter.
1653 Custom filtering behavior can be achieved by reimplementing the
1654 filterAcceptsRow() and filterAcceptsColumn() functions. For
1655 example (from the \l{itemviews/customsortfiltermodel}
1656 {Custom Sort/Filter Model} example), the following implementation ignores
1657 the \l{QSortFilterProxyModel::filterKeyColumn}{filterKeyColumn} property
1658 and performs filtering on columns 0, 1, and 2:
1660 \snippet itemviews/customsortfiltermodel/mysortfilterproxymodel.cpp 3
1662 (This code snippet comes from the
1663 \l{itemviews/customsortfiltermodel}{Custom Sort/Filter Model}
1666 If you are working with large amounts of filtering and have to invoke
1667 invalidateFilter() repeatedly, using reset() may be more efficient,
1668 depending on the implementation of your model. However, reset() returns the
1669 proxy model to its original state, losing selection information, and will
1670 cause the proxy model to be repopulated.
1672 \section1 Subclassing
1674 Since QAbstractProxyModel and its subclasses are derived from
1675 QAbstractItemModel, much of the same advice about subclassing normal models
1676 also applies to proxy models. In addition, it is worth noting that many of
1677 the default implementations of functions in this class are written so that
1678 they call the equivalent functions in the relevant source model. This
1679 simple proxying mechanism may need to be overridden for source models with
1680 more complex behavior; for example, if the source model provides a custom
1681 hasChildren() implementation, you should also provide one in the proxy
1684 \note Some general guidelines for subclassing models are available in the
1685 \l{Model Subclassing Reference}.
1687 \sa QAbstractProxyModel, QAbstractItemModel, {Model/View Programming},
1688 {Basic Sort/Filter Model Example}, {Custom Sort/Filter Model Example}, QIdentityProxyModel
1692 Constructs a sorting filter model with the given \a parent.
1695 QSortFilterProxyModel::QSortFilterProxyModel(QObject *parent)
1696 : QAbstractProxyModel(*new QSortFilterProxyModelPrivate, parent)
1698 Q_D(QSortFilterProxyModel);
1699 d->proxy_sort_column = d->source_sort_column = -1;
1700 d->sort_order = Qt::AscendingOrder;
1701 d->sort_casesensitivity = Qt::CaseSensitive;
1702 d->sort_role = Qt::DisplayRole;
1703 d->sort_localeaware = false;
1704 d->filter_column = 0;
1705 d->filter_role = Qt::DisplayRole;
1706 d->dynamic_sortfilter = true;
1707 connect(this, SIGNAL(modelReset()), this, SLOT(_q_clearMapping()));
1711 Destroys this sorting filter model.
1713 QSortFilterProxyModel::~QSortFilterProxyModel()
1715 Q_D(QSortFilterProxyModel);
1716 qDeleteAll(d->source_index_mapping);
1717 d->source_index_mapping.clear();
1723 void QSortFilterProxyModel::setSourceModel(QAbstractItemModel *sourceModel)
1725 Q_D(QSortFilterProxyModel);
1729 disconnect(d->model, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
1730 this, SLOT(_q_sourceDataChanged(QModelIndex,QModelIndex)));
1732 disconnect(d->model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)),
1733 this, SLOT(_q_sourceHeaderDataChanged(Qt::Orientation,int,int)));
1735 disconnect(d->model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
1736 this, SLOT(_q_sourceRowsAboutToBeInserted(QModelIndex,int,int)));
1738 disconnect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)),
1739 this, SLOT(_q_sourceRowsInserted(QModelIndex,int,int)));
1741 disconnect(d->model, SIGNAL(columnsAboutToBeInserted(QModelIndex,int,int)),
1742 this, SLOT(_q_sourceColumnsAboutToBeInserted(QModelIndex,int,int)));
1744 disconnect(d->model, SIGNAL(columnsInserted(QModelIndex,int,int)),
1745 this, SLOT(_q_sourceColumnsInserted(QModelIndex,int,int)));
1747 disconnect(d->model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
1748 this, SLOT(_q_sourceRowsAboutToBeRemoved(QModelIndex,int,int)));
1750 disconnect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
1751 this, SLOT(_q_sourceRowsRemoved(QModelIndex,int,int)));
1753 disconnect(d->model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
1754 this, SLOT(_q_sourceColumnsAboutToBeRemoved(QModelIndex,int,int)));
1756 disconnect(d->model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
1757 this, SLOT(_q_sourceColumnsRemoved(QModelIndex,int,int)));
1759 disconnect(d->model, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
1760 this, SLOT(_q_sourceRowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)));
1762 disconnect(d->model, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
1763 this, SLOT(_q_sourceRowsMoved(QModelIndex,int,int,QModelIndex,int)));
1765 disconnect(d->model, SIGNAL(columnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
1766 this, SLOT(_q_sourceColumnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)));
1768 disconnect(d->model, SIGNAL(columnsMoved(QModelIndex,int,int,QModelIndex,int)),
1769 this, SLOT(_q_sourceColumnsMoved(QModelIndex,int,int,QModelIndex,int)));
1771 disconnect(d->model, SIGNAL(layoutAboutToBeChanged(QList<QPersistentModelIndex>)),
1772 this, SLOT(_q_sourceLayoutAboutToBeChanged(QList<QPersistentModelIndex>)));
1774 disconnect(d->model, SIGNAL(layoutChanged(QList<QPersistentModelIndex>)),
1775 this, SLOT(_q_sourceLayoutChanged(QList<QPersistentModelIndex>)));
1777 disconnect(d->model, SIGNAL(modelAboutToBeReset()), this, SLOT(_q_sourceAboutToBeReset()));
1778 disconnect(d->model, SIGNAL(modelReset()), this, SLOT(_q_sourceReset()));
1780 QAbstractProxyModel::setSourceModel(sourceModel);
1782 connect(d->model, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
1783 this, SLOT(_q_sourceDataChanged(QModelIndex,QModelIndex)));
1785 connect(d->model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)),
1786 this, SLOT(_q_sourceHeaderDataChanged(Qt::Orientation,int,int)));
1788 connect(d->model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
1789 this, SLOT(_q_sourceRowsAboutToBeInserted(QModelIndex,int,int)));
1791 connect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)),
1792 this, SLOT(_q_sourceRowsInserted(QModelIndex,int,int)));
1794 connect(d->model, SIGNAL(columnsAboutToBeInserted(QModelIndex,int,int)),
1795 this, SLOT(_q_sourceColumnsAboutToBeInserted(QModelIndex,int,int)));
1797 connect(d->model, SIGNAL(columnsInserted(QModelIndex,int,int)),
1798 this, SLOT(_q_sourceColumnsInserted(QModelIndex,int,int)));
1800 connect(d->model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
1801 this, SLOT(_q_sourceRowsAboutToBeRemoved(QModelIndex,int,int)));
1803 connect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
1804 this, SLOT(_q_sourceRowsRemoved(QModelIndex,int,int)));
1806 connect(d->model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
1807 this, SLOT(_q_sourceColumnsAboutToBeRemoved(QModelIndex,int,int)));
1809 connect(d->model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
1810 this, SLOT(_q_sourceColumnsRemoved(QModelIndex,int,int)));
1812 connect(d->model, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
1813 this, SLOT(_q_sourceRowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)));
1815 connect(d->model, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
1816 this, SLOT(_q_sourceRowsMoved(QModelIndex,int,int,QModelIndex,int)));
1818 connect(d->model, SIGNAL(columnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
1819 this, SLOT(_q_sourceColumnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)));
1821 connect(d->model, SIGNAL(columnsMoved(QModelIndex,int,int,QModelIndex,int)),
1822 this, SLOT(_q_sourceColumnsMoved(QModelIndex,int,int,QModelIndex,int)));
1824 connect(d->model, SIGNAL(layoutAboutToBeChanged(QList<QPersistentModelIndex>)),
1825 this, SLOT(_q_sourceLayoutAboutToBeChanged(QList<QPersistentModelIndex>)));
1827 connect(d->model, SIGNAL(layoutChanged(QList<QPersistentModelIndex>)),
1828 this, SLOT(_q_sourceLayoutChanged(QList<QPersistentModelIndex>)));
1830 connect(d->model, SIGNAL(modelAboutToBeReset()), this, SLOT(_q_sourceAboutToBeReset()));
1831 connect(d->model, SIGNAL(modelReset()), this, SLOT(_q_sourceReset()));
1833 d->_q_clearMapping();
1835 if (d->update_source_sort_column() && d->dynamic_sortfilter)
1842 QModelIndex QSortFilterProxyModel::index(int row, int column, const QModelIndex &parent) const
1844 Q_D(const QSortFilterProxyModel);
1845 if (row < 0 || column < 0)
1846 return QModelIndex();
1848 QModelIndex source_parent = mapToSource(parent); // parent is already mapped at this point
1849 IndexMap::const_iterator it = d->create_mapping(source_parent); // but make sure that the children are mapped
1850 if (it.value()->source_rows.count() <= row || it.value()->source_columns.count() <= column)
1851 return QModelIndex();
1853 return d->create_index(row, column, it);
1859 QModelIndex QSortFilterProxyModel::parent(const QModelIndex &child) const
1861 Q_D(const QSortFilterProxyModel);
1862 if (!d->indexValid(child))
1863 return QModelIndex();
1864 IndexMap::const_iterator it = d->index_to_iterator(child);
1865 Q_ASSERT(it != d->source_index_mapping.constEnd());
1866 QModelIndex source_parent = it.key();
1867 QModelIndex proxy_parent = mapFromSource(source_parent);
1868 return proxy_parent;
1874 int QSortFilterProxyModel::rowCount(const QModelIndex &parent) const
1876 Q_D(const QSortFilterProxyModel);
1877 QModelIndex source_parent = mapToSource(parent);
1878 if (parent.isValid() && !source_parent.isValid())
1880 IndexMap::const_iterator it = d->create_mapping(source_parent);
1881 return it.value()->source_rows.count();
1887 int QSortFilterProxyModel::columnCount(const QModelIndex &parent) const
1889 Q_D(const QSortFilterProxyModel);
1890 QModelIndex source_parent = mapToSource(parent);
1891 if (parent.isValid() && !source_parent.isValid())
1893 IndexMap::const_iterator it = d->create_mapping(source_parent);
1894 return it.value()->source_columns.count();
1900 bool QSortFilterProxyModel::hasChildren(const QModelIndex &parent) const
1902 Q_D(const QSortFilterProxyModel);
1903 QModelIndex source_parent = mapToSource(parent);
1904 if (parent.isValid() && !source_parent.isValid())
1906 if (!d->model->hasChildren(source_parent))
1909 if (d->model->canFetchMore(source_parent))
1910 return true; //we assume we might have children that can be fetched
1912 QSortFilterProxyModelPrivate::Mapping *m = d->create_mapping(source_parent).value();
1913 return m->source_rows.count() != 0 && m->source_columns.count() != 0;
1919 QVariant QSortFilterProxyModel::data(const QModelIndex &index, int role) const
1921 Q_D(const QSortFilterProxyModel);
1922 QModelIndex source_index = mapToSource(index);
1923 if (index.isValid() && !source_index.isValid())
1925 return d->model->data(source_index, role);
1931 bool QSortFilterProxyModel::setData(const QModelIndex &index, const QVariant &value, int role)
1933 Q_D(QSortFilterProxyModel);
1934 QModelIndex source_index = mapToSource(index);
1935 if (index.isValid() && !source_index.isValid())
1937 return d->model->setData(source_index, value, role);
1943 QVariant QSortFilterProxyModel::headerData(int section, Qt::Orientation orientation, int role) const
1945 Q_D(const QSortFilterProxyModel);
1946 IndexMap::const_iterator it = d->create_mapping(QModelIndex());
1947 if (it.value()->source_rows.count() * it.value()->source_columns.count() > 0)
1948 return QAbstractProxyModel::headerData(section, orientation, role);
1950 if (orientation == Qt::Vertical) {
1951 if (section < 0 || section >= it.value()->source_rows.count())
1953 source_section = it.value()->source_rows.at(section);
1955 if (section < 0 || section >= it.value()->source_columns.count())
1957 source_section = it.value()->source_columns.at(section);
1959 return d->model->headerData(source_section, orientation, role);
1965 bool QSortFilterProxyModel::setHeaderData(int section, Qt::Orientation orientation,
1966 const QVariant &value, int role)
1968 Q_D(QSortFilterProxyModel);
1969 IndexMap::const_iterator it = d->create_mapping(QModelIndex());
1970 if (it.value()->source_rows.count() * it.value()->source_columns.count() > 0)
1971 return QAbstractProxyModel::setHeaderData(section, orientation, value, role);
1973 if (orientation == Qt::Vertical) {
1974 if (section < 0 || section >= it.value()->source_rows.count())
1976 source_section = it.value()->source_rows.at(section);
1978 if (section < 0 || section >= it.value()->source_columns.count())
1980 source_section = it.value()->source_columns.at(section);
1982 return d->model->setHeaderData(source_section, orientation, value, role);
1988 QMimeData *QSortFilterProxyModel::mimeData(const QModelIndexList &indexes) const
1990 Q_D(const QSortFilterProxyModel);
1991 QModelIndexList source_indexes;
1992 for (int i = 0; i < indexes.count(); ++i)
1993 source_indexes << mapToSource(indexes.at(i));
1994 return d->model->mimeData(source_indexes);
2000 QStringList QSortFilterProxyModel::mimeTypes() const
2002 Q_D(const QSortFilterProxyModel);
2003 return d->model->mimeTypes();
2009 Qt::DropActions QSortFilterProxyModel::supportedDropActions() const
2011 Q_D(const QSortFilterProxyModel);
2012 return d->model->supportedDropActions();
2018 bool QSortFilterProxyModel::dropMimeData(const QMimeData *data, Qt::DropAction action,
2019 int row, int column, const QModelIndex &parent)
2021 Q_D(QSortFilterProxyModel);
2022 if ((row == -1) && (column == -1))
2023 return d->model->dropMimeData(data, action, -1, -1, mapToSource(parent));
2024 int source_destination_row = -1;
2025 int source_destination_column = -1;
2026 QModelIndex source_parent;
2027 if (row == rowCount(parent)) {
2028 source_parent = mapToSource(parent);
2029 source_destination_row = d->model->rowCount(source_parent);
2031 QModelIndex proxy_index = index(row, column, parent);
2032 QModelIndex source_index = mapToSource(proxy_index);
2033 source_destination_row = source_index.row();
2034 source_destination_column = source_index.column();
2035 source_parent = source_index.parent();
2037 return d->model->dropMimeData(data, action, source_destination_row,
2038 source_destination_column, source_parent);
2044 bool QSortFilterProxyModel::insertRows(int row, int count, const QModelIndex &parent)
2046 Q_D(QSortFilterProxyModel);
2047 if (row < 0 || count <= 0)
2049 QModelIndex source_parent = mapToSource(parent);
2050 if (parent.isValid() && !source_parent.isValid())
2052 QSortFilterProxyModelPrivate::Mapping *m = d->create_mapping(source_parent).value();
2053 if (row > m->source_rows.count())
2055 int source_row = (row >= m->source_rows.count()
2056 ? m->source_rows.count()
2057 : m->source_rows.at(row));
2058 return d->model->insertRows(source_row, count, source_parent);
2064 bool QSortFilterProxyModel::insertColumns(int column, int count, const QModelIndex &parent)
2066 Q_D(QSortFilterProxyModel);
2067 if (column < 0|| count <= 0)
2069 QModelIndex source_parent = mapToSource(parent);
2070 if (parent.isValid() && !source_parent.isValid())
2072 QSortFilterProxyModelPrivate::Mapping *m = d->create_mapping(source_parent).value();
2073 if (column > m->source_columns.count())
2075 int source_column = (column >= m->source_columns.count()
2076 ? m->source_columns.count()
2077 : m->source_columns.at(column));
2078 return d->model->insertColumns(source_column, count, source_parent);
2084 bool QSortFilterProxyModel::removeRows(int row, int count, const QModelIndex &parent)
2086 Q_D(QSortFilterProxyModel);
2087 if (row < 0 || count <= 0)
2089 QModelIndex source_parent = mapToSource(parent);
2090 if (parent.isValid() && !source_parent.isValid())
2092 QSortFilterProxyModelPrivate::Mapping *m = d->create_mapping(source_parent).value();
2093 if (row + count > m->source_rows.count())
2096 || ((d->source_sort_column < 0) && (m->proxy_rows.count() == m->source_rows.count()))) {
2097 int source_row = m->source_rows.at(row);
2098 return d->model->removeRows(source_row, count, source_parent);
2100 // remove corresponding source intervals
2101 // ### if this proves to be slow, we can switch to single-row removal
2103 for (int i = row; i < row + count; ++i)
2104 rows.append(m->source_rows.at(i));
2105 qSort(rows.begin(), rows.end());
2107 int pos = rows.count() - 1;
2110 const int source_end = rows.at(pos--);
2111 int source_start = source_end;
2112 while ((pos >= 0) && (rows.at(pos) == (source_start - 1))) {
2116 ok = ok && d->model->removeRows(source_start, source_end - source_start + 1,
2125 bool QSortFilterProxyModel::removeColumns(int column, int count, const QModelIndex &parent)
2127 Q_D(QSortFilterProxyModel);
2128 if (column < 0 || count <= 0)
2130 QModelIndex source_parent = mapToSource(parent);
2131 if (parent.isValid() && !source_parent.isValid())
2133 QSortFilterProxyModelPrivate::Mapping *m = d->create_mapping(source_parent).value();
2134 if (column + count > m->source_columns.count())
2136 if ((count == 1) || (m->proxy_columns.count() == m->source_columns.count())) {
2137 int source_column = m->source_columns.at(column);
2138 return d->model->removeColumns(source_column, count, source_parent);
2140 // remove corresponding source intervals
2141 QVector<int> columns;
2142 for (int i = column; i < column + count; ++i)
2143 columns.append(m->source_columns.at(i));
2145 int pos = columns.count() - 1;
2148 const int source_end = columns.at(pos--);
2149 int source_start = source_end;
2150 while ((pos >= 0) && (columns.at(pos) == (source_start - 1))) {
2154 ok = ok && d->model->removeColumns(source_start, source_end - source_start + 1,
2163 void QSortFilterProxyModel::fetchMore(const QModelIndex &parent)
2165 Q_D(QSortFilterProxyModel);
2166 QModelIndex source_parent;
2167 if (d->indexValid(parent))
2168 source_parent = mapToSource(parent);
2169 d->model->fetchMore(source_parent);
2175 bool QSortFilterProxyModel::canFetchMore(const QModelIndex &parent) const
2177 Q_D(const QSortFilterProxyModel);
2178 QModelIndex source_parent;
2179 if (d->indexValid(parent))
2180 source_parent = mapToSource(parent);
2181 return d->model->canFetchMore(source_parent);
2187 Qt::ItemFlags QSortFilterProxyModel::flags(const QModelIndex &index) const
2189 Q_D(const QSortFilterProxyModel);
2190 QModelIndex source_index;
2191 if (d->indexValid(index))
2192 source_index = mapToSource(index);
2193 return d->model->flags(source_index);
2199 QModelIndex QSortFilterProxyModel::buddy(const QModelIndex &index) const
2201 Q_D(const QSortFilterProxyModel);
2202 if (!d->indexValid(index))
2203 return QModelIndex();
2204 QModelIndex source_index = mapToSource(index);
2205 QModelIndex source_buddy = d->model->buddy(source_index);
2206 if (source_index == source_buddy)
2208 return mapFromSource(source_buddy);
2214 QModelIndexList QSortFilterProxyModel::match(const QModelIndex &start, int role,
2215 const QVariant &value, int hits,
2216 Qt::MatchFlags flags) const
2218 return QAbstractProxyModel::match(start, role, value, hits, flags);
2224 QSize QSortFilterProxyModel::span(const QModelIndex &index) const
2226 Q_D(const QSortFilterProxyModel);
2227 QModelIndex source_index = mapToSource(index);
2228 if (index.isValid() && !source_index.isValid())
2230 return d->model->span(source_index);
2236 void QSortFilterProxyModel::sort(int column, Qt::SortOrder order)
2238 Q_D(QSortFilterProxyModel);
2239 if (d->dynamic_sortfilter && d->proxy_sort_column == column && d->sort_order == order)
2241 d->sort_order = order;
2242 d->proxy_sort_column = column;
2243 d->update_source_sort_column();
2249 \brief the column currently used for sorting
2251 This returns the most recently used sort column.
2253 int QSortFilterProxyModel::sortColumn() const
2255 Q_D(const QSortFilterProxyModel);
2256 return d->proxy_sort_column;
2261 \brief the order currently used for sorting
2263 This returns the most recently used sort order.
2265 Qt::SortOrder QSortFilterProxyModel::sortOrder() const
2267 Q_D(const QSortFilterProxyModel);
2268 return d->sort_order;
2272 \property QSortFilterProxyModel::filterRegExp
2273 \brief the QRegExp used to filter the contents of the source model
2275 Setting this property overwrites the current
2276 \l{QSortFilterProxyModel::filterCaseSensitivity}{filterCaseSensitivity}.
2277 By default, the QRegExp is an empty string matching all contents.
2279 If no QRegExp or an empty string is set, everything in the source model
2282 \sa filterCaseSensitivity, setFilterWildcard(), setFilterFixedString()
2284 QRegExp QSortFilterProxyModel::filterRegExp() const
2286 Q_D(const QSortFilterProxyModel);
2287 return d->filter_regexp;
2290 void QSortFilterProxyModel::setFilterRegExp(const QRegExp ®Exp)
2292 Q_D(QSortFilterProxyModel);
2293 d->filter_regexp = regExp;
2294 d->filter_changed();
2298 \property QSortFilterProxyModel::filterKeyColumn
2299 \brief the column where the key used to filter the contents of the
2300 source model is read from.
2302 The default value is 0. If the value is -1, the keys will be read
2305 int QSortFilterProxyModel::filterKeyColumn() const
2307 Q_D(const QSortFilterProxyModel);
2308 return d->filter_column;
2311 void QSortFilterProxyModel::setFilterKeyColumn(int column)
2313 Q_D(QSortFilterProxyModel);
2314 d->filter_column = column;
2315 d->filter_changed();
2319 \property QSortFilterProxyModel::filterCaseSensitivity
2321 \brief the case sensitivity of the QRegExp pattern used to filter the
2322 contents of the source model
2324 By default, the filter is case sensitive.
2326 \sa filterRegExp, sortCaseSensitivity
2328 Qt::CaseSensitivity QSortFilterProxyModel::filterCaseSensitivity() const
2330 Q_D(const QSortFilterProxyModel);
2331 return d->filter_regexp.caseSensitivity();
2334 void QSortFilterProxyModel::setFilterCaseSensitivity(Qt::CaseSensitivity cs)
2336 Q_D(QSortFilterProxyModel);
2337 if (cs == d->filter_regexp.caseSensitivity())
2339 d->filter_regexp.setCaseSensitivity(cs);
2340 d->filter_changed();
2345 \property QSortFilterProxyModel::sortCaseSensitivity
2346 \brief the case sensitivity setting used for comparing strings when sorting
2348 By default, sorting is case sensitive.
2350 \sa filterCaseSensitivity, lessThan()
2352 Qt::CaseSensitivity QSortFilterProxyModel::sortCaseSensitivity() const
2354 Q_D(const QSortFilterProxyModel);
2355 return d->sort_casesensitivity;
2358 void QSortFilterProxyModel::setSortCaseSensitivity(Qt::CaseSensitivity cs)
2360 Q_D(QSortFilterProxyModel);
2361 if (d->sort_casesensitivity == cs)
2364 d->sort_casesensitivity = cs;
2370 \property QSortFilterProxyModel::isSortLocaleAware
2371 \brief the local aware setting used for comparing strings when sorting
2373 By default, sorting is not local aware.
2375 \sa sortCaseSensitivity, lessThan()
2377 bool QSortFilterProxyModel::isSortLocaleAware() const
2379 Q_D(const QSortFilterProxyModel);
2380 return d->sort_localeaware;
2383 void QSortFilterProxyModel::setSortLocaleAware(bool on)
2385 Q_D(QSortFilterProxyModel);
2386 if (d->sort_localeaware == on)
2389 d->sort_localeaware = on;
2396 Sets the regular expression used to filter the contents
2397 of the source model to \a pattern.
2399 \sa setFilterCaseSensitivity(), setFilterWildcard(), setFilterFixedString(), filterRegExp()
2401 void QSortFilterProxyModel::setFilterRegExp(const QString &pattern)
2403 Q_D(QSortFilterProxyModel);
2404 d->filter_regexp.setPatternSyntax(QRegExp::RegExp);
2405 d->filter_regexp.setPattern(pattern);
2406 d->filter_changed();
2410 Sets the wildcard expression used to filter the contents
2411 of the source model to the given \a pattern.
2413 \sa setFilterCaseSensitivity(), setFilterRegExp(), setFilterFixedString(), filterRegExp()
2415 void QSortFilterProxyModel::setFilterWildcard(const QString &pattern)
2417 Q_D(QSortFilterProxyModel);
2418 d->filter_regexp.setPatternSyntax(QRegExp::Wildcard);
2419 d->filter_regexp.setPattern(pattern);
2420 d->filter_changed();
2424 Sets the fixed string used to filter the contents
2425 of the source model to the given \a pattern.
2427 \sa setFilterCaseSensitivity(), setFilterRegExp(), setFilterWildcard(), filterRegExp()
2429 void QSortFilterProxyModel::setFilterFixedString(const QString &pattern)
2431 Q_D(QSortFilterProxyModel);
2432 d->filter_regexp.setPatternSyntax(QRegExp::FixedString);
2433 d->filter_regexp.setPattern(pattern);
2434 d->filter_changed();
2439 \property QSortFilterProxyModel::dynamicSortFilter
2440 \brief whether the proxy model is dynamically sorted and filtered
2441 whenever the contents of the source model change
2443 Note that you should not update the source model through the proxy
2444 model when dynamicSortFilter is true. For instance, if you set the
2445 proxy model on a QComboBox, then using functions that update the
2446 model, e.g., \l{QComboBox::}{addItem()}, will not work as
2447 expected. An alternative is to set dynamicSortFilter to false and
2448 call \l{QSortFilterProxyModel::}{sort()} after adding items to the
2451 The default value is true.
2453 bool QSortFilterProxyModel::dynamicSortFilter() const
2455 Q_D(const QSortFilterProxyModel);
2456 return d->dynamic_sortfilter;
2459 void QSortFilterProxyModel::setDynamicSortFilter(bool enable)
2461 Q_D(QSortFilterProxyModel);
2462 d->dynamic_sortfilter = enable;
2469 \property QSortFilterProxyModel::sortRole
2470 \brief the item role that is used to query the source model's data when sorting items
2472 The default value is Qt::DisplayRole.
2476 int QSortFilterProxyModel::sortRole() const
2478 Q_D(const QSortFilterProxyModel);
2479 return d->sort_role;
2482 void QSortFilterProxyModel::setSortRole(int role)
2484 Q_D(QSortFilterProxyModel);
2485 if (d->sort_role == role)
2487 d->sort_role = role;
2493 \property QSortFilterProxyModel::filterRole
2494 \brief the item role that is used to query the source model's data when filtering items
2496 The default value is Qt::DisplayRole.
2498 \sa filterAcceptsRow()
2500 int QSortFilterProxyModel::filterRole() const
2502 Q_D(const QSortFilterProxyModel);
2503 return d->filter_role;
2506 void QSortFilterProxyModel::setFilterRole(int role)
2508 Q_D(QSortFilterProxyModel);
2509 if (d->filter_role == role)
2511 d->filter_role = role;
2512 d->filter_changed();
2518 This function is obsolete. Use invalidate() instead.
2520 void QSortFilterProxyModel::clear()
2522 Q_D(QSortFilterProxyModel);
2523 emit layoutAboutToBeChanged();
2524 d->_q_clearMapping();
2525 emit layoutChanged();
2531 Invalidates the current sorting and filtering.
2533 \sa invalidateFilter()
2535 void QSortFilterProxyModel::invalidate()
2537 Q_D(QSortFilterProxyModel);
2538 emit layoutAboutToBeChanged();
2539 d->_q_clearMapping();
2540 emit layoutChanged();
2546 This function is obsolete. Use invalidateFilter() instead.
2548 void QSortFilterProxyModel::filterChanged()
2550 Q_D(QSortFilterProxyModel);
2551 d->filter_changed();
2557 Invalidates the current filtering.
2559 This function should be called if you are implementing custom filtering
2560 (e.g. filterAcceptsRow()), and your filter parameters have changed.
2564 void QSortFilterProxyModel::invalidateFilter()
2566 Q_D(QSortFilterProxyModel);
2567 d->filter_changed();
2571 Returns true if the value of the item referred to by the given
2572 index \a left is less than the value of the item referred to by
2573 the given index \a right, otherwise returns false.
2575 This function is used as the < operator when sorting, and handles
2576 the following QVariant types:
2581 \li QVariant::LongLong
2582 \li QVariant::ULongLong
2583 \li QVariant::Double
2587 \li QVariant::DateTime
2588 \li QVariant::String
2591 Any other type will be converted to a QString using
2592 QVariant::toString().
2594 Comparison of \l{QString}s is case sensitive by default; this can
2595 be changed using the \l {QSortFilterProxyModel::sortCaseSensitivity}
2596 {sortCaseSensitivity} property.
2598 By default, the Qt::DisplayRole associated with the
2599 \l{QModelIndex}es is used for comparisons. This can be changed by
2600 setting the \l {QSortFilterProxyModel::sortRole} {sortRole} property.
2602 \note The indices passed in correspond to the source model.
2604 \sa sortRole, sortCaseSensitivity, dynamicSortFilter
2606 bool QSortFilterProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
2608 Q_D(const QSortFilterProxyModel);
2609 QVariant l = (left.model() ? left.model()->data(left, d->sort_role) : QVariant());
2610 QVariant r = (right.model() ? right.model()->data(right, d->sort_role) : QVariant());
2611 switch (l.userType()) {
2612 case QVariant::Invalid:
2613 return (r.type() != QVariant::Invalid);
2615 return l.toInt() < r.toInt();
2616 case QVariant::UInt:
2617 return l.toUInt() < r.toUInt();
2618 case QVariant::LongLong:
2619 return l.toLongLong() < r.toLongLong();
2620 case QVariant::ULongLong:
2621 return l.toULongLong() < r.toULongLong();
2622 case QMetaType::Float:
2623 return l.toFloat() < r.toFloat();
2624 case QVariant::Double:
2625 return l.toDouble() < r.toDouble();
2626 case QVariant::Char:
2627 return l.toChar() < r.toChar();
2628 case QVariant::Date:
2629 return l.toDate() < r.toDate();
2630 case QVariant::Time:
2631 return l.toTime() < r.toTime();
2632 case QVariant::DateTime:
2633 return l.toDateTime() < r.toDateTime();
2634 case QVariant::String:
2636 if (d->sort_localeaware)
2637 return l.toString().localeAwareCompare(r.toString()) < 0;
2639 return l.toString().compare(r.toString(), d->sort_casesensitivity) < 0;
2645 Returns true if the item in the row indicated by the given \a source_row
2646 and \a source_parent should be included in the model; otherwise returns
2649 The default implementation returns true if the value held by the relevant item
2650 matches the filter string, wildcard string or regular expression.
2652 \note By default, the Qt::DisplayRole is used to determine if the row
2653 should be accepted or not. This can be changed by setting the
2654 \l{QSortFilterProxyModel::filterRole}{filterRole} property.
2656 \sa filterAcceptsColumn(), setFilterFixedString(), setFilterRegExp(), setFilterWildcard()
2658 bool QSortFilterProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
2660 Q_D(const QSortFilterProxyModel);
2661 if (d->filter_regexp.isEmpty())
2663 if (d->filter_column == -1) {
2664 int column_count = d->model->columnCount(source_parent);
2665 for (int column = 0; column < column_count; ++column) {
2666 QModelIndex source_index = d->model->index(source_row, column, source_parent);
2667 QString key = d->model->data(source_index, d->filter_role).toString();
2668 if (key.contains(d->filter_regexp))
2673 QModelIndex source_index = d->model->index(source_row, d->filter_column, source_parent);
2674 if (!source_index.isValid()) // the column may not exist
2676 QString key = d->model->data(source_index, d->filter_role).toString();
2677 return key.contains(d->filter_regexp);
2681 Returns true if the item in the column indicated by the given \a source_column
2682 and \a source_parent should be included in the model; otherwise returns false.
2684 The default implementation returns true if the value held by the relevant item
2685 matches the filter string, wildcard string or regular expression.
2687 \note By default, the Qt::DisplayRole is used to determine if the row
2688 should be accepted or not. This can be changed by setting the \l
2689 filterRole property.
2691 \sa filterAcceptsRow(), setFilterFixedString(), setFilterRegExp(), setFilterWildcard()
2693 bool QSortFilterProxyModel::filterAcceptsColumn(int source_column, const QModelIndex &source_parent) const
2695 Q_UNUSED(source_column);
2696 Q_UNUSED(source_parent);
2701 Returns the source model index corresponding to the given \a
2702 proxyIndex from the sorting filter model.
2706 QModelIndex QSortFilterProxyModel::mapToSource(const QModelIndex &proxyIndex) const
2708 Q_D(const QSortFilterProxyModel);
2709 return d->proxy_to_source(proxyIndex);
2713 Returns the model index in the QSortFilterProxyModel given the \a
2714 sourceIndex from the source model.
2718 QModelIndex QSortFilterProxyModel::mapFromSource(const QModelIndex &sourceIndex) const
2720 Q_D(const QSortFilterProxyModel);
2721 return d->source_to_proxy(sourceIndex);
2727 QItemSelection QSortFilterProxyModel::mapSelectionToSource(const QItemSelection &proxySelection) const
2729 return QAbstractProxyModel::mapSelectionToSource(proxySelection);
2735 QItemSelection QSortFilterProxyModel::mapSelectionFromSource(const QItemSelection &sourceSelection) const
2737 return QAbstractProxyModel::mapSelectionFromSource(sourceSelection);
2741 \fn QObject *QSortFilterProxyModel::parent() const
2747 #include "moc_qsortfilterproxymodel.cpp"
2749 #endif // QT_NO_SORTFILTERPROXYMODEL