1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtGui 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 http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://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 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file. Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qsortfilterproxymodel.h"
43
44 #ifndef QT_NO_SORTFILTERPROXYMODEL
45
46 #include "qitemselectionmodel.h"
47 #include <qsize.h>
48 #include <qdebug.h>
49 #include <qdatetime.h>
50 #include <qpair.h>
51 #include <qstringlist.h>
52 #include <private/qabstractitemmodel_p.h>
53 #include <private/qabstractproxymodel_p.h>
54
55 QT_BEGIN_NAMESPACE
56
57 typedef QList<QPair<QModelIndex, QPersistentModelIndex> > QModelIndexPairList;
58
qVectorToSet(const QVector<int> & vector)59 static inline QSet<int> qVectorToSet(const QVector<int> &vector)
60 {
61 QSet<int> set;
62 set.reserve(vector.size());
63 for(int i=0; i < vector.size(); ++i)
64 set << vector.at(i);
65 return set;
66 }
67
68 class QSortFilterProxyModelLessThan
69 {
70 public:
QSortFilterProxyModelLessThan(int column,const QModelIndex & parent,const QAbstractItemModel * source,const QSortFilterProxyModel * proxy)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) {}
75
operator ()(int r1,int r2) const76 inline bool operator()(int r1, int r2) const
77 {
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);
81 }
82
83 private:
84 int sort_column;
85 QModelIndex source_parent;
86 const QAbstractItemModel *source_model;
87 const QSortFilterProxyModel *proxy_model;
88 };
89
90 class QSortFilterProxyModelGreaterThan
91 {
92 public:
QSortFilterProxyModelGreaterThan(int column,const QModelIndex & parent,const QAbstractItemModel * source,const QSortFilterProxyModel * proxy)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) {}
98
operator ()(int r1,int r2) const99 inline bool operator()(int r1, int r2) const
100 {
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);
104 }
105
106 private:
107 int sort_column;
108 QModelIndex source_parent;
109 const QAbstractItemModel *source_model;
110 const QSortFilterProxyModel *proxy_model;
111 };
112
113
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
117 struct QRowsRemoval
118 {
QRowsRemovalQRowsRemoval119 QRowsRemoval(const QModelIndex &parent_source, int start, int end) : parent_source(parent_source), start(start), end(end)
120 {
121 }
122
QRowsRemovalQRowsRemoval123 QRowsRemoval() : start(-1), end(-1)
124 {
125 }
126
containsQRowsRemoval127 bool contains(QModelIndex parent, int row)
128 {
129 do {
130 if (parent == parent_source)
131 return row >= start && row <= end;
132 row = parent.row();
133 parent = parent.parent();
134 } while (row >= 0);
135 return false;
136 }
137 private:
138 QModelIndex parent_source;
139 int start;
140 int end;
141 };
142
143 class QSortFilterProxyModelPrivate : public QAbstractProxyModelPrivate
144 {
145 Q_DECLARE_PUBLIC(QSortFilterProxyModel)
146
147 public:
148 struct Mapping {
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;
155 };
156
157 mutable QHash<QModelIndex, Mapping*> source_index_mapping;
158
159 int source_sort_column;
160 int proxy_sort_column;
161 Qt::SortOrder sort_order;
162 Qt::CaseSensitivity sort_casesensitivity;
163 int sort_role;
164 bool sort_localeaware;
165
166 int filter_column;
167 QRegExp filter_regexp;
168 int filter_role;
169
170 bool dynamic_sortfilter;
171 QRowsRemoval itemsBeingRemoved;
172
173 QModelIndexPairList saved_persistent_indexes;
174
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;
180
181 void remove_from_mapping(const QModelIndex &source_parent);
182
index_to_iterator(const QModelIndex & proxy_index) const183 inline QHash<QModelIndex, Mapping *>::const_iterator index_to_iterator(
184 const QModelIndex &proxy_index) const
185 {
186 Q_ASSERT(proxy_index.isValid());
187 Q_ASSERT(proxy_index.model() == q_func());
188 const void *p = proxy_index.internalPointer();
189 Q_ASSERT(p);
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());
194 return it;
195 }
196
create_index(int row,int column,QHash<QModelIndex,Mapping * >::const_iterator it) const197 inline QModelIndex create_index(int row, int column,
198 QHash<QModelIndex, Mapping*>::const_iterator it) const
199 {
200 return q_func()->createIndex(row, column, *it);
201 }
202
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);
206
207 void _q_sourceAboutToBeReset();
208 void _q_sourceReset();
209
210 void _q_sourceLayoutAboutToBeChanged();
211 void _q_sourceLayoutChanged();
212
213 void _q_sourceRowsAboutToBeInserted(const QModelIndex &source_parent,
214 int start, int end);
215 void _q_sourceRowsInserted(const QModelIndex &source_parent,
216 int start, int end);
217 void _q_sourceRowsAboutToBeRemoved(const QModelIndex &source_parent,
218 int start, int end);
219 void _q_sourceRowsRemoved(const QModelIndex &source_parent,
220 int start, int end);
221 void _q_sourceColumnsAboutToBeInserted(const QModelIndex &source_parent,
222 int start, int end);
223 void _q_sourceColumnsInserted(const QModelIndex &source_parent,
224 int start, int end);
225 void _q_sourceColumnsAboutToBeRemoved(const QModelIndex &source_parent,
226 int start, int end);
227 void _q_sourceColumnsRemoved(const QModelIndex &source_parent,
228 int start, int end);
229
230 void _q_clearMapping();
231
232 void sort();
233 bool update_source_sort_column();
234 void sort_source_rows(QVector<int> &source_rows,
235 const QModelIndex &source_parent) const;
236 QVector<QPair<int, QVector<int > > > proxy_intervals_for_source_items_to_add(
237 const QVector<int> &proxy_to_source, const QVector<int> &source_items,
238 const QModelIndex &source_parent, Qt::Orientation orient) const;
239 QVector<QPair<int, int > > proxy_intervals_for_source_items(
240 const QVector<int> &source_to_proxy, const QVector<int> &source_items) const;
241 void insert_source_items(
242 QVector<int> &source_to_proxy, QVector<int> &proxy_to_source,
243 const QVector<int> &source_items, const QModelIndex &source_parent,
244 Qt::Orientation orient, bool emit_signal = true);
245 void remove_source_items(
246 QVector<int> &source_to_proxy, QVector<int> &proxy_to_source,
247 const QVector<int> &source_items, const QModelIndex &source_parent,
248 Qt::Orientation orient, bool emit_signal = true);
249 void remove_proxy_interval(
250 QVector<int> &source_to_proxy, QVector<int> &proxy_to_source,
251 int proxy_start, int proxy_end, const QModelIndex &proxy_parent,
252 Qt::Orientation orient, bool emit_signal = true);
253 void build_source_to_proxy_mapping(
254 const QVector<int> &proxy_to_source, QVector<int> &source_to_proxy) const;
255 void source_items_inserted(const QModelIndex &source_parent,
256 int start, int end, Qt::Orientation orient);
257 void source_items_about_to_be_removed(const QModelIndex &source_parent,
258 int start, int end, Qt::Orientation orient);
259 void source_items_removed(const QModelIndex &source_parent,
260 int start, int end, Qt::Orientation orient);
261 void proxy_item_range(
262 const QVector<int> &source_to_proxy, const QVector<int> &source_items,
263 int &proxy_low, int &proxy_high) const;
264
265 QModelIndexPairList store_persistent_indexes();
266 void update_persistent_indexes(const QModelIndexPairList &source_indexes);
267
268 void filter_changed(const QModelIndex &source_parent = QModelIndex());
269 QSet<int> handle_filter_changed(
270 QVector<int> &source_to_proxy, QVector<int> &proxy_to_source,
271 const QModelIndex &source_parent, Qt::Orientation orient);
272
273 void updateChildrenMapping(const QModelIndex &source_parent, Mapping *parent_mapping,
274 Qt::Orientation orient, int start, int end, int delta_item_count, bool remove);
275
276 virtual void _q_sourceModelDestroyed();
277 };
278
279 typedef QHash<QModelIndex, QSortFilterProxyModelPrivate::Mapping *> IndexMap;
280
_q_sourceModelDestroyed()281 void QSortFilterProxyModelPrivate::_q_sourceModelDestroyed()
282 {
283 QAbstractProxyModelPrivate::_q_sourceModelDestroyed();
284 qDeleteAll(source_index_mapping);
285 source_index_mapping.clear();
286 }
287
remove_from_mapping(const QModelIndex & source_parent)288 void QSortFilterProxyModelPrivate::remove_from_mapping(const QModelIndex &source_parent)
289 {
290 if (Mapping *m = source_index_mapping.take(source_parent)) {
291 for (int i = 0; i < m->mapped_children.size(); ++i)
292 remove_from_mapping(m->mapped_children.at(i));
293 delete m;
294 }
295 }
296
_q_clearMapping()297 void QSortFilterProxyModelPrivate::_q_clearMapping()
298 {
299 // store the persistent indexes
300 QModelIndexPairList source_indexes = store_persistent_indexes();
301
302 qDeleteAll(source_index_mapping);
303 source_index_mapping.clear();
304 if (dynamic_sortfilter && update_source_sort_column()) {
305 //update_source_sort_column might have created wrong mapping so we have to clear it again
306 qDeleteAll(source_index_mapping);
307 source_index_mapping.clear();
308 }
309
310 // update the persistent indexes
311 update_persistent_indexes(source_indexes);
312 }
313
create_mapping(const QModelIndex & source_parent) const314 IndexMap::const_iterator QSortFilterProxyModelPrivate::create_mapping(
315 const QModelIndex &source_parent) const
316 {
317 Q_Q(const QSortFilterProxyModel);
318
319 IndexMap::const_iterator it = source_index_mapping.constFind(source_parent);
320 if (it != source_index_mapping.constEnd()) // was mapped already
321 return it;
322
323 Mapping *m = new Mapping;
324
325 int source_rows = model->rowCount(source_parent);
326 m->source_rows.reserve(source_rows);
327 for (int i = 0; i < source_rows; ++i) {
328 if (q->filterAcceptsRow(i, source_parent))
329 m->source_rows.append(i);
330 }
331 int source_cols = model->columnCount(source_parent);
332 m->source_columns.reserve(source_cols);
333 for (int i = 0; i < source_cols; ++i) {
334 if (q->filterAcceptsColumn(i, source_parent))
335 m->source_columns.append(i);
336 }
337
338 sort_source_rows(m->source_rows, source_parent);
339 m->proxy_rows.resize(source_rows);
340 build_source_to_proxy_mapping(m->source_rows, m->proxy_rows);
341 m->proxy_columns.resize(source_cols);
342 build_source_to_proxy_mapping(m->source_columns, m->proxy_columns);
343
344 it = IndexMap::const_iterator(source_index_mapping.insert(source_parent, m));
345 m->map_iter = it;
346
347 if (source_parent.isValid()) {
348 QModelIndex source_grand_parent = source_parent.parent();
349 IndexMap::const_iterator it2 = create_mapping(source_grand_parent);
350 Q_ASSERT(it2 != source_index_mapping.constEnd());
351 it2.value()->mapped_children.append(source_parent);
352 }
353
354 Q_ASSERT(it != source_index_mapping.constEnd());
355 Q_ASSERT(it.value());
356
357 return it;
358 }
359
proxy_to_source(const QModelIndex & proxy_index) const360 QModelIndex QSortFilterProxyModelPrivate::proxy_to_source(const QModelIndex &proxy_index) const
361 {
362 if (!proxy_index.isValid())
363 return QModelIndex(); // for now; we may want to be able to set a root index later
364 if (proxy_index.model() != q_func()) {
365 qWarning() << "QSortFilterProxyModel: index from wrong model passed to mapToSource";
366 Q_ASSERT(!"QSortFilterProxyModel: index from wrong model passed to mapToSource");
367 return QModelIndex();
368 }
369 IndexMap::const_iterator it = index_to_iterator(proxy_index);
370 Mapping *m = it.value();
371 if ((proxy_index.row() >= m->source_rows.size()) || (proxy_index.column() >= m->source_columns.size()))
372 return QModelIndex();
373 int source_row = m->source_rows.at(proxy_index.row());
374 int source_col = m->source_columns.at(proxy_index.column());
375 return model->index(source_row, source_col, it.key());
376 }
377
source_to_proxy(const QModelIndex & source_index) const378 QModelIndex QSortFilterProxyModelPrivate::source_to_proxy(const QModelIndex &source_index) const
379 {
380 if (!source_index.isValid())
381 return QModelIndex(); // for now; we may want to be able to set a root index later
382 if (source_index.model() != model) {
383 qWarning() << "QSortFilterProxyModel: index from wrong model passed to mapFromSource";
384 Q_ASSERT(!"QSortFilterProxyModel: index from wrong model passed to mapFromSource");
385 return QModelIndex();
386 }
387 QModelIndex source_parent = source_index.parent();
388 IndexMap::const_iterator it = create_mapping(source_parent);
389 Mapping *m = it.value();
390 if ((source_index.row() >= m->proxy_rows.size()) || (source_index.column() >= m->proxy_columns.size()))
391 return QModelIndex();
392 int proxy_row = m->proxy_rows.at(source_index.row());
393 int proxy_column = m->proxy_columns.at(source_index.column());
394 if (proxy_row == -1 || proxy_column == -1)
395 return QModelIndex();
396 return create_index(proxy_row, proxy_column, it);
397 }
398
can_create_mapping(const QModelIndex & source_parent) const399 bool QSortFilterProxyModelPrivate::can_create_mapping(const QModelIndex &source_parent) const
400 {
401 if (source_parent.isValid()) {
402 QModelIndex source_grand_parent = source_parent.parent();
403 IndexMap::const_iterator it = source_index_mapping.constFind(source_grand_parent);
404 if (it == source_index_mapping.constEnd()) {
405 // Don't care, since we don't have mapping for the grand parent
406 return false;
407 }
408 Mapping *gm = it.value();
409 if (gm->proxy_rows.at(source_parent.row()) == -1 ||
410 gm->proxy_columns.at(source_parent.column()) == -1) {
411 // Don't care, since parent is filtered
412 return false;
413 }
414 }
415 return true;
416 }
417
418 /*!
419 \internal
420
421 Sorts the existing mappings.
422 */
sort()423 void QSortFilterProxyModelPrivate::sort()
424 {
425 Q_Q(QSortFilterProxyModel);
426 emit q->layoutAboutToBeChanged();
427 QModelIndexPairList source_indexes = store_persistent_indexes();
428 IndexMap::const_iterator it = source_index_mapping.constBegin();
429 for (; it != source_index_mapping.constEnd(); ++it) {
430 QModelIndex source_parent = it.key();
431 Mapping *m = it.value();
432 sort_source_rows(m->source_rows, source_parent);
433 build_source_to_proxy_mapping(m->source_rows, m->proxy_rows);
434 }
435 update_persistent_indexes(source_indexes);
436 emit q->layoutChanged();
437 }
438
439 /*!
440 \internal
441
442 update the source_sort_column according to the proxy_sort_column
443 return true if the column was changed
444 */
update_source_sort_column()445 bool QSortFilterProxyModelPrivate::update_source_sort_column()
446 {
447 Q_Q(QSortFilterProxyModel);
448 QModelIndex proxy_index = q->index(0, proxy_sort_column, QModelIndex());
449 int old_source_sort_colum = source_sort_column;
450 source_sort_column = q->mapToSource(proxy_index).column();
451 return old_source_sort_colum != source_sort_column;
452 }
453
454
455 /*!
456 \internal
457
458 Sorts the given \a source_rows according to current sort column and order.
459 */
sort_source_rows(QVector<int> & source_rows,const QModelIndex & source_parent) const460 void QSortFilterProxyModelPrivate::sort_source_rows(
461 QVector<int> &source_rows, const QModelIndex &source_parent) const
462 {
463 Q_Q(const QSortFilterProxyModel);
464 if (source_sort_column >= 0) {
465 if (sort_order == Qt::AscendingOrder) {
466 QSortFilterProxyModelLessThan lt(source_sort_column, source_parent, model, q);
467 qStableSort(source_rows.begin(), source_rows.end(), lt);
468 } else {
469 QSortFilterProxyModelGreaterThan gt(source_sort_column, source_parent, model, q);
470 qStableSort(source_rows.begin(), source_rows.end(), gt);
471 }
472 } else { // restore the source model order
473 qStableSort(source_rows.begin(), source_rows.end());
474 }
475 }
476
477 /*!
478 \internal
479
480 Given source-to-proxy mapping \a source_to_proxy and the set of
481 source items \a source_items (which are part of that mapping),
482 determines the corresponding proxy item intervals that should
483 be removed from the proxy model.
484
485 The result is a vector of pairs, where each pair represents a
486 (start, end) tuple, sorted in ascending order.
487 */
proxy_intervals_for_source_items(const QVector<int> & source_to_proxy,const QVector<int> & source_items) const488 QVector<QPair<int, int > > QSortFilterProxyModelPrivate::proxy_intervals_for_source_items(
489 const QVector<int> &source_to_proxy, const QVector<int> &source_items) const
490 {
491 QVector<QPair<int, int> > proxy_intervals;
492 if (source_items.isEmpty())
493 return proxy_intervals;
494
495 int source_items_index = 0;
496 while (source_items_index < source_items.size()) {
497 int first_proxy_item = source_to_proxy.at(source_items.at(source_items_index));
498 Q_ASSERT(first_proxy_item != -1);
499 int last_proxy_item = first_proxy_item;
500 ++source_items_index;
501 // Find end of interval
502 while ((source_items_index < source_items.size())
503 && (source_to_proxy.at(source_items.at(source_items_index)) == last_proxy_item + 1)) {
504 ++last_proxy_item;
505 ++source_items_index;
506 }
507 // Add interval to result
508 proxy_intervals.append(QPair<int, int>(first_proxy_item, last_proxy_item));
509 }
510 qStableSort(proxy_intervals.begin(), proxy_intervals.end());
511 return proxy_intervals;
512 }
513
514 /*!
515 \internal
516
517 Given source-to-proxy mapping \a src_to_proxy and proxy-to-source mapping
518 \a proxy_to_source, removes \a source_items from this proxy model.
519 The corresponding proxy items are removed in intervals, so that the proper
520 rows/columnsRemoved(start, end) signals will be generated.
521 */
remove_source_items(QVector<int> & source_to_proxy,QVector<int> & proxy_to_source,const QVector<int> & source_items,const QModelIndex & source_parent,Qt::Orientation orient,bool emit_signal)522 void QSortFilterProxyModelPrivate::remove_source_items(
523 QVector<int> &source_to_proxy, QVector<int> &proxy_to_source,
524 const QVector<int> &source_items, const QModelIndex &source_parent,
525 Qt::Orientation orient, bool emit_signal)
526 {
527 Q_Q(QSortFilterProxyModel);
528 QModelIndex proxy_parent = q->mapFromSource(source_parent);
529 if (!proxy_parent.isValid() && source_parent.isValid())
530 return; // nothing to do (already removed)
531
532 QVector<QPair<int, int> > proxy_intervals;
533 proxy_intervals = proxy_intervals_for_source_items(source_to_proxy, source_items);
534
535 for (int i = proxy_intervals.size()-1; i >= 0; --i) {
536 QPair<int, int> interval = proxy_intervals.at(i);
537 int proxy_start = interval.first;
538 int proxy_end = interval.second;
539 remove_proxy_interval(source_to_proxy, proxy_to_source, proxy_start, proxy_end,
540 proxy_parent, orient, emit_signal);
541 }
542 }
543
544 /*!
545 \internal
546
547 Given source-to-proxy mapping \a source_to_proxy and proxy-to-source mapping
548 \a proxy_to_source, removes items from \a proxy_start to \a proxy_end
549 (inclusive) from this proxy model.
550 */
remove_proxy_interval(QVector<int> & source_to_proxy,QVector<int> & proxy_to_source,int proxy_start,int proxy_end,const QModelIndex & proxy_parent,Qt::Orientation orient,bool emit_signal)551 void QSortFilterProxyModelPrivate::remove_proxy_interval(
552 QVector<int> &source_to_proxy, QVector<int> &proxy_to_source, int proxy_start, int proxy_end,
553 const QModelIndex &proxy_parent, Qt::Orientation orient, bool emit_signal)
554 {
555 Q_Q(QSortFilterProxyModel);
556 if (emit_signal) {
557 if (orient == Qt::Vertical)
558 q->beginRemoveRows(proxy_parent, proxy_start, proxy_end);
559 else
560 q->beginRemoveColumns(proxy_parent, proxy_start, proxy_end);
561 }
562
563 // Remove items from proxy-to-source mapping
564 proxy_to_source.remove(proxy_start, proxy_end - proxy_start + 1);
565
566 build_source_to_proxy_mapping(proxy_to_source, source_to_proxy);
567
568 if (emit_signal) {
569 if (orient == Qt::Vertical)
570 q->endRemoveRows();
571 else
572 q->endRemoveColumns();
573 }
574 }
575
576 /*!
577 \internal
578
579 Given proxy-to-source mapping \a proxy_to_source and a set of
580 unmapped source items \a source_items, determines the proxy item
581 intervals at which the subsets of source items should be inserted
582 (but does not actually add them to the mapping).
583
584 The result is a vector of pairs, each pair representing a tuple (start,
585 items), where items is a vector containing the (sorted) source items that
586 should be inserted at that proxy model location.
587 */
proxy_intervals_for_source_items_to_add(const QVector<int> & proxy_to_source,const QVector<int> & source_items,const QModelIndex & source_parent,Qt::Orientation orient) const588 QVector<QPair<int, QVector<int > > > QSortFilterProxyModelPrivate::proxy_intervals_for_source_items_to_add(
589 const QVector<int> &proxy_to_source, const QVector<int> &source_items,
590 const QModelIndex &source_parent, Qt::Orientation orient) const
591 {
592 Q_Q(const QSortFilterProxyModel);
593 QVector<QPair<int, QVector<int> > > proxy_intervals;
594 if (source_items.isEmpty())
595 return proxy_intervals;
596
597 int proxy_low = 0;
598 int proxy_item = 0;
599 int source_items_index = 0;
600 QVector<int> source_items_in_interval;
601 bool compare = (orient == Qt::Vertical && source_sort_column >= 0 && dynamic_sortfilter);
602 while (source_items_index < source_items.size()) {
603 source_items_in_interval.clear();
604 int first_new_source_item = source_items.at(source_items_index);
605 source_items_in_interval.append(first_new_source_item);
606 ++source_items_index;
607
608 // Find proxy item at which insertion should be started
609 int proxy_high = proxy_to_source.size() - 1;
610 QModelIndex i1 = compare ? model->index(first_new_source_item, source_sort_column, source_parent) : QModelIndex();
611 while (proxy_low <= proxy_high) {
612 proxy_item = (proxy_low + proxy_high) / 2;
613 if (compare) {
614 QModelIndex i2 = model->index(proxy_to_source.at(proxy_item), source_sort_column, source_parent);
615 if ((sort_order == Qt::AscendingOrder) ? q->lessThan(i1, i2) : q->lessThan(i2, i1))
616 proxy_high = proxy_item - 1;
617 else
618 proxy_low = proxy_item + 1;
619 } else {
620 if (first_new_source_item < proxy_to_source.at(proxy_item))
621 proxy_high = proxy_item - 1;
622 else
623 proxy_low = proxy_item + 1;
624 }
625 }
626 proxy_item = proxy_low;
627
628 // Find the sequence of new source items that should be inserted here
629 if (proxy_item >= proxy_to_source.size()) {
630 for ( ; source_items_index < source_items.size(); ++source_items_index)
631 source_items_in_interval.append(source_items.at(source_items_index));
632 } else {
633 i1 = compare ? model->index(proxy_to_source.at(proxy_item), source_sort_column, source_parent) : QModelIndex();
634 for ( ; source_items_index < source_items.size(); ++source_items_index) {
635 int new_source_item = source_items.at(source_items_index);
636 if (compare) {
637 QModelIndex i2 = model->index(new_source_item, source_sort_column, source_parent);
638 if ((sort_order == Qt::AscendingOrder) ? q->lessThan(i1, i2) : q->lessThan(i2, i1))
639 break;
640 } else {
641 if (proxy_to_source.at(proxy_item) < new_source_item)
642 break;
643 }
644 source_items_in_interval.append(new_source_item);
645 }
646 }
647
648 // Add interval to result
649 proxy_intervals.append(QPair<int, QVector<int> >(proxy_item, source_items_in_interval));
650 }
651 return proxy_intervals;
652 }
653
654 /*!
655 \internal
656
657 Given source-to-proxy mapping \a source_to_proxy and proxy-to-source mapping
658 \a proxy_to_source, inserts the given \a source_items into this proxy model.
659 The source items are inserted in intervals (based on some sorted order), so
660 that the proper rows/columnsInserted(start, end) signals will be generated.
661 */
insert_source_items(QVector<int> & source_to_proxy,QVector<int> & proxy_to_source,const QVector<int> & source_items,const QModelIndex & source_parent,Qt::Orientation orient,bool emit_signal)662 void QSortFilterProxyModelPrivate::insert_source_items(
663 QVector<int> &source_to_proxy, QVector<int> &proxy_to_source,
664 const QVector<int> &source_items, const QModelIndex &source_parent,
665 Qt::Orientation orient, bool emit_signal)
666 {
667 Q_Q(QSortFilterProxyModel);
668 QModelIndex proxy_parent = q->mapFromSource(source_parent);
669 if (!proxy_parent.isValid() && source_parent.isValid())
670 return; // nothing to do (source_parent is not mapped)
671
672 QVector<QPair<int, QVector<int> > > proxy_intervals;
673 proxy_intervals = proxy_intervals_for_source_items_to_add(
674 proxy_to_source, source_items, source_parent, orient);
675
676 for (int i = proxy_intervals.size()-1; i >= 0; --i) {
677 QPair<int, QVector<int> > interval = proxy_intervals.at(i);
678 int proxy_start = interval.first;
679 QVector<int> source_items = interval.second;
680 int proxy_end = proxy_start + source_items.size() - 1;
681
682 if (emit_signal) {
683 if (orient == Qt::Vertical)
684 q->beginInsertRows(proxy_parent, proxy_start, proxy_end);
685 else
686 q->beginInsertColumns(proxy_parent, proxy_start, proxy_end);
687 }
688
689 for (int i = 0; i < source_items.size(); ++i)
690 proxy_to_source.insert(proxy_start + i, source_items.at(i));
691
692 build_source_to_proxy_mapping(proxy_to_source, source_to_proxy);
693
694 if (emit_signal) {
695 if (orient == Qt::Vertical)
696 q->endInsertRows();
697 else
698 q->endInsertColumns();
699 }
700 }
701 }
702
703 /*!
704 \internal
705
706 Handles source model items insertion (columnsInserted(), rowsInserted()).
707 Determines
708 1) which of the inserted items to also insert into proxy model (filtering),
709 2) where to insert the items into the proxy model (sorting),
710 then inserts those items.
711 The items are inserted into the proxy model in intervals (based on
712 sorted order), so that the proper rows/columnsInserted(start, end)
713 signals will be generated.
714 */
source_items_inserted(const QModelIndex & source_parent,int start,int end,Qt::Orientation orient)715 void QSortFilterProxyModelPrivate::source_items_inserted(
716 const QModelIndex &source_parent, int start, int end, Qt::Orientation orient)
717 {
718 Q_Q(QSortFilterProxyModel);
719 if ((start < 0) || (end < 0))
720 return;
721 IndexMap::const_iterator it = source_index_mapping.constFind(source_parent);
722 if (it == source_index_mapping.constEnd()) {
723 if (!can_create_mapping(source_parent))
724 return;
725 it = create_mapping(source_parent);
726 Mapping *m = it.value();
727 QModelIndex proxy_parent = q->mapFromSource(source_parent);
728 if (m->source_rows.count() > 0) {
729 q->beginInsertRows(proxy_parent, 0, m->source_rows.count() - 1);
730 q->endInsertRows();
731 }
732 if (m->source_columns.count() > 0) {
733 q->beginInsertColumns(proxy_parent, 0, m->source_columns.count() - 1);
734 q->endInsertColumns();
735 }
736 return;
737 }
738
739 Mapping *m = it.value();
740 QVector<int> &source_to_proxy = (orient == Qt::Vertical) ? m->proxy_rows : m->proxy_columns;
741 QVector<int> &proxy_to_source = (orient == Qt::Vertical) ? m->source_rows : m->source_columns;
742
743 int delta_item_count = end - start + 1;
744 int old_item_count = source_to_proxy.size();
745
746 updateChildrenMapping(source_parent, m, orient, start, end, delta_item_count, false);
747
748 // Expand source-to-proxy mapping to account for new items
749 if (start < 0 || start > source_to_proxy.size()) {
750 qWarning("QSortFilterProxyModel: invalid inserted rows reported by source model");
751 remove_from_mapping(source_parent);
752 return;
753 }
754 source_to_proxy.insert(start, delta_item_count, -1);
755
756 if (start < old_item_count) {
757 // Adjust existing "stale" indexes in proxy-to-source mapping
758 int proxy_count = proxy_to_source.size();
759 for (int proxy_item = 0; proxy_item < proxy_count; ++proxy_item) {
760 int source_item = proxy_to_source.at(proxy_item);
761 if (source_item >= start)
762 proxy_to_source.replace(proxy_item, source_item + delta_item_count);
763 }
764 build_source_to_proxy_mapping(proxy_to_source, source_to_proxy);
765 }
766
767 // Figure out which items to add to mapping based on filter
768 QVector<int> source_items;
769 for (int i = start; i <= end; ++i) {
770 if ((orient == Qt::Vertical)
771 ? q->filterAcceptsRow(i, source_parent)
772 : q->filterAcceptsColumn(i, source_parent)) {
773 source_items.append(i);
774 }
775 }
776
777 if (model->rowCount(source_parent) == delta_item_count) {
778 // Items were inserted where there were none before.
779 // If it was new rows make sure to create mappings for columns so that a
780 // valid mapping can be retrieved later and vice-versa.
781
782 QVector<int> &orthogonal_proxy_to_source = (orient == Qt::Horizontal) ? m->source_rows : m->source_columns;
783 QVector<int> &orthogonal_source_to_proxy = (orient == Qt::Horizontal) ? m->proxy_rows : m->proxy_columns;
784
785 if (orthogonal_source_to_proxy.isEmpty()) {
786 const int ortho_end = (orient == Qt::Horizontal) ? model->rowCount(source_parent) : model->columnCount(source_parent);
787
788 orthogonal_source_to_proxy.resize(ortho_end);
789
790 for (int ortho_item = 0; ortho_item < ortho_end; ++ortho_item) {
791 if ((orient == Qt::Horizontal) ? q->filterAcceptsRow(ortho_item, source_parent)
792 : q->filterAcceptsColumn(ortho_item, source_parent)) {
793 orthogonal_proxy_to_source.append(ortho_item);
794 }
795 }
796 if (orient == Qt::Horizontal) {
797 // We're reacting to columnsInserted, but we've just inserted new rows. Sort them.
798 sort_source_rows(orthogonal_proxy_to_source, source_parent);
799 }
800 build_source_to_proxy_mapping(orthogonal_proxy_to_source, orthogonal_source_to_proxy);
801 }
802 }
803
804 // Sort and insert the items
805 if (orient == Qt::Vertical) // Only sort rows
806 sort_source_rows(source_items, source_parent);
807 insert_source_items(source_to_proxy, proxy_to_source, source_items, source_parent, orient);
808 }
809
810 /*!
811 \internal
812
813 Handles source model items removal
814 (columnsAboutToBeRemoved(), rowsAboutToBeRemoved()).
815 */
source_items_about_to_be_removed(const QModelIndex & source_parent,int start,int end,Qt::Orientation orient)816 void QSortFilterProxyModelPrivate::source_items_about_to_be_removed(
817 const QModelIndex &source_parent, int start, int end, Qt::Orientation orient)
818 {
819 if ((start < 0) || (end < 0))
820 return;
821 IndexMap::const_iterator it = source_index_mapping.constFind(source_parent);
822 if (it == source_index_mapping.constEnd()) {
823 // Don't care, since we don't have mapping for this index
824 return;
825 }
826
827 Mapping *m = it.value();
828 QVector<int> &source_to_proxy = (orient == Qt::Vertical) ? m->proxy_rows : m->proxy_columns;
829 QVector<int> &proxy_to_source = (orient == Qt::Vertical) ? m->source_rows : m->source_columns;
830
831 // figure out which items to remove
832 QVector<int> source_items_to_remove;
833 int proxy_count = proxy_to_source.size();
834 for (int proxy_item = 0; proxy_item < proxy_count; ++proxy_item) {
835 int source_item = proxy_to_source.at(proxy_item);
836 if ((source_item >= start) && (source_item <= end))
837 source_items_to_remove.append(source_item);
838 }
839
840 remove_source_items(source_to_proxy, proxy_to_source, source_items_to_remove,
841 source_parent, orient);
842 }
843
844 /*!
845 \internal
846
847 Handles source model items removal (columnsRemoved(), rowsRemoved()).
848 */
source_items_removed(const QModelIndex & source_parent,int start,int end,Qt::Orientation orient)849 void QSortFilterProxyModelPrivate::source_items_removed(
850 const QModelIndex &source_parent, int start, int end, Qt::Orientation orient)
851 {
852 if ((start < 0) || (end < 0))
853 return;
854 IndexMap::const_iterator it = source_index_mapping.constFind(source_parent);
855 if (it == source_index_mapping.constEnd()) {
856 // Don't care, since we don't have mapping for this index
857 return;
858 }
859
860 Mapping *m = it.value();
861 QVector<int> &source_to_proxy = (orient == Qt::Vertical) ? m->proxy_rows : m->proxy_columns;
862 QVector<int> &proxy_to_source = (orient == Qt::Vertical) ? m->source_rows : m->source_columns;
863
864 if (end >= source_to_proxy.size())
865 end = source_to_proxy.size() - 1;
866
867 // Shrink the source-to-proxy mapping to reflect the new item count
868 int delta_item_count = end - start + 1;
869 source_to_proxy.remove(start, delta_item_count);
870
871 int proxy_count = proxy_to_source.size();
872 if (proxy_count > source_to_proxy.size()) {
873 // mapping is in an inconsistent state -- redo the whole mapping
874 qWarning("QSortFilterProxyModel: inconsistent changes reported by source model");
875 remove_from_mapping(source_parent);
876 Q_Q(QSortFilterProxyModel);
877 q->reset();
878 return;
879 }
880
881 // Adjust "stale" indexes in proxy-to-source mapping
882 for (int proxy_item = 0; proxy_item < proxy_count; ++proxy_item) {
883 int source_item = proxy_to_source.at(proxy_item);
884 if (source_item >= start) {
885 Q_ASSERT(source_item - delta_item_count >= 0);
886 proxy_to_source.replace(proxy_item, source_item - delta_item_count);
887 }
888 }
889 build_source_to_proxy_mapping(proxy_to_source, source_to_proxy);
890
891 updateChildrenMapping(source_parent, m, orient, start, end, delta_item_count, true);
892
893 }
894
895
896 /*!
897 \internal
898 updates the mapping of the children when inserting or removing items
899 */
updateChildrenMapping(const QModelIndex & source_parent,Mapping * parent_mapping,Qt::Orientation orient,int start,int end,int delta_item_count,bool remove)900 void QSortFilterProxyModelPrivate::updateChildrenMapping(const QModelIndex &source_parent, Mapping *parent_mapping,
901 Qt::Orientation orient, int start, int end, int delta_item_count, bool remove)
902 {
903 // see if any mapped children should be (re)moved
904 QVector<QPair<QModelIndex, Mapping*> > moved_source_index_mappings;
905 QVector<QModelIndex>::iterator it2 = parent_mapping->mapped_children.begin();
906 for ( ; it2 != parent_mapping->mapped_children.end();) {
907 const QModelIndex source_child_index = *it2;
908 const int pos = (orient == Qt::Vertical)
909 ? source_child_index.row()
910 : source_child_index.column();
911 if (pos < start) {
912 // not affected
913 ++it2;
914 } else if (remove && pos <= end) {
915 // in the removed interval
916 it2 = parent_mapping->mapped_children.erase(it2);
917 remove_from_mapping(source_child_index);
918 } else {
919 // below the removed items -- recompute the index
920 QModelIndex new_index;
921 const int newpos = remove ? pos - delta_item_count : pos + delta_item_count;
922 if (orient == Qt::Vertical) {
923 new_index = model->index(newpos,
924 source_child_index.column(),
925 source_parent);
926 } else {
927 new_index = model->index(source_child_index.row(),
928 newpos,
929 source_parent);
930 }
931 *it2 = new_index;
932 ++it2;
933
934 // update mapping
935 Mapping *cm = source_index_mapping.take(source_child_index);
936 Q_ASSERT(cm);
937 // we do not reinsert right away, because the new index might be identical with another, old index
938 moved_source_index_mappings.append(QPair<QModelIndex, Mapping*>(new_index, cm));
939 }
940 }
941
942 // reinsert moved, mapped indexes
943 QVector<QPair<QModelIndex, Mapping*> >::iterator it = moved_source_index_mappings.begin();
944 for (; it != moved_source_index_mappings.end(); ++it) {
945 #ifdef QT_STRICT_ITERATORS
946 source_index_mapping.insert((*it).first, (*it).second);
947 (*it).second->map_iter = source_index_mapping.constFind((*it).first);
948 #else
949 (*it).second->map_iter = source_index_mapping.insert((*it).first, (*it).second);
950 #endif
951 }
952 }
953
954 /*!
955 \internal
956 */
proxy_item_range(const QVector<int> & source_to_proxy,const QVector<int> & source_items,int & proxy_low,int & proxy_high) const957 void QSortFilterProxyModelPrivate::proxy_item_range(
958 const QVector<int> &source_to_proxy, const QVector<int> &source_items,
959 int &proxy_low, int &proxy_high) const
960 {
961 proxy_low = INT_MAX;
962 proxy_high = INT_MIN;
963 for (int i = 0; i < source_items.count(); ++i) {
964 int proxy_item = source_to_proxy.at(source_items.at(i));
965 Q_ASSERT(proxy_item != -1);
966 if (proxy_item < proxy_low)
967 proxy_low = proxy_item;
968 if (proxy_item > proxy_high)
969 proxy_high = proxy_item;
970 }
971 }
972
973 /*!
974 \internal
975 */
build_source_to_proxy_mapping(const QVector<int> & proxy_to_source,QVector<int> & source_to_proxy) const976 void QSortFilterProxyModelPrivate::build_source_to_proxy_mapping(
977 const QVector<int> &proxy_to_source, QVector<int> &source_to_proxy) const
978 {
979 source_to_proxy.fill(-1);
980 int proxy_count = proxy_to_source.size();
981 for (int i = 0; i < proxy_count; ++i)
982 source_to_proxy[proxy_to_source.at(i)] = i;
983 }
984
985 /*!
986 \internal
987
988 Maps the persistent proxy indexes to source indexes and
989 returns the list of source indexes.
990 */
store_persistent_indexes()991 QModelIndexPairList QSortFilterProxyModelPrivate::store_persistent_indexes()
992 {
993 Q_Q(QSortFilterProxyModel);
994 QModelIndexPairList source_indexes;
995 foreach (QPersistentModelIndexData *data, persistent.indexes) {
996 QModelIndex proxy_index = data->index;
997 QModelIndex source_index = q->mapToSource(proxy_index);
998 source_indexes.append(qMakePair(proxy_index, QPersistentModelIndex(source_index)));
999 }
1000 return source_indexes;
1001 }
1002
1003 /*!
1004 \internal
1005
1006 Maps \a source_indexes to proxy indexes and stores those
1007 as persistent indexes.
1008 */
update_persistent_indexes(const QModelIndexPairList & source_indexes)1009 void QSortFilterProxyModelPrivate::update_persistent_indexes(
1010 const QModelIndexPairList &source_indexes)
1011 {
1012 Q_Q(QSortFilterProxyModel);
1013 QModelIndexList from, to;
1014 for (int i = 0; i < source_indexes.count(); ++i) {
1015 QModelIndex source_index = source_indexes.at(i).second;
1016 QModelIndex old_proxy_index = source_indexes.at(i).first;
1017 create_mapping(source_index.parent());
1018 QModelIndex proxy_index = q->mapFromSource(source_index);
1019 from << old_proxy_index;
1020 to << proxy_index;
1021 }
1022 q->changePersistentIndexList(from, to);
1023 }
1024
1025
1026 /*!
1027 \internal
1028
1029 Updates the proxy model (adds/removes rows) based on the
1030 new filter.
1031 */
filter_changed(const QModelIndex & source_parent)1032 void QSortFilterProxyModelPrivate::filter_changed(const QModelIndex &source_parent)
1033 {
1034 IndexMap::const_iterator it = source_index_mapping.constFind(source_parent);
1035 if (it == source_index_mapping.constEnd())
1036 return;
1037 Mapping *m = it.value();
1038 QSet<int> rows_removed = handle_filter_changed(m->proxy_rows, m->source_rows, source_parent, Qt::Vertical);
1039 QSet<int> columns_removed = handle_filter_changed(m->proxy_columns, m->source_columns, source_parent, Qt::Horizontal);
1040
1041 // We need to iterate over a copy of m->mapped_children because otherwise it may be changed by other code, invalidating
1042 // the iterator it2.
1043 // The m->mapped_children vector can be appended to with indexes which are no longer filtered
1044 // out (in create_mapping) when this function recurses for child indexes.
1045 const QVector<QModelIndex> mappedChildren = m->mapped_children;
1046 QVector<int> indexesToRemove;
1047 for (int i = 0; i < mappedChildren.size(); ++i) {
1048 const QModelIndex source_child_index = mappedChildren.at(i);
1049 if (rows_removed.contains(source_child_index.row()) || columns_removed.contains(source_child_index.column())) {
1050 indexesToRemove.push_back(i);
1051 remove_from_mapping(source_child_index);
1052 } else {
1053 filter_changed(source_child_index);
1054 }
1055 }
1056 QVector<int>::const_iterator removeIt = indexesToRemove.constEnd();
1057 const QVector<int>::const_iterator removeBegin = indexesToRemove.constBegin();
1058
1059 // We can't just remove these items from mappedChildren while iterating above and then
1060 // do something like m->mapped_children = mappedChildren, because mapped_children might
1061 // be appended to in create_mapping, and we would lose those new items.
1062 // Because they are always appended in create_mapping, we can still remove them by
1063 // position here.
1064 while (removeIt != removeBegin) {
1065 --removeIt;
1066 m->mapped_children.remove(*removeIt);
1067 }
1068 }
1069
1070 /*!
1071 \internal
1072 returns the removed items indexes
1073 */
handle_filter_changed(QVector<int> & source_to_proxy,QVector<int> & proxy_to_source,const QModelIndex & source_parent,Qt::Orientation orient)1074 QSet<int> QSortFilterProxyModelPrivate::handle_filter_changed(
1075 QVector<int> &source_to_proxy, QVector<int> &proxy_to_source,
1076 const QModelIndex &source_parent, Qt::Orientation orient)
1077 {
1078 Q_Q(QSortFilterProxyModel);
1079 // Figure out which mapped items to remove
1080 QVector<int> source_items_remove;
1081 for (int i = 0; i < proxy_to_source.count(); ++i) {
1082 const int source_item = proxy_to_source.at(i);
1083 if ((orient == Qt::Vertical)
1084 ? !q->filterAcceptsRow(source_item, source_parent)
1085 : !q->filterAcceptsColumn(source_item, source_parent)) {
1086 // This source item does not satisfy the filter, so it must be removed
1087 source_items_remove.append(source_item);
1088 }
1089 }
1090 // Figure out which non-mapped items to insert
1091 QVector<int> source_items_insert;
1092 int source_count = source_to_proxy.size();
1093 for (int source_item = 0; source_item < source_count; ++source_item) {
1094 if (source_to_proxy.at(source_item) == -1) {
1095 if ((orient == Qt::Vertical)
1096 ? q->filterAcceptsRow(source_item, source_parent)
1097 : q->filterAcceptsColumn(source_item, source_parent)) {
1098 // This source item satisfies the filter, so it must be added
1099 source_items_insert.append(source_item);
1100 }
1101 }
1102 }
1103 if (!source_items_remove.isEmpty() || !source_items_insert.isEmpty()) {
1104 // Do item removal and insertion
1105 remove_source_items(source_to_proxy, proxy_to_source,
1106 source_items_remove, source_parent, orient);
1107 if (orient == Qt::Vertical)
1108 sort_source_rows(source_items_insert, source_parent);
1109 insert_source_items(source_to_proxy, proxy_to_source,
1110 source_items_insert, source_parent, orient);
1111 }
1112 return qVectorToSet(source_items_remove);
1113 }
1114
_q_sourceDataChanged(const QModelIndex & source_top_left,const QModelIndex & source_bottom_right)1115 void QSortFilterProxyModelPrivate::_q_sourceDataChanged(const QModelIndex &source_top_left,
1116 const QModelIndex &source_bottom_right)
1117 {
1118 Q_Q(QSortFilterProxyModel);
1119 if (!source_top_left.isValid() || !source_bottom_right.isValid())
1120 return;
1121 QModelIndex source_parent = source_top_left.parent();
1122 IndexMap::const_iterator it = source_index_mapping.find(source_parent);
1123 if (it == source_index_mapping.constEnd()) {
1124 // Don't care, since we don't have mapping for this index
1125 return;
1126 }
1127 Mapping *m = it.value();
1128
1129 // Figure out how the source changes affect us
1130 QVector<int> source_rows_remove;
1131 QVector<int> source_rows_insert;
1132 QVector<int> source_rows_change;
1133 QVector<int> source_rows_resort;
1134 int end = qMin(source_bottom_right.row(), m->proxy_rows.count() - 1);
1135 for (int source_row = source_top_left.row(); source_row <= end; ++source_row) {
1136 if (dynamic_sortfilter) {
1137 if (m->proxy_rows.at(source_row) != -1) {
1138 if (!q->filterAcceptsRow(source_row, source_parent)) {
1139 // This source row no longer satisfies the filter, so it must be removed
1140 source_rows_remove.append(source_row);
1141 } else if (source_sort_column >= source_top_left.column() && source_sort_column <= source_bottom_right.column()) {
1142 // This source row has changed in a way that may affect sorted order
1143 source_rows_resort.append(source_row);
1144 } else {
1145 // This row has simply changed, without affecting filtering nor sorting
1146 source_rows_change.append(source_row);
1147 }
1148 } else {
1149 if (!itemsBeingRemoved.contains(source_parent, source_row) && q->filterAcceptsRow(source_row, source_parent)) {
1150 // This source row now satisfies the filter, so it must be added
1151 source_rows_insert.append(source_row);
1152 }
1153 }
1154 } else {
1155 if (m->proxy_rows.at(source_row) != -1)
1156 source_rows_change.append(source_row);
1157 }
1158 }
1159
1160 if (!source_rows_remove.isEmpty()) {
1161 remove_source_items(m->proxy_rows, m->source_rows,
1162 source_rows_remove, source_parent, Qt::Vertical);
1163 QSet<int> source_rows_remove_set = qVectorToSet(source_rows_remove);
1164 QVector<QModelIndex>::iterator it = m->mapped_children.end();
1165 while (it != m->mapped_children.begin()) {
1166 --it;
1167 const QModelIndex source_child_index = *it;
1168 if (source_rows_remove_set.contains(source_child_index.row())) {
1169 it = m->mapped_children.erase(it);
1170 remove_from_mapping(source_child_index);
1171 }
1172 }
1173 }
1174
1175 if (!source_rows_resort.isEmpty()) {
1176 // Re-sort the rows
1177 emit q->layoutAboutToBeChanged();
1178 QModelIndexPairList source_indexes = store_persistent_indexes();
1179 remove_source_items(m->proxy_rows, m->source_rows, source_rows_resort,
1180 source_parent, Qt::Vertical, false);
1181 sort_source_rows(source_rows_resort, source_parent);
1182 insert_source_items(m->proxy_rows, m->source_rows, source_rows_resort,
1183 source_parent, Qt::Vertical, false);
1184 update_persistent_indexes(source_indexes);
1185 emit q->layoutChanged();
1186 // Make sure we also emit dataChanged for the rows
1187 source_rows_change += source_rows_resort;
1188 }
1189
1190 if (!source_rows_change.isEmpty()) {
1191 // Find the proxy row range
1192 int proxy_start_row;
1193 int proxy_end_row;
1194 proxy_item_range(m->proxy_rows, source_rows_change,
1195 proxy_start_row, proxy_end_row);
1196 // ### Find the proxy column range also
1197 if (proxy_end_row >= 0) {
1198 // the row was accepted, but some columns might still be filtered out
1199 int source_left_column = source_top_left.column();
1200 while (source_left_column < source_bottom_right.column()
1201 && m->proxy_columns.at(source_left_column) == -1)
1202 ++source_left_column;
1203 const QModelIndex proxy_top_left = create_index(
1204 proxy_start_row, m->proxy_columns.at(source_left_column), it);
1205 int source_right_column = source_bottom_right.column();
1206 while (source_right_column > source_top_left.column()
1207 && m->proxy_columns.at(source_right_column) == -1)
1208 --source_right_column;
1209 const QModelIndex proxy_bottom_right = create_index(
1210 proxy_end_row, m->proxy_columns.at(source_right_column), it);
1211 emit q->dataChanged(proxy_top_left, proxy_bottom_right);
1212 }
1213 }
1214
1215 if (!source_rows_insert.isEmpty()) {
1216 sort_source_rows(source_rows_insert, source_parent);
1217 insert_source_items(m->proxy_rows, m->source_rows,
1218 source_rows_insert, source_parent, Qt::Vertical);
1219 }
1220 }
1221
_q_sourceHeaderDataChanged(Qt::Orientation orientation,int start,int end)1222 void QSortFilterProxyModelPrivate::_q_sourceHeaderDataChanged(Qt::Orientation orientation,
1223 int start, int end)
1224 {
1225 Q_Q(QSortFilterProxyModel);
1226 Mapping *m = create_mapping(QModelIndex()).value();
1227 int proxy_start = (orientation == Qt::Vertical
1228 ? m->proxy_rows.at(start)
1229 : m->proxy_columns.at(start));
1230 int proxy_end = (orientation == Qt::Vertical
1231 ? m->proxy_rows.at(end)
1232 : m->proxy_columns.at(end));
1233 emit q->headerDataChanged(orientation, proxy_start, proxy_end);
1234 }
1235
_q_sourceAboutToBeReset()1236 void QSortFilterProxyModelPrivate::_q_sourceAboutToBeReset()
1237 {
1238 Q_Q(QSortFilterProxyModel);
1239 q->beginResetModel();
1240 }
1241
_q_sourceReset()1242 void QSortFilterProxyModelPrivate::_q_sourceReset()
1243 {
1244 Q_Q(QSortFilterProxyModel);
1245 invalidatePersistentIndexes();
1246 _q_clearMapping();
1247 // All internal structures are deleted in clear()
1248 q->endResetModel();
1249 update_source_sort_column();
1250 if (dynamic_sortfilter)
1251 sort();
1252 }
1253
_q_sourceLayoutAboutToBeChanged()1254 void QSortFilterProxyModelPrivate::_q_sourceLayoutAboutToBeChanged()
1255 {
1256 Q_Q(QSortFilterProxyModel);
1257 saved_persistent_indexes.clear();
1258 emit q->layoutAboutToBeChanged();
1259 if (persistent.indexes.isEmpty())
1260 return;
1261
1262 saved_persistent_indexes = store_persistent_indexes();
1263 }
1264
_q_sourceLayoutChanged()1265 void QSortFilterProxyModelPrivate::_q_sourceLayoutChanged()
1266 {
1267 Q_Q(QSortFilterProxyModel);
1268
1269 qDeleteAll(source_index_mapping);
1270 source_index_mapping.clear();
1271
1272 update_persistent_indexes(saved_persistent_indexes);
1273 saved_persistent_indexes.clear();
1274
1275 if (dynamic_sortfilter && update_source_sort_column()) {
1276 //update_source_sort_column might have created wrong mapping so we have to clear it again
1277 qDeleteAll(source_index_mapping);
1278 source_index_mapping.clear();
1279 }
1280
1281 emit q->layoutChanged();
1282 }
1283
_q_sourceRowsAboutToBeInserted(const QModelIndex & source_parent,int start,int end)1284 void QSortFilterProxyModelPrivate::_q_sourceRowsAboutToBeInserted(
1285 const QModelIndex &source_parent, int start, int end)
1286 {
1287 Q_UNUSED(start);
1288 Q_UNUSED(end);
1289 //Force the creation of a mapping now, even if its empty.
1290 //We need it because the proxy can be acessed at the moment it emits rowsAboutToBeInserted in insert_source_items
1291 if (can_create_mapping(source_parent))
1292 create_mapping(source_parent);
1293 }
1294
_q_sourceRowsInserted(const QModelIndex & source_parent,int start,int end)1295 void QSortFilterProxyModelPrivate::_q_sourceRowsInserted(
1296 const QModelIndex &source_parent, int start, int end)
1297 {
1298 source_items_inserted(source_parent, start, end, Qt::Vertical);
1299 if (update_source_sort_column() && dynamic_sortfilter) //previous call to update_source_sort_column may fail if the model has no column.
1300 sort(); // now it should succeed so we need to make sure to sort again
1301 }
1302
_q_sourceRowsAboutToBeRemoved(const QModelIndex & source_parent,int start,int end)1303 void QSortFilterProxyModelPrivate::_q_sourceRowsAboutToBeRemoved(
1304 const QModelIndex &source_parent, int start, int end)
1305 {
1306 itemsBeingRemoved = QRowsRemoval(source_parent, start, end);
1307 source_items_about_to_be_removed(source_parent, start, end,
1308 Qt::Vertical);
1309 }
1310
_q_sourceRowsRemoved(const QModelIndex & source_parent,int start,int end)1311 void QSortFilterProxyModelPrivate::_q_sourceRowsRemoved(
1312 const QModelIndex &source_parent, int start, int end)
1313 {
1314 itemsBeingRemoved = QRowsRemoval();
1315 source_items_removed(source_parent, start, end, Qt::Vertical);
1316 }
1317
_q_sourceColumnsAboutToBeInserted(const QModelIndex & source_parent,int start,int end)1318 void QSortFilterProxyModelPrivate::_q_sourceColumnsAboutToBeInserted(
1319 const QModelIndex &source_parent, int start, int end)
1320 {
1321 Q_UNUSED(start);
1322 Q_UNUSED(end);
1323 //Force the creation of a mapping now, even if its empty.
1324 //We need it because the proxy can be acessed at the moment it emits columnsAboutToBeInserted in insert_source_items
1325 if (can_create_mapping(source_parent))
1326 create_mapping(source_parent);
1327 }
1328
_q_sourceColumnsInserted(const QModelIndex & source_parent,int start,int end)1329 void QSortFilterProxyModelPrivate::_q_sourceColumnsInserted(
1330 const QModelIndex &source_parent, int start, int end)
1331 {
1332 Q_Q(const QSortFilterProxyModel);
1333 source_items_inserted(source_parent, start, end, Qt::Horizontal);
1334
1335 if (source_parent.isValid())
1336 return; //we sort according to the root column only
1337 if (source_sort_column == -1) {
1338 //we update the source_sort_column depending on the proxy_sort_column
1339 if (update_source_sort_column() && dynamic_sortfilter)
1340 sort();
1341 } else {
1342 if (start <= source_sort_column)
1343 source_sort_column += end - start + 1;
1344
1345 proxy_sort_column = q->mapFromSource(model->index(0,source_sort_column, source_parent)).column();
1346 }
1347 }
1348
_q_sourceColumnsAboutToBeRemoved(const QModelIndex & source_parent,int start,int end)1349 void QSortFilterProxyModelPrivate::_q_sourceColumnsAboutToBeRemoved(
1350 const QModelIndex &source_parent, int start, int end)
1351 {
1352 source_items_about_to_be_removed(source_parent, start, end,
1353 Qt::Horizontal);
1354 }
1355
_q_sourceColumnsRemoved(const QModelIndex & source_parent,int start,int end)1356 void QSortFilterProxyModelPrivate::_q_sourceColumnsRemoved(
1357 const QModelIndex &source_parent, int start, int end)
1358 {
1359 Q_Q(const QSortFilterProxyModel);
1360 source_items_removed(source_parent, start, end, Qt::Horizontal);
1361
1362 if (source_parent.isValid())
1363 return; //we sort according to the root column only
1364 if (start <= source_sort_column) {
1365 if (end < source_sort_column)
1366 source_sort_column -= end - start + 1;
1367 else
1368 source_sort_column = -1;
1369 }
1370
1371 proxy_sort_column = q->mapFromSource(model->index(0,source_sort_column, source_parent)).column();
1372 }
1373
1374 /*!
1375 \since 4.1
1376 \class QSortFilterProxyModel
1377 \brief The QSortFilterProxyModel class provides support for sorting and
1378 filtering data passed between another model and a view.
1379
1380 \ingroup model-view
1381
1382 QSortFilterProxyModel can be used for sorting items, filtering out items,
1383 or both. The model transforms the structure of a source model by mapping
1384 the model indexes it supplies to new indexes, corresponding to different
1385 locations, for views to use. This approach allows a given source model to
1386 be restructured as far as views are concerned without requiring any
1387 transformations on the underlying data, and without duplicating the data in
1388 memory.
1389
1390 Let's assume that we want to sort and filter the items provided by a custom
1391 model. The code to set up the model and the view, \e without sorting and
1392 filtering, would look like this:
1393
1394 \snippet doc/src/snippets/qsortfilterproxymodel-details/main.cpp 1
1395
1396 To add sorting and filtering support to \c MyItemModel, we need to create
1397 a QSortFilterProxyModel, call setSourceModel() with the \c MyItemModel as
1398 argument, and install the QSortFilterProxyModel on the view:
1399
1400 \snippet doc/src/snippets/qsortfilterproxymodel-details/main.cpp 0
1401 \snippet doc/src/snippets/qsortfilterproxymodel-details/main.cpp 2
1402
1403 At this point, neither sorting nor filtering is enabled; the original data
1404 is displayed in the view. Any changes made through the
1405 QSortFilterProxyModel are applied to the original model.
1406
1407 The QSortFilterProxyModel acts as a wrapper for the original model. If you
1408 need to convert source \l{QModelIndex}es to sorted/filtered model indexes
1409 or vice versa, use mapToSource(), mapFromSource(), mapSelectionToSource(),
1410 and mapSelectionFromSource().
1411
1412 \note By default, the model does not dynamically re-sort and re-filter data
1413 whenever the original model changes. This behavior can be changed by
1414 setting the \l{QSortFilterProxyModel::dynamicSortFilter}{dynamicSortFilter}
1415 property.
1416
1417 The \l{itemviews/basicsortfiltermodel}{Basic Sort/Filter Model} and
1418 \l{itemviews/customsortfiltermodel}{Custom Sort/Filter Model} examples
1419 illustrate how to use QSortFilterProxyModel to perform basic sorting and
1420 filtering and how to subclass it to implement custom behavior.
1421
1422 \section1 Sorting
1423
1424 QTableView and QTreeView have a
1425 \l{QTreeView::sortingEnabled}{sortingEnabled} property that controls
1426 whether the user can sort the view by clicking the view's horizontal
1427 header. For example:
1428
1429 \snippet doc/src/snippets/qsortfilterproxymodel-details/main.cpp 3
1430
1431 When this feature is on (the default is off), clicking on a header section
1432 sorts the items according to that column. By clicking repeatedly, the user
1433 can alternate between ascending and descending order.
1434
1435 \image qsortfilterproxymodel-sorting.png A sorted QTreeView
1436
1437 Behind the scene, the view calls the sort() virtual function on the model
1438 to reorder the data in the model. To make your data sortable, you can
1439 either implement sort() in your model, or use a QSortFilterProxyModel to
1440 wrap your model -- QSortFilterProxyModel provides a generic sort()
1441 reimplementation that operates on the sortRole() (Qt::DisplayRole by
1442 default) of the items and that understands several data types, including
1443 \c int, QString, and QDateTime. For hierarchical models, sorting is applied
1444 recursively to all child items. String comparisons are case sensitive by
1445 default; this can be changed by setting the \l{QSortFilterProxyModel::}
1446 {sortCaseSensitivity} property.
1447
1448 Custom sorting behavior is achieved by subclassing
1449 QSortFilterProxyModel and reimplementing lessThan(), which is
1450 used to compare items. For example:
1451
1452 \snippet examples/itemviews/customsortfiltermodel/mysortfilterproxymodel.cpp 5
1453
1454 (This code snippet comes from the
1455 \l{itemviews/customsortfiltermodel}{Custom Sort/Filter Model}
1456 example.)
1457
1458 An alternative approach to sorting is to disable sorting on the view and to
1459 impose a certain order to the user. This is done by explicitly calling
1460 sort() with the desired column and order as arguments on the
1461 QSortFilterProxyModel (or on the original model if it implements sort()).
1462 For example:
1463
1464 \snippet doc/src/snippets/qsortfilterproxymodel-details/main.cpp 4
1465
1466 QSortFilterProxyModel can be sorted by column -1, in which case it returns
1467 to the sort order of the underlying source model.
1468
1469 \section1 Filtering
1470
1471 In addition to sorting, QSortFilterProxyModel can be used to hide items
1472 that do not match a certain filter. The filter is specified using a QRegExp
1473 object and is applied to the filterRole() (Qt::DisplayRole by default) of
1474 each item, for a given column. The QRegExp object can be used to match a
1475 regular expression, a wildcard pattern, or a fixed string. For example:
1476
1477 \snippet doc/src/snippets/qsortfilterproxymodel-details/main.cpp 5
1478
1479 For hierarchical models, the filter is applied recursively to all children.
1480 If a parent item doesn't match the filter, none of its children will be
1481 shown.
1482
1483 A common use case is to let the user specify the filter regexp, wildcard
1484 pattern, or fixed string in a QLineEdit and to connect the
1485 \l{QLineEdit::textChanged()}{textChanged()} signal to setFilterRegExp(),
1486 setFilterWildcard(), or setFilterFixedString() to reapply the filter.
1487
1488 Custom filtering behavior can be achieved by reimplementing the
1489 filterAcceptsRow() and filterAcceptsColumn() functions. For
1490 example (from the \l{itemviews/customsortfiltermodel}
1491 {Custom Sort/Filter Model} example), the following implementation ignores
1492 the \l{QSortFilterProxyModel::filterKeyColumn}{filterKeyColumn} property
1493 and performs filtering on columns 0, 1, and 2:
1494
1495 \snippet examples/itemviews/customsortfiltermodel/mysortfilterproxymodel.cpp 3
1496
1497 (This code snippet comes from the
1498 \l{itemviews/customsortfiltermodel}{Custom Sort/Filter Model}
1499 example.)
1500
1501 If you are working with large amounts of filtering and have to invoke
1502 invalidateFilter() repeatedly, using reset() may be more efficient,
1503 depending on the implementation of your model. However, reset() returns the
1504 proxy model to its original state, losing selection information, and will
1505 cause the proxy model to be repopulated.
1506
1507 \section1 Subclassing
1508
1509 Since QAbstractProxyModel and its subclasses are derived from
1510 QAbstractItemModel, much of the same advice about subclassing normal models
1511 also applies to proxy models. In addition, it is worth noting that many of
1512 the default implementations of functions in this class are written so that
1513 they call the equivalent functions in the relevant source model. This
1514 simple proxying mechanism may need to be overridden for source models with
1515 more complex behavior; for example, if the source model provides a custom
1516 hasChildren() implementation, you should also provide one in the proxy
1517 model.
1518
1519 \note Some general guidelines for subclassing models are available in the
1520 \l{Model Subclassing Reference}.
1521
1522 \sa QAbstractProxyModel, QAbstractItemModel, {Model/View Programming},
1523 {Basic Sort/Filter Model Example}, {Custom Sort/Filter Model Example}, QIdentityProxyModel
1524 */
1525
1526 /*!
1527 Constructs a sorting filter model with the given \a parent.
1528 */
1529
QSortFilterProxyModel(QObject * parent)1530 QSortFilterProxyModel::QSortFilterProxyModel(QObject *parent)
1531 : QAbstractProxyModel(*new QSortFilterProxyModelPrivate, parent)
1532 {
1533 Q_D(QSortFilterProxyModel);
1534 d->proxy_sort_column = d->source_sort_column = -1;
1535 d->sort_order = Qt::AscendingOrder;
1536 d->sort_casesensitivity = Qt::CaseSensitive;
1537 d->sort_role = Qt::DisplayRole;
1538 d->sort_localeaware = false;
1539 d->filter_column = 0;
1540 d->filter_role = Qt::DisplayRole;
1541 d->dynamic_sortfilter = false;
1542 connect(this, SIGNAL(modelReset()), this, SLOT(_q_clearMapping()));
1543 }
1544
1545 /*!
1546 Destroys this sorting filter model.
1547 */
~QSortFilterProxyModel()1548 QSortFilterProxyModel::~QSortFilterProxyModel()
1549 {
1550 Q_D(QSortFilterProxyModel);
1551 qDeleteAll(d->source_index_mapping);
1552 d->source_index_mapping.clear();
1553 }
1554
1555 /*!
1556 \reimp
1557 */
setSourceModel(QAbstractItemModel * sourceModel)1558 void QSortFilterProxyModel::setSourceModel(QAbstractItemModel *sourceModel)
1559 {
1560 Q_D(QSortFilterProxyModel);
1561
1562 beginResetModel();
1563
1564 disconnect(d->model, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
1565 this, SLOT(_q_sourceDataChanged(QModelIndex,QModelIndex)));
1566
1567 disconnect(d->model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)),
1568 this, SLOT(_q_sourceHeaderDataChanged(Qt::Orientation,int,int)));
1569
1570 disconnect(d->model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
1571 this, SLOT(_q_sourceRowsAboutToBeInserted(QModelIndex,int,int)));
1572
1573 disconnect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)),
1574 this, SLOT(_q_sourceRowsInserted(QModelIndex,int,int)));
1575
1576 disconnect(d->model, SIGNAL(columnsAboutToBeInserted(QModelIndex,int,int)),
1577 this, SLOT(_q_sourceColumnsAboutToBeInserted(QModelIndex,int,int)));
1578
1579 disconnect(d->model, SIGNAL(columnsInserted(QModelIndex,int,int)),
1580 this, SLOT(_q_sourceColumnsInserted(QModelIndex,int,int)));
1581
1582 disconnect(d->model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
1583 this, SLOT(_q_sourceRowsAboutToBeRemoved(QModelIndex,int,int)));
1584
1585 disconnect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
1586 this, SLOT(_q_sourceRowsRemoved(QModelIndex,int,int)));
1587
1588 disconnect(d->model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
1589 this, SLOT(_q_sourceColumnsAboutToBeRemoved(QModelIndex,int,int)));
1590
1591 disconnect(d->model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
1592 this, SLOT(_q_sourceColumnsRemoved(QModelIndex,int,int)));
1593
1594 disconnect(d->model, SIGNAL(layoutAboutToBeChanged()),
1595 this, SLOT(_q_sourceLayoutAboutToBeChanged()));
1596
1597 disconnect(d->model, SIGNAL(layoutChanged()),
1598 this, SLOT(_q_sourceLayoutChanged()));
1599
1600 disconnect(d->model, SIGNAL(modelAboutToBeReset()), this, SLOT(_q_sourceAboutToBeReset()));
1601 disconnect(d->model, SIGNAL(modelReset()), this, SLOT(_q_sourceReset()));
1602
1603 QAbstractProxyModel::setSourceModel(sourceModel);
1604
1605 connect(d->model, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
1606 this, SLOT(_q_sourceDataChanged(QModelIndex,QModelIndex)));
1607
1608 connect(d->model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)),
1609 this, SLOT(_q_sourceHeaderDataChanged(Qt::Orientation,int,int)));
1610
1611 connect(d->model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
1612 this, SLOT(_q_sourceRowsAboutToBeInserted(QModelIndex,int,int)));
1613
1614 connect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)),
1615 this, SLOT(_q_sourceRowsInserted(QModelIndex,int,int)));
1616
1617 connect(d->model, SIGNAL(columnsAboutToBeInserted(QModelIndex,int,int)),
1618 this, SLOT(_q_sourceColumnsAboutToBeInserted(QModelIndex,int,int)));
1619
1620 connect(d->model, SIGNAL(columnsInserted(QModelIndex,int,int)),
1621 this, SLOT(_q_sourceColumnsInserted(QModelIndex,int,int)));
1622
1623 connect(d->model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
1624 this, SLOT(_q_sourceRowsAboutToBeRemoved(QModelIndex,int,int)));
1625
1626 connect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
1627 this, SLOT(_q_sourceRowsRemoved(QModelIndex,int,int)));
1628
1629 connect(d->model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
1630 this, SLOT(_q_sourceColumnsAboutToBeRemoved(QModelIndex,int,int)));
1631
1632 connect(d->model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
1633 this, SLOT(_q_sourceColumnsRemoved(QModelIndex,int,int)));
1634
1635 connect(d->model, SIGNAL(layoutAboutToBeChanged()),
1636 this, SLOT(_q_sourceLayoutAboutToBeChanged()));
1637
1638 connect(d->model, SIGNAL(layoutChanged()),
1639 this, SLOT(_q_sourceLayoutChanged()));
1640
1641 connect(d->model, SIGNAL(modelAboutToBeReset()), this, SLOT(_q_sourceAboutToBeReset()));
1642 connect(d->model, SIGNAL(modelReset()), this, SLOT(_q_sourceReset()));
1643
1644 d->_q_clearMapping();
1645 endResetModel();
1646 if (d->update_source_sort_column() && d->dynamic_sortfilter)
1647 d->sort();
1648 }
1649
1650 /*!
1651 \reimp
1652 */
index(int row,int column,const QModelIndex & parent) const1653 QModelIndex QSortFilterProxyModel::index(int row, int column, const QModelIndex &parent) const
1654 {
1655 Q_D(const QSortFilterProxyModel);
1656 if (row < 0 || column < 0)
1657 return QModelIndex();
1658
1659 QModelIndex source_parent = mapToSource(parent); // parent is already mapped at this point
1660 IndexMap::const_iterator it = d->create_mapping(source_parent); // but make sure that the children are mapped
1661 if (it.value()->source_rows.count() <= row || it.value()->source_columns.count() <= column)
1662 return QModelIndex();
1663
1664 return d->create_index(row, column, it);
1665 }
1666
1667 /*!
1668 \reimp
1669 */
parent(const QModelIndex & child) const1670 QModelIndex QSortFilterProxyModel::parent(const QModelIndex &child) const
1671 {
1672 Q_D(const QSortFilterProxyModel);
1673 if (!d->indexValid(child))
1674 return QModelIndex();
1675 IndexMap::const_iterator it = d->index_to_iterator(child);
1676 Q_ASSERT(it != d->source_index_mapping.constEnd());
1677 QModelIndex source_parent = it.key();
1678 QModelIndex proxy_parent = mapFromSource(source_parent);
1679 return proxy_parent;
1680 }
1681
1682 /*!
1683 \reimp
1684 */
rowCount(const QModelIndex & parent) const1685 int QSortFilterProxyModel::rowCount(const QModelIndex &parent) const
1686 {
1687 Q_D(const QSortFilterProxyModel);
1688 QModelIndex source_parent = mapToSource(parent);
1689 if (parent.isValid() && !source_parent.isValid())
1690 return 0;
1691 IndexMap::const_iterator it = d->create_mapping(source_parent);
1692 return it.value()->source_rows.count();
1693 }
1694
1695 /*!
1696 \reimp
1697 */
columnCount(const QModelIndex & parent) const1698 int QSortFilterProxyModel::columnCount(const QModelIndex &parent) const
1699 {
1700 Q_D(const QSortFilterProxyModel);
1701 QModelIndex source_parent = mapToSource(parent);
1702 if (parent.isValid() && !source_parent.isValid())
1703 return 0;
1704 IndexMap::const_iterator it = d->create_mapping(source_parent);
1705 return it.value()->source_columns.count();
1706 }
1707
1708 /*!
1709 \reimp
1710 */
hasChildren(const QModelIndex & parent) const1711 bool QSortFilterProxyModel::hasChildren(const QModelIndex &parent) const
1712 {
1713 Q_D(const QSortFilterProxyModel);
1714 QModelIndex source_parent = mapToSource(parent);
1715 if (parent.isValid() && !source_parent.isValid())
1716 return false;
1717 if (!d->model->hasChildren(source_parent))
1718 return false;
1719
1720 if (d->model->canFetchMore(source_parent))
1721 return true; //we assume we might have children that can be fetched
1722
1723 QSortFilterProxyModelPrivate::Mapping *m = d->create_mapping(source_parent).value();
1724 return m->source_rows.count() != 0 && m->source_columns.count() != 0;
1725 }
1726
1727 /*!
1728 \reimp
1729 */
data(const QModelIndex & index,int role) const1730 QVariant QSortFilterProxyModel::data(const QModelIndex &index, int role) const
1731 {
1732 Q_D(const QSortFilterProxyModel);
1733 QModelIndex source_index = mapToSource(index);
1734 if (index.isValid() && !source_index.isValid())
1735 return QVariant();
1736 return d->model->data(source_index, role);
1737 }
1738
1739 /*!
1740 \reimp
1741 */
setData(const QModelIndex & index,const QVariant & value,int role)1742 bool QSortFilterProxyModel::setData(const QModelIndex &index, const QVariant &value, int role)
1743 {
1744 Q_D(QSortFilterProxyModel);
1745 QModelIndex source_index = mapToSource(index);
1746 if (index.isValid() && !source_index.isValid())
1747 return false;
1748 return d->model->setData(source_index, value, role);
1749 }
1750
1751 /*!
1752 \reimp
1753 */
headerData(int section,Qt::Orientation orientation,int role) const1754 QVariant QSortFilterProxyModel::headerData(int section, Qt::Orientation orientation, int role) const
1755 {
1756 Q_D(const QSortFilterProxyModel);
1757 IndexMap::const_iterator it = d->create_mapping(QModelIndex());
1758 if (it.value()->source_rows.count() * it.value()->source_columns.count() > 0)
1759 return QAbstractProxyModel::headerData(section, orientation, role);
1760 int source_section;
1761 if (orientation == Qt::Vertical) {
1762 if (section < 0 || section >= it.value()->source_rows.count())
1763 return QVariant();
1764 source_section = it.value()->source_rows.at(section);
1765 } else {
1766 if (section < 0 || section >= it.value()->source_columns.count())
1767 return QVariant();
1768 source_section = it.value()->source_columns.at(section);
1769 }
1770 return d->model->headerData(source_section, orientation, role);
1771 }
1772
1773 /*!
1774 \reimp
1775 */
setHeaderData(int section,Qt::Orientation orientation,const QVariant & value,int role)1776 bool QSortFilterProxyModel::setHeaderData(int section, Qt::Orientation orientation,
1777 const QVariant &value, int role)
1778 {
1779 Q_D(QSortFilterProxyModel);
1780 IndexMap::const_iterator it = d->create_mapping(QModelIndex());
1781 if (it.value()->source_rows.count() * it.value()->source_columns.count() > 0)
1782 return QAbstractProxyModel::setHeaderData(section, orientation, value, role);
1783 int source_section;
1784 if (orientation == Qt::Vertical) {
1785 if (section < 0 || section >= it.value()->source_rows.count())
1786 return false;
1787 source_section = it.value()->source_rows.at(section);
1788 } else {
1789 if (section < 0 || section >= it.value()->source_columns.count())
1790 return false;
1791 source_section = it.value()->source_columns.at(section);
1792 }
1793 return d->model->setHeaderData(source_section, orientation, value, role);
1794 }
1795
1796 /*!
1797 \reimp
1798 */
mimeData(const QModelIndexList & indexes) const1799 QMimeData *QSortFilterProxyModel::mimeData(const QModelIndexList &indexes) const
1800 {
1801 Q_D(const QSortFilterProxyModel);
1802 QModelIndexList source_indexes;
1803 for (int i = 0; i < indexes.count(); ++i)
1804 source_indexes << mapToSource(indexes.at(i));
1805 return d->model->mimeData(source_indexes);
1806 }
1807
1808 /*!
1809 \reimp
1810 */
mimeTypes() const1811 QStringList QSortFilterProxyModel::mimeTypes() const
1812 {
1813 Q_D(const QSortFilterProxyModel);
1814 return d->model->mimeTypes();
1815 }
1816
1817 /*!
1818 \reimp
1819 */
supportedDropActions() const1820 Qt::DropActions QSortFilterProxyModel::supportedDropActions() const
1821 {
1822 Q_D(const QSortFilterProxyModel);
1823 return d->model->supportedDropActions();
1824 }
1825
1826 /*!
1827 \reimp
1828 */
dropMimeData(const QMimeData * data,Qt::DropAction action,int row,int column,const QModelIndex & parent)1829 bool QSortFilterProxyModel::dropMimeData(const QMimeData *data, Qt::DropAction action,
1830 int row, int column, const QModelIndex &parent)
1831 {
1832 Q_D(QSortFilterProxyModel);
1833 if ((row == -1) && (column == -1))
1834 return d->model->dropMimeData(data, action, -1, -1, mapToSource(parent));
1835 int source_destination_row = -1;
1836 int source_destination_column = -1;
1837 QModelIndex source_parent;
1838 if (row == rowCount(parent)) {
1839 source_parent = mapToSource(parent);
1840 source_destination_row = d->model->rowCount(source_parent);
1841 } else {
1842 QModelIndex proxy_index = index(row, column, parent);
1843 QModelIndex source_index = mapToSource(proxy_index);
1844 source_destination_row = source_index.row();
1845 source_destination_column = source_index.column();
1846 source_parent = source_index.parent();
1847 }
1848 return d->model->dropMimeData(data, action, source_destination_row,
1849 source_destination_column, source_parent);
1850 }
1851
1852 /*!
1853 \reimp
1854 */
insertRows(int row,int count,const QModelIndex & parent)1855 bool QSortFilterProxyModel::insertRows(int row, int count, const QModelIndex &parent)
1856 {
1857 Q_D(QSortFilterProxyModel);
1858 if (row < 0 || count <= 0)
1859 return false;
1860 QModelIndex source_parent = mapToSource(parent);
1861 if (parent.isValid() && !source_parent.isValid())
1862 return false;
1863 QSortFilterProxyModelPrivate::Mapping *m = d->create_mapping(source_parent).value();
1864 if (row > m->source_rows.count())
1865 return false;
1866 int source_row = (row >= m->source_rows.count()
1867 ? m->source_rows.count()
1868 : m->source_rows.at(row));
1869 return d->model->insertRows(source_row, count, source_parent);
1870 }
1871
1872 /*!
1873 \reimp
1874 */
insertColumns(int column,int count,const QModelIndex & parent)1875 bool QSortFilterProxyModel::insertColumns(int column, int count, const QModelIndex &parent)
1876 {
1877 Q_D(QSortFilterProxyModel);
1878 if (column < 0|| count <= 0)
1879 return false;
1880 QModelIndex source_parent = mapToSource(parent);
1881 if (parent.isValid() && !source_parent.isValid())
1882 return false;
1883 QSortFilterProxyModelPrivate::Mapping *m = d->create_mapping(source_parent).value();
1884 if (column > m->source_columns.count())
1885 return false;
1886 int source_column = (column >= m->source_columns.count()
1887 ? m->source_columns.count()
1888 : m->source_columns.at(column));
1889 return d->model->insertColumns(source_column, count, source_parent);
1890 }
1891
1892 /*!
1893 \reimp
1894 */
removeRows(int row,int count,const QModelIndex & parent)1895 bool QSortFilterProxyModel::removeRows(int row, int count, const QModelIndex &parent)
1896 {
1897 Q_D(QSortFilterProxyModel);
1898 if (row < 0 || count <= 0)
1899 return false;
1900 QModelIndex source_parent = mapToSource(parent);
1901 if (parent.isValid() && !source_parent.isValid())
1902 return false;
1903 QSortFilterProxyModelPrivate::Mapping *m = d->create_mapping(source_parent).value();
1904 if (row + count > m->source_rows.count())
1905 return false;
1906 if ((count == 1)
1907 || ((d->source_sort_column < 0) && (m->proxy_rows.count() == m->source_rows.count()))) {
1908 int source_row = m->source_rows.at(row);
1909 return d->model->removeRows(source_row, count, source_parent);
1910 }
1911 // remove corresponding source intervals
1912 // ### if this proves to be slow, we can switch to single-row removal
1913 QVector<int> rows;
1914 for (int i = row; i < row + count; ++i)
1915 rows.append(m->source_rows.at(i));
1916 qSort(rows.begin(), rows.end());
1917
1918 int pos = rows.count() - 1;
1919 bool ok = true;
1920 while (pos >= 0) {
1921 const int source_end = rows.at(pos--);
1922 int source_start = source_end;
1923 while ((pos >= 0) && (rows.at(pos) == (source_start - 1))) {
1924 --source_start;
1925 --pos;
1926 }
1927 ok = ok && d->model->removeRows(source_start, source_end - source_start + 1,
1928 source_parent);
1929 }
1930 return ok;
1931 }
1932
1933 /*!
1934 \reimp
1935 */
removeColumns(int column,int count,const QModelIndex & parent)1936 bool QSortFilterProxyModel::removeColumns(int column, int count, const QModelIndex &parent)
1937 {
1938 Q_D(QSortFilterProxyModel);
1939 if (column < 0 || count <= 0)
1940 return false;
1941 QModelIndex source_parent = mapToSource(parent);
1942 if (parent.isValid() && !source_parent.isValid())
1943 return false;
1944 QSortFilterProxyModelPrivate::Mapping *m = d->create_mapping(source_parent).value();
1945 if (column + count > m->source_columns.count())
1946 return false;
1947 if ((count == 1) || (m->proxy_columns.count() == m->source_columns.count())) {
1948 int source_column = m->source_columns.at(column);
1949 return d->model->removeColumns(source_column, count, source_parent);
1950 }
1951 // remove corresponding source intervals
1952 QVector<int> columns;
1953 for (int i = column; i < column + count; ++i)
1954 columns.append(m->source_columns.at(i));
1955
1956 int pos = columns.count() - 1;
1957 bool ok = true;
1958 while (pos >= 0) {
1959 const int source_end = columns.at(pos--);
1960 int source_start = source_end;
1961 while ((pos >= 0) && (columns.at(pos) == (source_start - 1))) {
1962 --source_start;
1963 --pos;
1964 }
1965 ok = ok && d->model->removeColumns(source_start, source_end - source_start + 1,
1966 source_parent);
1967 }
1968 return ok;
1969 }
1970
1971 /*!
1972 \reimp
1973 */
fetchMore(const QModelIndex & parent)1974 void QSortFilterProxyModel::fetchMore(const QModelIndex &parent)
1975 {
1976 Q_D(QSortFilterProxyModel);
1977 QModelIndex source_parent;
1978 if (d->indexValid(parent))
1979 source_parent = mapToSource(parent);
1980 d->model->fetchMore(source_parent);
1981 }
1982
1983 /*!
1984 \reimp
1985 */
canFetchMore(const QModelIndex & parent) const1986 bool QSortFilterProxyModel::canFetchMore(const QModelIndex &parent) const
1987 {
1988 Q_D(const QSortFilterProxyModel);
1989 QModelIndex source_parent;
1990 if (d->indexValid(parent))
1991 source_parent = mapToSource(parent);
1992 return d->model->canFetchMore(source_parent);
1993 }
1994
1995 /*!
1996 \reimp
1997 */
flags(const QModelIndex & index) const1998 Qt::ItemFlags QSortFilterProxyModel::flags(const QModelIndex &index) const
1999 {
2000 Q_D(const QSortFilterProxyModel);
2001 QModelIndex source_index;
2002 if (d->indexValid(index))
2003 source_index = mapToSource(index);
2004 return d->model->flags(source_index);
2005 }
2006
2007 /*!
2008 \reimp
2009 */
buddy(const QModelIndex & index) const2010 QModelIndex QSortFilterProxyModel::buddy(const QModelIndex &index) const
2011 {
2012 Q_D(const QSortFilterProxyModel);
2013 if (!d->indexValid(index))
2014 return QModelIndex();
2015 QModelIndex source_index = mapToSource(index);
2016 QModelIndex source_buddy = d->model->buddy(source_index);
2017 if (source_index == source_buddy)
2018 return index;
2019 return mapFromSource(source_buddy);
2020 }
2021
2022 /*!
2023 \reimp
2024 */
match(const QModelIndex & start,int role,const QVariant & value,int hits,Qt::MatchFlags flags) const2025 QModelIndexList QSortFilterProxyModel::match(const QModelIndex &start, int role,
2026 const QVariant &value, int hits,
2027 Qt::MatchFlags flags) const
2028 {
2029 return QAbstractProxyModel::match(start, role, value, hits, flags);
2030 }
2031
2032 /*!
2033 \reimp
2034 */
span(const QModelIndex & index) const2035 QSize QSortFilterProxyModel::span(const QModelIndex &index) const
2036 {
2037 Q_D(const QSortFilterProxyModel);
2038 QModelIndex source_index = mapToSource(index);
2039 if (index.isValid() && !source_index.isValid())
2040 return QSize();
2041 return d->model->span(source_index);
2042 }
2043
2044 /*!
2045 \reimp
2046 */
sort(int column,Qt::SortOrder order)2047 void QSortFilterProxyModel::sort(int column, Qt::SortOrder order)
2048 {
2049 Q_D(QSortFilterProxyModel);
2050 if (d->dynamic_sortfilter && d->proxy_sort_column == column && d->sort_order == order)
2051 return;
2052 d->sort_order = order;
2053 d->proxy_sort_column = column;
2054 d->update_source_sort_column();
2055 d->sort();
2056 }
2057
2058 /*!
2059 \since 4.5
2060 \brief the column currently used for sorting
2061
2062 This returns the most recently used sort column.
2063 */
sortColumn() const2064 int QSortFilterProxyModel::sortColumn() const
2065 {
2066 Q_D(const QSortFilterProxyModel);
2067 return d->proxy_sort_column;
2068 }
2069
2070 /*!
2071 \since 4.5
2072 \brief the order currently used for sorting
2073
2074 This returns the most recently used sort order.
2075 */
sortOrder() const2076 Qt::SortOrder QSortFilterProxyModel::sortOrder() const
2077 {
2078 Q_D(const QSortFilterProxyModel);
2079 return d->sort_order;
2080 }
2081
2082 /*!
2083 \property QSortFilterProxyModel::filterRegExp
2084 \brief the QRegExp used to filter the contents of the source model
2085
2086 Setting this property overwrites the current
2087 \l{QSortFilterProxyModel::filterCaseSensitivity}{filterCaseSensitivity}.
2088 By default, the QRegExp is an empty string matching all contents.
2089
2090 If no QRegExp or an empty string is set, everything in the source model
2091 will be accepted.
2092
2093 \sa filterCaseSensitivity, setFilterWildcard(), setFilterFixedString()
2094 */
filterRegExp() const2095 QRegExp QSortFilterProxyModel::filterRegExp() const
2096 {
2097 Q_D(const QSortFilterProxyModel);
2098 return d->filter_regexp;
2099 }
2100
setFilterRegExp(const QRegExp & regExp)2101 void QSortFilterProxyModel::setFilterRegExp(const QRegExp ®Exp)
2102 {
2103 Q_D(QSortFilterProxyModel);
2104 d->filter_regexp = regExp;
2105 d->filter_changed();
2106 }
2107
2108 /*!
2109 \property QSortFilterProxyModel::filterKeyColumn
2110 \brief the column where the key used to filter the contents of the
2111 source model is read from.
2112
2113 The default value is 0. If the value is -1, the keys will be read
2114 from all columns.
2115 */
filterKeyColumn() const2116 int QSortFilterProxyModel::filterKeyColumn() const
2117 {
2118 Q_D(const QSortFilterProxyModel);
2119 return d->filter_column;
2120 }
2121
setFilterKeyColumn(int column)2122 void QSortFilterProxyModel::setFilterKeyColumn(int column)
2123 {
2124 Q_D(QSortFilterProxyModel);
2125 d->filter_column = column;
2126 d->filter_changed();
2127 }
2128
2129 /*!
2130 \property QSortFilterProxyModel::filterCaseSensitivity
2131
2132 \brief the case sensitivity of the QRegExp pattern used to filter the
2133 contents of the source model
2134
2135 By default, the filter is case sensitive.
2136
2137 \sa filterRegExp, sortCaseSensitivity
2138 */
filterCaseSensitivity() const2139 Qt::CaseSensitivity QSortFilterProxyModel::filterCaseSensitivity() const
2140 {
2141 Q_D(const QSortFilterProxyModel);
2142 return d->filter_regexp.caseSensitivity();
2143 }
2144
setFilterCaseSensitivity(Qt::CaseSensitivity cs)2145 void QSortFilterProxyModel::setFilterCaseSensitivity(Qt::CaseSensitivity cs)
2146 {
2147 Q_D(QSortFilterProxyModel);
2148 if (cs == d->filter_regexp.caseSensitivity())
2149 return;
2150 d->filter_regexp.setCaseSensitivity(cs);
2151 d->filter_changed();
2152 }
2153
2154 /*!
2155 \since 4.2
2156 \property QSortFilterProxyModel::sortCaseSensitivity
2157 \brief the case sensitivity setting used for comparing strings when sorting
2158
2159 By default, sorting is case sensitive.
2160
2161 \sa filterCaseSensitivity, lessThan()
2162 */
sortCaseSensitivity() const2163 Qt::CaseSensitivity QSortFilterProxyModel::sortCaseSensitivity() const
2164 {
2165 Q_D(const QSortFilterProxyModel);
2166 return d->sort_casesensitivity;
2167 }
2168
setSortCaseSensitivity(Qt::CaseSensitivity cs)2169 void QSortFilterProxyModel::setSortCaseSensitivity(Qt::CaseSensitivity cs)
2170 {
2171 Q_D(QSortFilterProxyModel);
2172 if (d->sort_casesensitivity == cs)
2173 return;
2174
2175 d->sort_casesensitivity = cs;
2176 d->sort();
2177 }
2178
2179 /*!
2180 \since 4.3
2181 \property QSortFilterProxyModel::isSortLocaleAware
2182 \brief the local aware setting used for comparing strings when sorting
2183
2184 By default, sorting is not local aware.
2185
2186 \sa sortCaseSensitivity, lessThan()
2187 */
isSortLocaleAware() const2188 bool QSortFilterProxyModel::isSortLocaleAware() const
2189 {
2190 Q_D(const QSortFilterProxyModel);
2191 return d->sort_localeaware;
2192 }
2193
setSortLocaleAware(bool on)2194 void QSortFilterProxyModel::setSortLocaleAware(bool on)
2195 {
2196 Q_D(QSortFilterProxyModel);
2197 if (d->sort_localeaware == on)
2198 return;
2199
2200 d->sort_localeaware = on;
2201 d->sort();
2202 }
2203
2204 /*!
2205 \overload
2206
2207 Sets the regular expression used to filter the contents
2208 of the source model to \a pattern.
2209
2210 \sa setFilterCaseSensitivity(), setFilterWildcard(), setFilterFixedString(), filterRegExp()
2211 */
setFilterRegExp(const QString & pattern)2212 void QSortFilterProxyModel::setFilterRegExp(const QString &pattern)
2213 {
2214 Q_D(QSortFilterProxyModel);
2215 d->filter_regexp.setPatternSyntax(QRegExp::RegExp);
2216 d->filter_regexp.setPattern(pattern);
2217 d->filter_changed();
2218 }
2219
2220 /*!
2221 Sets the wildcard expression used to filter the contents
2222 of the source model to the given \a pattern.
2223
2224 \sa setFilterCaseSensitivity(), setFilterRegExp(), setFilterFixedString(), filterRegExp()
2225 */
setFilterWildcard(const QString & pattern)2226 void QSortFilterProxyModel::setFilterWildcard(const QString &pattern)
2227 {
2228 Q_D(QSortFilterProxyModel);
2229 d->filter_regexp.setPatternSyntax(QRegExp::Wildcard);
2230 d->filter_regexp.setPattern(pattern);
2231 d->filter_changed();
2232 }
2233
2234 /*!
2235 Sets the fixed string used to filter the contents
2236 of the source model to the given \a pattern.
2237
2238 \sa setFilterCaseSensitivity(), setFilterRegExp(), setFilterWildcard(), filterRegExp()
2239 */
setFilterFixedString(const QString & pattern)2240 void QSortFilterProxyModel::setFilterFixedString(const QString &pattern)
2241 {
2242 Q_D(QSortFilterProxyModel);
2243 d->filter_regexp.setPatternSyntax(QRegExp::FixedString);
2244 d->filter_regexp.setPattern(pattern);
2245 d->filter_changed();
2246 }
2247
2248 /*!
2249 \since 4.2
2250 \property QSortFilterProxyModel::dynamicSortFilter
2251 \brief whether the proxy model is dynamically sorted and filtered
2252 whenever the contents of the source model change
2253
2254 Note that you should not update the source model through the proxy
2255 model when dynamicSortFilter is true. For instance, if you set the
2256 proxy model on a QComboBox, then using functions that update the
2257 model, e.g., \l{QComboBox::}{addItem()}, will not work as
2258 expected. An alternative is to set dynamicSortFilter to false and
2259 call \l{QSortFilterProxyModel::}{sort()} after adding items to the
2260 QComboBox.
2261
2262 The default value is false.
2263 */
dynamicSortFilter() const2264 bool QSortFilterProxyModel::dynamicSortFilter() const
2265 {
2266 Q_D(const QSortFilterProxyModel);
2267 return d->dynamic_sortfilter;
2268 }
2269
setDynamicSortFilter(bool enable)2270 void QSortFilterProxyModel::setDynamicSortFilter(bool enable)
2271 {
2272 Q_D(QSortFilterProxyModel);
2273 d->dynamic_sortfilter = enable;
2274 if (enable)
2275 d->sort();
2276 }
2277
2278 /*!
2279 \since 4.2
2280 \property QSortFilterProxyModel::sortRole
2281 \brief the item role that is used to query the source model's data when sorting items
2282
2283 The default value is Qt::DisplayRole.
2284
2285 \sa lessThan()
2286 */
sortRole() const2287 int QSortFilterProxyModel::sortRole() const
2288 {
2289 Q_D(const QSortFilterProxyModel);
2290 return d->sort_role;
2291 }
2292
setSortRole(int role)2293 void QSortFilterProxyModel::setSortRole(int role)
2294 {
2295 Q_D(QSortFilterProxyModel);
2296 if (d->sort_role == role)
2297 return;
2298 d->sort_role = role;
2299 d->sort();
2300 }
2301
2302 /*!
2303 \since 4.2
2304 \property QSortFilterProxyModel::filterRole
2305 \brief the item role that is used to query the source model's data when filtering items
2306
2307 The default value is Qt::DisplayRole.
2308
2309 \sa filterAcceptsRow()
2310 */
filterRole() const2311 int QSortFilterProxyModel::filterRole() const
2312 {
2313 Q_D(const QSortFilterProxyModel);
2314 return d->filter_role;
2315 }
2316
setFilterRole(int role)2317 void QSortFilterProxyModel::setFilterRole(int role)
2318 {
2319 Q_D(QSortFilterProxyModel);
2320 if (d->filter_role == role)
2321 return;
2322 d->filter_role = role;
2323 d->filter_changed();
2324 }
2325
2326 /*!
2327 \obsolete
2328
2329 This function is obsolete. Use invalidate() instead.
2330 */
clear()2331 void QSortFilterProxyModel::clear()
2332 {
2333 Q_D(QSortFilterProxyModel);
2334 emit layoutAboutToBeChanged();
2335 d->_q_clearMapping();
2336 emit layoutChanged();
2337 }
2338
2339 /*!
2340 \since 4.3
2341
2342 Invalidates the current sorting and filtering.
2343
2344 \sa invalidateFilter()
2345 */
invalidate()2346 void QSortFilterProxyModel::invalidate()
2347 {
2348 Q_D(QSortFilterProxyModel);
2349 emit layoutAboutToBeChanged();
2350 d->_q_clearMapping();
2351 emit layoutChanged();
2352 }
2353
2354 /*!
2355 \obsolete
2356
2357 This function is obsolete. Use invalidateFilter() instead.
2358 */
filterChanged()2359 void QSortFilterProxyModel::filterChanged()
2360 {
2361 Q_D(QSortFilterProxyModel);
2362 d->filter_changed();
2363 }
2364
2365 /*!
2366 \since 4.3
2367
2368 Invalidates the current filtering.
2369
2370 This function should be called if you are implementing custom filtering
2371 (e.g. filterAcceptsRow()), and your filter parameters have changed.
2372
2373 \sa invalidate()
2374 */
invalidateFilter()2375 void QSortFilterProxyModel::invalidateFilter()
2376 {
2377 Q_D(QSortFilterProxyModel);
2378 d->filter_changed();
2379 }
2380
2381 /*!
2382 Returns true if the value of the item referred to by the given
2383 index \a left is less than the value of the item referred to by
2384 the given index \a right, otherwise returns false.
2385
2386 This function is used as the < operator when sorting, and handles
2387 the following QVariant types:
2388
2389 \list
2390 \o QVariant::Int
2391 \o QVariant::UInt
2392 \o QVariant::LongLong
2393 \o QVariant::ULongLong
2394 \o QVariant::Double
2395 \o QVariant::Char
2396 \o QVariant::Date
2397 \o QVariant::Time
2398 \o QVariant::DateTime
2399 \o QVariant::String
2400 \endlist
2401
2402 Any other type will be converted to a QString using
2403 QVariant::toString().
2404
2405 Comparison of \l{QString}s is case sensitive by default; this can
2406 be changed using the \l {QSortFilterProxyModel::sortCaseSensitivity}
2407 {sortCaseSensitivity} property.
2408
2409 By default, the Qt::DisplayRole associated with the
2410 \l{QModelIndex}es is used for comparisons. This can be changed by
2411 setting the \l {QSortFilterProxyModel::sortRole} {sortRole} property.
2412
2413 \note The indices passed in correspond to the source model.
2414
2415 \sa sortRole, sortCaseSensitivity, dynamicSortFilter
2416 */
lessThan(const QModelIndex & left,const QModelIndex & right) const2417 bool QSortFilterProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
2418 {
2419 Q_D(const QSortFilterProxyModel);
2420 QVariant l = (left.model() ? left.model()->data(left, d->sort_role) : QVariant());
2421 QVariant r = (right.model() ? right.model()->data(right, d->sort_role) : QVariant());
2422 switch (l.userType()) {
2423 case QVariant::Invalid:
2424 return (r.type() != QVariant::Invalid);
2425 case QVariant::Int:
2426 return l.toInt() < r.toInt();
2427 case QVariant::UInt:
2428 return l.toUInt() < r.toUInt();
2429 case QVariant::LongLong:
2430 return l.toLongLong() < r.toLongLong();
2431 case QVariant::ULongLong:
2432 return l.toULongLong() < r.toULongLong();
2433 case QMetaType::Float:
2434 return l.toFloat() < r.toFloat();
2435 case QVariant::Double:
2436 return l.toDouble() < r.toDouble();
2437 case QVariant::Char:
2438 return l.toChar() < r.toChar();
2439 case QVariant::Date:
2440 return l.toDate() < r.toDate();
2441 case QVariant::Time:
2442 return l.toTime() < r.toTime();
2443 case QVariant::DateTime:
2444 return l.toDateTime() < r.toDateTime();
2445 case QVariant::String:
2446 default:
2447 if (d->sort_localeaware)
2448 return l.toString().localeAwareCompare(r.toString()) < 0;
2449 else
2450 return l.toString().compare(r.toString(), d->sort_casesensitivity) < 0;
2451 }
2452 return false;
2453 }
2454
2455 /*!
2456 Returns true if the item in the row indicated by the given \a source_row
2457 and \a source_parent should be included in the model; otherwise returns
2458 false.
2459
2460 The default implementation returns true if the value held by the relevant item
2461 matches the filter string, wildcard string or regular expression.
2462
2463 \note By default, the Qt::DisplayRole is used to determine if the row
2464 should be accepted or not. This can be changed by setting the
2465 \l{QSortFilterProxyModel::filterRole}{filterRole} property.
2466
2467 \sa filterAcceptsColumn(), setFilterFixedString(), setFilterRegExp(), setFilterWildcard()
2468 */
filterAcceptsRow(int source_row,const QModelIndex & source_parent) const2469 bool QSortFilterProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
2470 {
2471 Q_D(const QSortFilterProxyModel);
2472 if (d->filter_regexp.isEmpty())
2473 return true;
2474 if (d->filter_column == -1) {
2475 int column_count = d->model->columnCount(source_parent);
2476 for (int column = 0; column < column_count; ++column) {
2477 QModelIndex source_index = d->model->index(source_row, column, source_parent);
2478 QString key = d->model->data(source_index, d->filter_role).toString();
2479 if (key.contains(d->filter_regexp))
2480 return true;
2481 }
2482 return false;
2483 }
2484 QModelIndex source_index = d->model->index(source_row, d->filter_column, source_parent);
2485 if (!source_index.isValid()) // the column may not exist
2486 return true;
2487 QString key = d->model->data(source_index, d->filter_role).toString();
2488 return key.contains(d->filter_regexp);
2489 }
2490
2491 /*!
2492 Returns true if the item in the column indicated by the given \a source_column
2493 and \a source_parent should be included in the model; otherwise returns false.
2494
2495 The default implementation returns true if the value held by the relevant item
2496 matches the filter string, wildcard string or regular expression.
2497
2498 \note By default, the Qt::DisplayRole is used to determine if the row
2499 should be accepted or not. This can be changed by setting the \l
2500 filterRole property.
2501
2502 \sa filterAcceptsRow(), setFilterFixedString(), setFilterRegExp(), setFilterWildcard()
2503 */
filterAcceptsColumn(int source_column,const QModelIndex & source_parent) const2504 bool QSortFilterProxyModel::filterAcceptsColumn(int source_column, const QModelIndex &source_parent) const
2505 {
2506 Q_UNUSED(source_column);
2507 Q_UNUSED(source_parent);
2508 return true;
2509 }
2510
2511 /*!
2512 Returns the source model index corresponding to the given \a
2513 proxyIndex from the sorting filter model.
2514
2515 \sa mapFromSource()
2516 */
mapToSource(const QModelIndex & proxyIndex) const2517 QModelIndex QSortFilterProxyModel::mapToSource(const QModelIndex &proxyIndex) const
2518 {
2519 Q_D(const QSortFilterProxyModel);
2520 return d->proxy_to_source(proxyIndex);
2521 }
2522
2523 /*!
2524 Returns the model index in the QSortFilterProxyModel given the \a
2525 sourceIndex from the source model.
2526
2527 \sa mapToSource()
2528 */
mapFromSource(const QModelIndex & sourceIndex) const2529 QModelIndex QSortFilterProxyModel::mapFromSource(const QModelIndex &sourceIndex) const
2530 {
2531 Q_D(const QSortFilterProxyModel);
2532 return d->source_to_proxy(sourceIndex);
2533 }
2534
2535 /*!
2536 \reimp
2537 */
mapSelectionToSource(const QItemSelection & proxySelection) const2538 QItemSelection QSortFilterProxyModel::mapSelectionToSource(const QItemSelection &proxySelection) const
2539 {
2540 return QAbstractProxyModel::mapSelectionToSource(proxySelection);
2541 }
2542
2543 /*!
2544 \reimp
2545 */
mapSelectionFromSource(const QItemSelection & sourceSelection) const2546 QItemSelection QSortFilterProxyModel::mapSelectionFromSource(const QItemSelection &sourceSelection) const
2547 {
2548 return QAbstractProxyModel::mapSelectionFromSource(sourceSelection);
2549 }
2550
2551 /*!
2552 \fn QObject *QSortFilterProxyModel::parent() const
2553 \internal
2554 */
2555
2556 QT_END_NAMESPACE
2557
2558 #include "moc_qsortfilterproxymodel.cpp"
2559
2560 #endif // QT_NO_SORTFILTERPROXYMODEL
2561