1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtCore module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #include "qsortfilterproxymodel.h"
41 #include "qitemselectionmodel.h"
42 #include <qsize.h>
43 #include <qdebug.h>
44 #include <qdatetime.h>
45 #include <qpair.h>
46 #include <qstringlist.h>
47 #include <private/qabstractitemmodel_p.h>
48 #include <private/qabstractproxymodel_p.h>
49 
50 #include <algorithm>
51 
52 QT_BEGIN_NAMESPACE
53 
54 typedef QVector<QPair<QModelIndex, QPersistentModelIndex> > QModelIndexPairList;
55 
56 struct QSortFilterProxyModelDataChanged
57 {
QSortFilterProxyModelDataChangedQSortFilterProxyModelDataChanged58     QSortFilterProxyModelDataChanged(const QModelIndex &tl, const QModelIndex &br)
59         : topLeft(tl), bottomRight(br) { }
60 
61     QModelIndex topLeft;
62     QModelIndex bottomRight;
63 };
64 
qVectorToSet(const QVector<int> & vector)65 static inline QSet<int> qVectorToSet(const QVector<int> &vector)
66 {
67     return {vector.begin(), vector.end()};
68 }
69 
70 class QSortFilterProxyModelLessThan
71 {
72 public:
QSortFilterProxyModelLessThan(int column,const QModelIndex & parent,const QAbstractItemModel * source,const QSortFilterProxyModel * proxy)73     inline QSortFilterProxyModelLessThan(int column, const QModelIndex &parent,
74                                        const QAbstractItemModel *source,
75                                        const QSortFilterProxyModel *proxy)
76         : sort_column(column), source_parent(parent), source_model(source), proxy_model(proxy) {}
77 
operator ()(int r1,int r2) const78     inline bool operator()(int r1, int r2) const
79     {
80         QModelIndex i1 = source_model->index(r1, sort_column, source_parent);
81         QModelIndex i2 = source_model->index(r2, sort_column, source_parent);
82         return proxy_model->lessThan(i1, i2);
83     }
84 
85 private:
86     int sort_column;
87     QModelIndex source_parent;
88     const QAbstractItemModel *source_model;
89     const QSortFilterProxyModel *proxy_model;
90 };
91 
92 class QSortFilterProxyModelGreaterThan
93 {
94 public:
QSortFilterProxyModelGreaterThan(int column,const QModelIndex & parent,const QAbstractItemModel * source,const QSortFilterProxyModel * proxy)95     inline QSortFilterProxyModelGreaterThan(int column, const QModelIndex &parent,
96                                           const QAbstractItemModel *source,
97                                           const QSortFilterProxyModel *proxy)
98         : sort_column(column), source_parent(parent),
99           source_model(source), proxy_model(proxy) {}
100 
operator ()(int r1,int r2) const101     inline bool operator()(int r1, int r2) const
102     {
103         QModelIndex i1 = source_model->index(r1, sort_column, source_parent);
104         QModelIndex i2 = source_model->index(r2, sort_column, source_parent);
105         return proxy_model->lessThan(i2, i1);
106     }
107 
108 private:
109     int sort_column;
110     QModelIndex source_parent;
111     const QAbstractItemModel *source_model;
112     const QSortFilterProxyModel *proxy_model;
113 };
114 
115 
116 //this struct is used to store what are the rows that are removed
117 //between a call to rowsAboutToBeRemoved and rowsRemoved
118 //it avoids readding rows to the mapping that are currently being removed
119 struct QRowsRemoval
120 {
QRowsRemovalQRowsRemoval121     QRowsRemoval(const QModelIndex &parent_source, int start, int end) : parent_source(parent_source), start(start), end(end)
122     {
123     }
124 
QRowsRemovalQRowsRemoval125     QRowsRemoval() : start(-1), end(-1)
126     {
127     }
128 
containsQRowsRemoval129     bool contains(QModelIndex parent, int row) const
130     {
131         do {
132             if (parent == parent_source)
133                 return row >= start && row <= end;
134             row = parent.row();
135             parent = parent.parent();
136         } while (row >= 0);
137         return false;
138     }
139 private:
140     QModelIndex parent_source;
141     int start;
142     int end;
143 };
144 
145 class RegularExpressionData {
146 
147 private:
148     enum class ExpressionType {
149         RegExp,
150 #if QT_CONFIG(regularexpression)
151         RegularExpression
152 #endif
153     };
154 
155 public:
RegularExpressionData()156     RegularExpressionData() :
157         m_type(ExpressionType::RegExp)
158     {}
159 
160 #if QT_CONFIG(regularexpression)
regularExpression() const161     QRegularExpression regularExpression() const
162     {
163         if (m_type == ExpressionType::RegularExpression)
164             return  m_regularExpression;
165         return QRegularExpression();
166     }
167 
setRegularExpression(const QRegularExpression & rx)168     void setRegularExpression(const QRegularExpression &rx)
169     {
170         m_type = ExpressionType::RegularExpression;
171         m_regularExpression = rx;
172         m_regExp = QRegExp();
173     }
174 #endif
175 
regExp() const176     QRegExp regExp() const
177     {
178         if (m_type == ExpressionType::RegExp)
179             return m_regExp;
180         return QRegExp();
181     }
182 
setRegExp(const QRegExp & rx)183     void setRegExp(const QRegExp &rx)
184     {
185         m_type = ExpressionType::RegExp;
186         m_regExp = rx;
187 #if QT_CONFIG(regularexpression)
188         m_regularExpression = QRegularExpression();
189 #endif
190 
191     }
192 
isEmpty() const193     bool isEmpty() const
194     {
195         bool result = true;
196         switch (m_type) {
197         case ExpressionType::RegExp:
198             result = m_regExp.isEmpty();
199             break;
200 #if QT_CONFIG(regularexpression)
201         case ExpressionType::RegularExpression:
202             result = m_regularExpression.pattern().isEmpty();
203             break;
204 #endif
205         }
206         return result;
207     }
208 
caseSensitivity() const209     Qt::CaseSensitivity caseSensitivity() const
210     {
211         Qt::CaseSensitivity sensitivity = Qt::CaseInsensitive;
212         switch (m_type) {
213         case ExpressionType::RegExp:
214             sensitivity = m_regExp.caseSensitivity();
215             break;
216 #if QT_CONFIG(regularexpression)
217         case ExpressionType::RegularExpression:
218         {
219             QRegularExpression::PatternOptions options = m_regularExpression.patternOptions();
220             if (!(options & QRegularExpression::CaseInsensitiveOption))
221                 sensitivity = Qt::CaseSensitive;
222         }
223             break;
224 #endif
225         }
226         return sensitivity;
227     }
228 
setCaseSensitivity(Qt::CaseSensitivity cs)229     void setCaseSensitivity(Qt::CaseSensitivity cs)
230     {
231         switch (m_type) {
232         case ExpressionType::RegExp:
233             m_regExp.setCaseSensitivity(cs);
234             break;
235 #if QT_CONFIG(regularexpression)
236         case ExpressionType::RegularExpression:
237         {
238             QRegularExpression::PatternOptions options = m_regularExpression.patternOptions();
239             options.setFlag(QRegularExpression::CaseInsensitiveOption, cs == Qt::CaseInsensitive);
240             m_regularExpression.setPatternOptions(options);
241         }
242             break;
243 #endif
244         }
245     }
246 
hasMatch(const QString & str) const247     bool hasMatch(const QString &str) const
248     {
249         bool result = false;
250         switch (m_type) {
251         case ExpressionType::RegExp:
252             result = str.contains(m_regExp);
253             break;
254 #if QT_CONFIG(regularexpression)
255         case ExpressionType::RegularExpression:
256             result = str.contains(m_regularExpression);
257             break;
258 #endif
259         }
260         return result;
261     }
262 
263 private:
264     ExpressionType m_type;
265     QRegExp m_regExp;
266 #if QT_CONFIG(regularexpression)
267     QRegularExpression m_regularExpression;
268 #endif
269 };
270 
271 
272 class QSortFilterProxyModelPrivate : public QAbstractProxyModelPrivate
273 {
274     Q_DECLARE_PUBLIC(QSortFilterProxyModel)
275 
276 public:
277     struct Mapping {
278         QVector<int> source_rows;
279         QVector<int> source_columns;
280         QVector<int> proxy_rows;
281         QVector<int> proxy_columns;
282         QVector<QModelIndex> mapped_children;
283         QHash<QModelIndex, Mapping *>::const_iterator map_iter;
284     };
285 
286     mutable QHash<QModelIndex, Mapping*> source_index_mapping;
287 
288     int source_sort_column;
289     int proxy_sort_column;
290     Qt::SortOrder sort_order;
291     Qt::CaseSensitivity sort_casesensitivity;
292     int sort_role;
293     bool sort_localeaware;
294 
295     int filter_column;
296     int filter_role;
297     RegularExpressionData filter_data;
298     QModelIndex last_top_source;
299 
300     bool filter_recursive;
301     bool complete_insert;
302     bool dynamic_sortfilter;
303     QRowsRemoval itemsBeingRemoved;
304 
305     QModelIndexPairList saved_persistent_indexes;
306     QList<QPersistentModelIndex> saved_layoutChange_parents;
307 
308     QHash<QModelIndex, Mapping *>::const_iterator create_mapping(
309         const QModelIndex &source_parent) const;
310     QHash<QModelIndex, Mapping *>::const_iterator create_mapping_recursive(
311             const QModelIndex &source_parent) const;
312     QModelIndex proxy_to_source(const QModelIndex &proxyIndex) const;
313     QModelIndex source_to_proxy(const QModelIndex &sourceIndex) const;
314     bool can_create_mapping(const QModelIndex &source_parent) const;
315 
316     void remove_from_mapping(const QModelIndex &source_parent);
317 
index_to_iterator(const QModelIndex & proxy_index) const318     inline QHash<QModelIndex, Mapping *>::const_iterator index_to_iterator(
319         const QModelIndex &proxy_index) const
320     {
321         Q_ASSERT(proxy_index.isValid());
322         Q_ASSERT(proxy_index.model() == q_func());
323         const void *p = proxy_index.internalPointer();
324         Q_ASSERT(p);
325         QHash<QModelIndex, Mapping *>::const_iterator it =
326             static_cast<const Mapping*>(p)->map_iter;
327         Q_ASSERT(it != source_index_mapping.constEnd());
328         Q_ASSERT(it.value());
329         return it;
330     }
331 
create_index(int row,int column,QHash<QModelIndex,Mapping * >::const_iterator it) const332     inline QModelIndex create_index(int row, int column,
333                                     QHash<QModelIndex, Mapping*>::const_iterator it) const
334     {
335         return q_func()->createIndex(row, column, *it);
336     }
337 
338     void _q_sourceDataChanged(const QModelIndex &source_top_left,
339                               const QModelIndex &source_bottom_right,
340                               const QVector<int> &roles);
341     void _q_sourceHeaderDataChanged(Qt::Orientation orientation, int start, int end);
342 
343     void _q_sourceAboutToBeReset();
344     void _q_sourceReset();
345 
346     void _q_sourceLayoutAboutToBeChanged(const QList<QPersistentModelIndex> &sourceParents, QAbstractItemModel::LayoutChangeHint hint);
347     void _q_sourceLayoutChanged(const QList<QPersistentModelIndex> &sourceParents, QAbstractItemModel::LayoutChangeHint hint);
348 
349     void _q_sourceRowsAboutToBeInserted(const QModelIndex &source_parent,
350                                         int start, int end);
351     void _q_sourceRowsInserted(const QModelIndex &source_parent,
352                                int start, int end);
353     void _q_sourceRowsAboutToBeRemoved(const QModelIndex &source_parent,
354                                        int start, int end);
355     void _q_sourceRowsRemoved(const QModelIndex &source_parent,
356                               int start, int end);
357     void _q_sourceRowsAboutToBeMoved(const QModelIndex &sourceParent,
358                                      int sourceStart, int sourceEnd,
359                                      const QModelIndex &destParent, int dest);
360     void _q_sourceRowsMoved(const QModelIndex &sourceParent,
361                             int sourceStart, int sourceEnd,
362                             const QModelIndex &destParent, int dest);
363     void _q_sourceColumnsAboutToBeInserted(const QModelIndex &source_parent,
364                                            int start, int end);
365     void _q_sourceColumnsInserted(const QModelIndex &source_parent,
366                                   int start, int end);
367     void _q_sourceColumnsAboutToBeRemoved(const QModelIndex &source_parent,
368                                           int start, int end);
369     void _q_sourceColumnsRemoved(const QModelIndex &source_parent,
370                                  int start, int end);
371     void _q_sourceColumnsAboutToBeMoved(const QModelIndex &sourceParent,
372                                         int sourceStart, int sourceEnd,
373                                         const QModelIndex &destParent, int dest);
374     void _q_sourceColumnsMoved(const QModelIndex &sourceParent,
375                                int sourceStart, int sourceEnd,
376                                const QModelIndex &destParent, int dest);
377 
378     void _q_clearMapping();
379 
380     void sort();
381     bool update_source_sort_column();
382     int find_source_sort_column() const;
383     void sort_source_rows(QVector<int> &source_rows,
384                           const QModelIndex &source_parent) const;
385     QVector<QPair<int, QVector<int > > > proxy_intervals_for_source_items_to_add(
386         const QVector<int> &proxy_to_source, const QVector<int> &source_items,
387         const QModelIndex &source_parent, Qt::Orientation orient) const;
388     QVector<QPair<int, int > > proxy_intervals_for_source_items(
389         const QVector<int> &source_to_proxy, const QVector<int> &source_items) const;
390     void insert_source_items(
391         QVector<int> &source_to_proxy, QVector<int> &proxy_to_source,
392         const QVector<int> &source_items, const QModelIndex &source_parent,
393         Qt::Orientation orient, bool emit_signal = true);
394     void remove_source_items(
395         QVector<int> &source_to_proxy, QVector<int> &proxy_to_source,
396         const QVector<int> &source_items, const QModelIndex &source_parent,
397         Qt::Orientation orient, bool emit_signal = true);
398     void remove_proxy_interval(
399         QVector<int> &source_to_proxy, QVector<int> &proxy_to_source,
400         int proxy_start, int proxy_end, const QModelIndex &proxy_parent,
401         Qt::Orientation orient, bool emit_signal = true);
402     void build_source_to_proxy_mapping(
403         const QVector<int> &proxy_to_source, QVector<int> &source_to_proxy) const;
404     void source_items_inserted(const QModelIndex &source_parent,
405                                int start, int end, Qt::Orientation orient);
406     void source_items_about_to_be_removed(const QModelIndex &source_parent,
407                                           int start, int end, Qt::Orientation orient);
408     void source_items_removed(const QModelIndex &source_parent,
409                               int start, int end, Qt::Orientation orient);
410     void proxy_item_range(
411         const QVector<int> &source_to_proxy, const QVector<int> &source_items,
412         int &proxy_low, int &proxy_high) const;
413 
414     QModelIndexPairList store_persistent_indexes() const;
415     void update_persistent_indexes(const QModelIndexPairList &source_indexes);
416 
417     void filter_about_to_be_changed(const QModelIndex &source_parent = QModelIndex());
418     void filter_changed(const QModelIndex &source_parent = QModelIndex());
419     QSet<int> handle_filter_changed(
420         QVector<int> &source_to_proxy, QVector<int> &proxy_to_source,
421         const QModelIndex &source_parent, Qt::Orientation orient);
422 
423     void updateChildrenMapping(const QModelIndex &source_parent, Mapping *parent_mapping,
424                                Qt::Orientation orient, int start, int end, int delta_item_count, bool remove);
425 
426     void _q_sourceModelDestroyed() override;
427 
428     bool needsReorder(const QVector<int> &source_rows, const QModelIndex &source_parent) const;
429 
430     bool filterAcceptsRowInternal(int source_row, const QModelIndex &source_parent) const;
431     bool filterRecursiveAcceptsRow(int source_row, const QModelIndex &source_parent) const;
432 };
433 
434 typedef QHash<QModelIndex, QSortFilterProxyModelPrivate::Mapping *> IndexMap;
435 
_q_sourceModelDestroyed()436 void QSortFilterProxyModelPrivate::_q_sourceModelDestroyed()
437 {
438     QAbstractProxyModelPrivate::_q_sourceModelDestroyed();
439     qDeleteAll(source_index_mapping);
440     source_index_mapping.clear();
441 }
442 
filterAcceptsRowInternal(int source_row,const QModelIndex & source_parent) const443 bool QSortFilterProxyModelPrivate::filterAcceptsRowInternal(int source_row, const QModelIndex &source_parent) const
444 {
445     Q_Q(const QSortFilterProxyModel);
446     return filter_recursive
447             ? filterRecursiveAcceptsRow(source_row, source_parent)
448             : q->filterAcceptsRow(source_row, source_parent);
449 }
450 
filterRecursiveAcceptsRow(int source_row,const QModelIndex & source_parent) const451 bool QSortFilterProxyModelPrivate::filterRecursiveAcceptsRow(int source_row, const QModelIndex &source_parent) const
452 {
453     Q_Q(const QSortFilterProxyModel);
454 
455     if (q->filterAcceptsRow(source_row, source_parent))
456         return true;
457 
458     const QModelIndex index = model->index(source_row, 0, source_parent);
459     const int count = model->rowCount(index);
460 
461     for (int i = 0; i < count; ++i) {
462         if (filterRecursiveAcceptsRow(i, index))
463             return true;
464     }
465 
466     return false;
467 }
468 
remove_from_mapping(const QModelIndex & source_parent)469 void QSortFilterProxyModelPrivate::remove_from_mapping(const QModelIndex &source_parent)
470 {
471     if (Mapping *m = source_index_mapping.take(source_parent)) {
472         for (const QModelIndex &mappedIdx : qAsConst(m->mapped_children))
473             remove_from_mapping(mappedIdx);
474         delete m;
475     }
476 }
477 
_q_clearMapping()478 void QSortFilterProxyModelPrivate::_q_clearMapping()
479 {
480     // store the persistent indexes
481     QModelIndexPairList source_indexes = store_persistent_indexes();
482 
483     qDeleteAll(source_index_mapping);
484     source_index_mapping.clear();
485     if (dynamic_sortfilter)
486         source_sort_column = find_source_sort_column();
487 
488     // update the persistent indexes
489     update_persistent_indexes(source_indexes);
490 }
491 
create_mapping(const QModelIndex & source_parent) const492 IndexMap::const_iterator QSortFilterProxyModelPrivate::create_mapping(
493     const QModelIndex &source_parent) const
494 {
495     Q_Q(const QSortFilterProxyModel);
496 
497     IndexMap::const_iterator it = source_index_mapping.constFind(source_parent);
498     if (it != source_index_mapping.constEnd()) // was mapped already
499         return it;
500 
501     Mapping *m = new Mapping;
502 
503     int source_rows = model->rowCount(source_parent);
504     m->source_rows.reserve(source_rows);
505     for (int i = 0; i < source_rows; ++i) {
506         if (filterAcceptsRowInternal(i, source_parent))
507             m->source_rows.append(i);
508     }
509     int source_cols = model->columnCount(source_parent);
510     m->source_columns.reserve(source_cols);
511     for (int i = 0; i < source_cols; ++i) {
512         if (q->filterAcceptsColumn(i, source_parent))
513             m->source_columns.append(i);
514     }
515 
516     sort_source_rows(m->source_rows, source_parent);
517     m->proxy_rows.resize(source_rows);
518     build_source_to_proxy_mapping(m->source_rows, m->proxy_rows);
519     m->proxy_columns.resize(source_cols);
520     build_source_to_proxy_mapping(m->source_columns, m->proxy_columns);
521 
522     it = IndexMap::const_iterator(source_index_mapping.insert(source_parent, m));
523     m->map_iter = it;
524 
525     if (source_parent.isValid()) {
526         QModelIndex source_grand_parent = source_parent.parent();
527         IndexMap::const_iterator it2 = create_mapping(source_grand_parent);
528         Q_ASSERT(it2 != source_index_mapping.constEnd());
529         it2.value()->mapped_children.append(source_parent);
530     }
531 
532     Q_ASSERT(it != source_index_mapping.constEnd());
533     Q_ASSERT(it.value());
534 
535     return it;
536 }
537 
538 // Go up the tree, creating mappings, unless of course the parent is filtered out
create_mapping_recursive(const QModelIndex & source_parent) const539 IndexMap::const_iterator QSortFilterProxyModelPrivate::create_mapping_recursive(const QModelIndex &source_parent) const
540 {
541     if (source_parent.isValid()) {
542         const QModelIndex source_grand_parent = source_parent.parent();
543         IndexMap::const_iterator it = source_index_mapping.constFind(source_grand_parent);
544         IndexMap::const_iterator end = source_index_mapping.constEnd();
545         if (it == end) {
546             it = create_mapping_recursive(source_grand_parent);
547             end = source_index_mapping.constEnd();
548             if (it == end)
549                 return end;
550         }
551         Mapping *gm = it.value();
552         if (gm->proxy_rows.at(source_parent.row()) == -1 ||
553                 gm->proxy_columns.at(source_parent.column()) == -1) {
554             // Can't do, parent is filtered
555             return end;
556         }
557     }
558     return create_mapping(source_parent);
559 }
560 
proxy_to_source(const QModelIndex & proxy_index) const561 QModelIndex QSortFilterProxyModelPrivate::proxy_to_source(const QModelIndex &proxy_index) const
562 {
563     if (!proxy_index.isValid())
564         return QModelIndex(); // for now; we may want to be able to set a root index later
565     if (proxy_index.model() != q_func()) {
566         qWarning("QSortFilterProxyModel: index from wrong model passed to mapToSource");
567         Q_ASSERT(!"QSortFilterProxyModel: index from wrong model passed to mapToSource");
568         return QModelIndex();
569     }
570     IndexMap::const_iterator it = index_to_iterator(proxy_index);
571     Mapping *m = it.value();
572     if ((proxy_index.row() >= m->source_rows.size()) || (proxy_index.column() >= m->source_columns.size()))
573         return QModelIndex();
574     int source_row = m->source_rows.at(proxy_index.row());
575     int source_col = m->source_columns.at(proxy_index.column());
576     return model->index(source_row, source_col, it.key());
577 }
578 
source_to_proxy(const QModelIndex & source_index) const579 QModelIndex QSortFilterProxyModelPrivate::source_to_proxy(const QModelIndex &source_index) const
580 {
581     if (!source_index.isValid())
582         return QModelIndex(); // for now; we may want to be able to set a root index later
583     if (source_index.model() != model) {
584         qWarning("QSortFilterProxyModel: index from wrong model passed to mapFromSource");
585         Q_ASSERT(!"QSortFilterProxyModel: index from wrong model passed to mapFromSource");
586         return QModelIndex();
587     }
588     QModelIndex source_parent = source_index.parent();
589     IndexMap::const_iterator it = create_mapping(source_parent);
590     Mapping *m = it.value();
591     if ((source_index.row() >= m->proxy_rows.size()) || (source_index.column() >= m->proxy_columns.size()))
592         return QModelIndex();
593     int proxy_row = m->proxy_rows.at(source_index.row());
594     int proxy_column = m->proxy_columns.at(source_index.column());
595     if (proxy_row == -1 || proxy_column == -1)
596         return QModelIndex();
597     return create_index(proxy_row, proxy_column, it);
598 }
599 
can_create_mapping(const QModelIndex & source_parent) const600 bool QSortFilterProxyModelPrivate::can_create_mapping(const QModelIndex &source_parent) const
601 {
602     if (source_parent.isValid()) {
603         QModelIndex source_grand_parent = source_parent.parent();
604         IndexMap::const_iterator it = source_index_mapping.constFind(source_grand_parent);
605         if (it == source_index_mapping.constEnd()) {
606             // Don't care, since we don't have mapping for the grand parent
607             return false;
608         }
609         Mapping *gm = it.value();
610         if (gm->proxy_rows.at(source_parent.row()) == -1 ||
611             gm->proxy_columns.at(source_parent.column()) == -1) {
612             // Don't care, since parent is filtered
613             return false;
614         }
615     }
616     return true;
617 }
618 
619 /*!
620   \internal
621 
622   Sorts the existing mappings.
623 */
sort()624 void QSortFilterProxyModelPrivate::sort()
625 {
626     Q_Q(QSortFilterProxyModel);
627     emit q->layoutAboutToBeChanged(QList<QPersistentModelIndex>(), QAbstractItemModel::VerticalSortHint);
628     QModelIndexPairList source_indexes = store_persistent_indexes();
629     const auto end = source_index_mapping.constEnd();
630     for (auto it = source_index_mapping.constBegin(); it != end; ++it) {
631         const QModelIndex &source_parent = it.key();
632         Mapping *m = it.value();
633         sort_source_rows(m->source_rows, source_parent);
634         build_source_to_proxy_mapping(m->source_rows, m->proxy_rows);
635     }
636     update_persistent_indexes(source_indexes);
637     emit q->layoutChanged(QList<QPersistentModelIndex>(), QAbstractItemModel::VerticalSortHint);
638 }
639 
640 /*!
641   \internal
642 
643     update the source_sort_column according to the proxy_sort_column
644     return true if the column was changed
645 */
update_source_sort_column()646 bool QSortFilterProxyModelPrivate::update_source_sort_column()
647 {
648     int old_source_sort_column = source_sort_column;
649 
650     if (proxy_sort_column == -1) {
651         source_sort_column = -1;
652     } else {
653         // We cannot use index mapping here because in case of a still-empty
654         // proxy model there's no valid proxy index we could map to source.
655         // So always use the root mapping directly instead.
656         Mapping *m = create_mapping(QModelIndex()).value();
657         if (proxy_sort_column < m->source_columns.size())
658             source_sort_column = m->source_columns.at(proxy_sort_column);
659         else
660             source_sort_column = -1;
661     }
662 
663     return old_source_sort_column != source_sort_column;
664 }
665 
666 /*!
667   \internal
668 
669   Find the source_sort_column without creating a full mapping and
670   without updating anything.
671 */
find_source_sort_column() const672 int QSortFilterProxyModelPrivate::find_source_sort_column() const
673 {
674     if (proxy_sort_column == -1)
675         return -1;
676 
677     const QModelIndex rootIndex;
678     const int source_cols = model->columnCount();
679     int accepted_columns = -1;
680 
681     Q_Q(const QSortFilterProxyModel);
682     for (int i = 0; i < source_cols; ++i) {
683         if (q->filterAcceptsColumn(i, rootIndex)) {
684             if (++accepted_columns == proxy_sort_column)
685                 return i;
686         }
687     }
688 
689     return -1;
690 }
691 
692 /*!
693   \internal
694 
695   Sorts the given \a source_rows according to current sort column and order.
696 */
sort_source_rows(QVector<int> & source_rows,const QModelIndex & source_parent) const697 void QSortFilterProxyModelPrivate::sort_source_rows(
698     QVector<int> &source_rows, const QModelIndex &source_parent) const
699 {
700     Q_Q(const QSortFilterProxyModel);
701     if (source_sort_column >= 0) {
702         if (sort_order == Qt::AscendingOrder) {
703             QSortFilterProxyModelLessThan lt(source_sort_column, source_parent, model, q);
704             std::stable_sort(source_rows.begin(), source_rows.end(), lt);
705         } else {
706             QSortFilterProxyModelGreaterThan gt(source_sort_column, source_parent, model, q);
707             std::stable_sort(source_rows.begin(), source_rows.end(), gt);
708         }
709     } else { // restore the source model order
710         std::stable_sort(source_rows.begin(), source_rows.end());
711     }
712 }
713 
714 /*!
715   \internal
716 
717   Given source-to-proxy mapping \a source_to_proxy and the set of
718   source items \a source_items (which are part of that mapping),
719   determines the corresponding proxy item intervals that should
720   be removed from the proxy model.
721 
722   The result is a vector of pairs, where each pair represents a
723   (start, end) tuple, sorted in ascending order.
724 */
proxy_intervals_for_source_items(const QVector<int> & source_to_proxy,const QVector<int> & source_items) const725 QVector<QPair<int, int > > QSortFilterProxyModelPrivate::proxy_intervals_for_source_items(
726     const QVector<int> &source_to_proxy, const QVector<int> &source_items) const
727 {
728     QVector<QPair<int, int> > proxy_intervals;
729     if (source_items.isEmpty())
730         return proxy_intervals;
731 
732     int source_items_index = 0;
733     while (source_items_index < source_items.size()) {
734         int first_proxy_item = source_to_proxy.at(source_items.at(source_items_index));
735         Q_ASSERT(first_proxy_item != -1);
736         int last_proxy_item = first_proxy_item;
737         ++source_items_index;
738         // Find end of interval
739         while ((source_items_index < source_items.size())
740                && (source_to_proxy.at(source_items.at(source_items_index)) == last_proxy_item + 1)) {
741             ++last_proxy_item;
742             ++source_items_index;
743         }
744         // Add interval to result
745         proxy_intervals.append(QPair<int, int>(first_proxy_item, last_proxy_item));
746     }
747     std::stable_sort(proxy_intervals.begin(), proxy_intervals.end());
748     // Consolidate adjacent intervals
749     for (int i = proxy_intervals.size()-1; i > 0; --i) {
750         QPair<int, int> &interval = proxy_intervals[i];
751         QPair<int, int> &preceeding_interval = proxy_intervals[i - 1];
752         if (interval.first == preceeding_interval.second + 1) {
753             preceeding_interval.second = interval.second;
754             interval.first = interval.second = -1;
755         }
756     }
757     proxy_intervals.erase(
758         std::remove_if(proxy_intervals.begin(), proxy_intervals.end(),
759                        [](QPair<int, int> &interval) { return interval.first < 0; }),
760         proxy_intervals.end());
761     return proxy_intervals;
762 }
763 
764 /*!
765   \internal
766 
767   Given source-to-proxy mapping \a src_to_proxy and proxy-to-source mapping
768   \a proxy_to_source, removes \a source_items from this proxy model.
769   The corresponding proxy items are removed in intervals, so that the proper
770   rows/columnsRemoved(start, end) signals will be generated.
771 */
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)772 void QSortFilterProxyModelPrivate::remove_source_items(
773     QVector<int> &source_to_proxy, QVector<int> &proxy_to_source,
774     const QVector<int> &source_items, const QModelIndex &source_parent,
775     Qt::Orientation orient, bool emit_signal)
776 {
777     Q_Q(QSortFilterProxyModel);
778     QModelIndex proxy_parent = q->mapFromSource(source_parent);
779     if (!proxy_parent.isValid() && source_parent.isValid()) {
780         proxy_to_source.clear();
781         return; // nothing to do (already removed)
782     }
783 
784     const auto proxy_intervals = proxy_intervals_for_source_items(
785         source_to_proxy, source_items);
786 
787     const auto end = proxy_intervals.rend();
788     for (auto it = proxy_intervals.rbegin(); it != end; ++it) {
789         const QPair<int, int> &interval = *it;
790         const int proxy_start = interval.first;
791         const int proxy_end = interval.second;
792         remove_proxy_interval(source_to_proxy, proxy_to_source, proxy_start, proxy_end,
793                               proxy_parent, orient, emit_signal);
794     }
795 }
796 
797 /*!
798   \internal
799 
800   Given source-to-proxy mapping \a source_to_proxy and proxy-to-source mapping
801   \a proxy_to_source, removes items from \a proxy_start to \a proxy_end
802   (inclusive) from this proxy model.
803 */
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)804 void QSortFilterProxyModelPrivate::remove_proxy_interval(
805     QVector<int> &source_to_proxy, QVector<int> &proxy_to_source, int proxy_start, int proxy_end,
806     const QModelIndex &proxy_parent, Qt::Orientation orient, bool emit_signal)
807 {
808     Q_Q(QSortFilterProxyModel);
809     if (emit_signal) {
810         if (orient == Qt::Vertical)
811             q->beginRemoveRows(proxy_parent, proxy_start, proxy_end);
812         else
813             q->beginRemoveColumns(proxy_parent, proxy_start, proxy_end);
814     }
815 
816     // Remove items from proxy-to-source mapping
817     proxy_to_source.remove(proxy_start, proxy_end - proxy_start + 1);
818 
819     build_source_to_proxy_mapping(proxy_to_source, source_to_proxy);
820 
821     if (emit_signal) {
822         if (orient == Qt::Vertical)
823             q->endRemoveRows();
824         else
825             q->endRemoveColumns();
826     }
827 }
828 
829 /*!
830   \internal
831 
832   Given proxy-to-source mapping \a proxy_to_source and a set of
833   unmapped source items \a source_items, determines the proxy item
834   intervals at which the subsets of source items should be inserted
835   (but does not actually add them to the mapping).
836 
837   The result is a vector of pairs, each pair representing a tuple (start,
838   items), where items is a vector containing the (sorted) source items that
839   should be inserted at that proxy model location.
840 */
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) const841 QVector<QPair<int, QVector<int > > > QSortFilterProxyModelPrivate::proxy_intervals_for_source_items_to_add(
842     const QVector<int> &proxy_to_source, const QVector<int> &source_items,
843     const QModelIndex &source_parent, Qt::Orientation orient) const
844 {
845     Q_Q(const QSortFilterProxyModel);
846     QVector<QPair<int, QVector<int> > > proxy_intervals;
847     if (source_items.isEmpty())
848         return proxy_intervals;
849 
850     int proxy_low = 0;
851     int proxy_item = 0;
852     int source_items_index = 0;
853     QVector<int> source_items_in_interval;
854     bool compare = (orient == Qt::Vertical && source_sort_column >= 0 && dynamic_sortfilter);
855     while (source_items_index < source_items.size()) {
856         source_items_in_interval.clear();
857         int first_new_source_item = source_items.at(source_items_index);
858         source_items_in_interval.append(first_new_source_item);
859         ++source_items_index;
860 
861         // Find proxy item at which insertion should be started
862         int proxy_high = proxy_to_source.size() - 1;
863         QModelIndex i1 = compare ? model->index(first_new_source_item, source_sort_column, source_parent) : QModelIndex();
864         while (proxy_low <= proxy_high) {
865             proxy_item = (proxy_low + proxy_high) / 2;
866             if (compare) {
867                 QModelIndex i2 = model->index(proxy_to_source.at(proxy_item), source_sort_column, source_parent);
868                 if ((sort_order == Qt::AscendingOrder) ? q->lessThan(i1, i2) : q->lessThan(i2, i1))
869                     proxy_high = proxy_item - 1;
870                 else
871                     proxy_low = proxy_item + 1;
872             } else {
873                 if (first_new_source_item < proxy_to_source.at(proxy_item))
874                     proxy_high = proxy_item - 1;
875                 else
876                     proxy_low = proxy_item + 1;
877             }
878         }
879         proxy_item = proxy_low;
880 
881         // Find the sequence of new source items that should be inserted here
882         if (proxy_item >= proxy_to_source.size()) {
883             for ( ; source_items_index < source_items.size(); ++source_items_index)
884                 source_items_in_interval.append(source_items.at(source_items_index));
885         } else {
886             i1 = compare ? model->index(proxy_to_source.at(proxy_item), source_sort_column, source_parent) : QModelIndex();
887             for ( ; source_items_index < source_items.size(); ++source_items_index) {
888                 int new_source_item = source_items.at(source_items_index);
889                 if (compare) {
890                     QModelIndex i2 = model->index(new_source_item, source_sort_column, source_parent);
891                     if ((sort_order == Qt::AscendingOrder) ? q->lessThan(i1, i2) : q->lessThan(i2, i1))
892                         break;
893                 } else {
894                     if (proxy_to_source.at(proxy_item) < new_source_item)
895                         break;
896                 }
897                 source_items_in_interval.append(new_source_item);
898             }
899         }
900 
901         // Add interval to result
902         proxy_intervals.append(QPair<int, QVector<int> >(proxy_item, source_items_in_interval));
903     }
904     return proxy_intervals;
905 }
906 
907 /*!
908   \internal
909 
910   Given source-to-proxy mapping \a source_to_proxy and proxy-to-source mapping
911   \a proxy_to_source, inserts the given \a source_items into this proxy model.
912   The source items are inserted in intervals (based on some sorted order), so
913   that the proper rows/columnsInserted(start, end) signals will be generated.
914 */
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)915 void QSortFilterProxyModelPrivate::insert_source_items(
916     QVector<int> &source_to_proxy, QVector<int> &proxy_to_source,
917     const QVector<int> &source_items, const QModelIndex &source_parent,
918     Qt::Orientation orient, bool emit_signal)
919 {
920     Q_Q(QSortFilterProxyModel);
921     QModelIndex proxy_parent = q->mapFromSource(source_parent);
922     if (!proxy_parent.isValid() && source_parent.isValid())
923         return; // nothing to do (source_parent is not mapped)
924 
925     const auto proxy_intervals = proxy_intervals_for_source_items_to_add(
926         proxy_to_source, source_items, source_parent, orient);
927 
928     const auto end = proxy_intervals.rend();
929     for (auto it = proxy_intervals.rbegin(); it != end; ++it) {
930         const QPair<int, QVector<int> > &interval = *it;
931         const int proxy_start = interval.first;
932         const QVector<int> &source_items = interval.second;
933         const int proxy_end = proxy_start + source_items.size() - 1;
934 
935         if (emit_signal) {
936             if (orient == Qt::Vertical)
937                 q->beginInsertRows(proxy_parent, proxy_start, proxy_end);
938             else
939                 q->beginInsertColumns(proxy_parent, proxy_start, proxy_end);
940         }
941 
942         // TODO: use the range QList::insert() overload once it is implemented (QTBUG-58633).
943         proxy_to_source.insert(proxy_start, source_items.size(), 0);
944         std::copy(source_items.cbegin(), source_items.cend(), proxy_to_source.begin() + proxy_start);
945 
946         build_source_to_proxy_mapping(proxy_to_source, source_to_proxy);
947 
948         if (emit_signal) {
949             if (orient == Qt::Vertical)
950                 q->endInsertRows();
951             else
952                 q->endInsertColumns();
953         }
954     }
955 }
956 
957 /*!
958   \internal
959 
960   Handles source model items insertion (columnsInserted(), rowsInserted()).
961   Determines
962   1) which of the inserted items to also insert into proxy model (filtering),
963   2) where to insert the items into the proxy model (sorting),
964   then inserts those items.
965   The items are inserted into the proxy model in intervals (based on
966   sorted order), so that the proper rows/columnsInserted(start, end)
967   signals will be generated.
968 */
source_items_inserted(const QModelIndex & source_parent,int start,int end,Qt::Orientation orient)969 void QSortFilterProxyModelPrivate::source_items_inserted(
970     const QModelIndex &source_parent, int start, int end, Qt::Orientation orient)
971 {
972     Q_Q(QSortFilterProxyModel);
973     if ((start < 0) || (end < 0))
974         return;
975     IndexMap::const_iterator it = source_index_mapping.constFind(source_parent);
976     if (it == source_index_mapping.constEnd()) {
977         if (!can_create_mapping(source_parent))
978             return;
979         it = create_mapping(source_parent);
980         Mapping *m = it.value();
981         QModelIndex proxy_parent = q->mapFromSource(source_parent);
982         if (m->source_rows.count() > 0) {
983             q->beginInsertRows(proxy_parent, 0, m->source_rows.count() - 1);
984             q->endInsertRows();
985         }
986         if (m->source_columns.count() > 0) {
987             q->beginInsertColumns(proxy_parent, 0, m->source_columns.count() - 1);
988             q->endInsertColumns();
989         }
990         return;
991     }
992 
993     Mapping *m = it.value();
994     QVector<int> &source_to_proxy = (orient == Qt::Vertical) ? m->proxy_rows : m->proxy_columns;
995     QVector<int> &proxy_to_source = (orient == Qt::Vertical) ? m->source_rows : m->source_columns;
996 
997     int delta_item_count = end - start + 1;
998     int old_item_count = source_to_proxy.size();
999 
1000     updateChildrenMapping(source_parent, m, orient, start, end, delta_item_count, false);
1001 
1002     // Expand source-to-proxy mapping to account for new items
1003     if (start < 0 || start > source_to_proxy.size()) {
1004         qWarning("QSortFilterProxyModel: invalid inserted rows reported by source model");
1005         remove_from_mapping(source_parent);
1006         return;
1007     }
1008     source_to_proxy.insert(start, delta_item_count, -1);
1009 
1010     if (start < old_item_count) {
1011         // Adjust existing "stale" indexes in proxy-to-source mapping
1012         int proxy_count = proxy_to_source.size();
1013         for (int proxy_item = 0; proxy_item < proxy_count; ++proxy_item) {
1014             int source_item = proxy_to_source.at(proxy_item);
1015             if (source_item >= start)
1016                 proxy_to_source.replace(proxy_item, source_item + delta_item_count);
1017         }
1018         build_source_to_proxy_mapping(proxy_to_source, source_to_proxy);
1019     }
1020 
1021     // Figure out which items to add to mapping based on filter
1022     QVector<int> source_items;
1023     for (int i = start; i <= end; ++i) {
1024         if ((orient == Qt::Vertical)
1025             ? filterAcceptsRowInternal(i, source_parent)
1026             : q->filterAcceptsColumn(i, source_parent)) {
1027             source_items.append(i);
1028         }
1029     }
1030 
1031     if (model->rowCount(source_parent) == delta_item_count) {
1032         // Items were inserted where there were none before.
1033         // If it was new rows make sure to create mappings for columns so that a
1034         // valid mapping can be retrieved later and vice-versa.
1035 
1036         QVector<int> &orthogonal_proxy_to_source = (orient == Qt::Horizontal) ? m->source_rows : m->source_columns;
1037         QVector<int> &orthogonal_source_to_proxy = (orient == Qt::Horizontal) ? m->proxy_rows : m->proxy_columns;
1038 
1039         if (orthogonal_source_to_proxy.isEmpty()) {
1040             const int ortho_end = (orient == Qt::Horizontal) ? model->rowCount(source_parent) : model->columnCount(source_parent);
1041 
1042             orthogonal_source_to_proxy.resize(ortho_end);
1043 
1044             for (int ortho_item = 0; ortho_item < ortho_end; ++ortho_item) {
1045                 if ((orient == Qt::Horizontal) ? filterAcceptsRowInternal(ortho_item, source_parent)
1046                         : q->filterAcceptsColumn(ortho_item, source_parent)) {
1047                     orthogonal_proxy_to_source.append(ortho_item);
1048                 }
1049             }
1050             if (orient == Qt::Horizontal) {
1051                 // We're reacting to columnsInserted, but we've just inserted new rows. Sort them.
1052                 sort_source_rows(orthogonal_proxy_to_source, source_parent);
1053             }
1054             build_source_to_proxy_mapping(orthogonal_proxy_to_source, orthogonal_source_to_proxy);
1055         }
1056     }
1057 
1058     // Sort and insert the items
1059     if (orient == Qt::Vertical) // Only sort rows
1060         sort_source_rows(source_items, source_parent);
1061     insert_source_items(source_to_proxy, proxy_to_source, source_items, source_parent, orient);
1062 }
1063 
1064 /*!
1065   \internal
1066 
1067   Handles source model items removal
1068   (columnsAboutToBeRemoved(), rowsAboutToBeRemoved()).
1069 */
source_items_about_to_be_removed(const QModelIndex & source_parent,int start,int end,Qt::Orientation orient)1070 void QSortFilterProxyModelPrivate::source_items_about_to_be_removed(
1071     const QModelIndex &source_parent, int start, int end, Qt::Orientation orient)
1072 {
1073     if ((start < 0) || (end < 0))
1074         return;
1075     IndexMap::const_iterator it = source_index_mapping.constFind(source_parent);
1076     if (it == source_index_mapping.constEnd()) {
1077         // Don't care, since we don't have mapping for this index
1078         return;
1079     }
1080 
1081     Mapping *m = it.value();
1082     QVector<int> &source_to_proxy = (orient == Qt::Vertical) ? m->proxy_rows : m->proxy_columns;
1083     QVector<int> &proxy_to_source = (orient == Qt::Vertical) ? m->source_rows : m->source_columns;
1084 
1085     // figure out which items to remove
1086     QVector<int> source_items_to_remove;
1087     int proxy_count = proxy_to_source.size();
1088     for (int proxy_item = 0; proxy_item < proxy_count; ++proxy_item) {
1089         int source_item = proxy_to_source.at(proxy_item);
1090         if ((source_item >= start) && (source_item <= end))
1091             source_items_to_remove.append(source_item);
1092     }
1093 
1094     remove_source_items(source_to_proxy, proxy_to_source, source_items_to_remove,
1095                         source_parent, orient);
1096 }
1097 
1098 /*!
1099   \internal
1100 
1101   Handles source model items removal (columnsRemoved(), rowsRemoved()).
1102 */
source_items_removed(const QModelIndex & source_parent,int start,int end,Qt::Orientation orient)1103 void QSortFilterProxyModelPrivate::source_items_removed(
1104     const QModelIndex &source_parent, int start, int end, Qt::Orientation orient)
1105 {
1106     if ((start < 0) || (end < 0))
1107         return;
1108     IndexMap::const_iterator it = source_index_mapping.constFind(source_parent);
1109     if (it == source_index_mapping.constEnd()) {
1110         // Don't care, since we don't have mapping for this index
1111         return;
1112     }
1113 
1114     Mapping *m = it.value();
1115     QVector<int> &source_to_proxy = (orient == Qt::Vertical) ? m->proxy_rows : m->proxy_columns;
1116     QVector<int> &proxy_to_source = (orient == Qt::Vertical) ? m->source_rows : m->source_columns;
1117 
1118     if (end >= source_to_proxy.size())
1119         end = source_to_proxy.size() - 1;
1120 
1121     // Shrink the source-to-proxy mapping to reflect the new item count
1122     int delta_item_count = end - start + 1;
1123     source_to_proxy.remove(start, delta_item_count);
1124 
1125     int proxy_count = proxy_to_source.size();
1126     if (proxy_count > source_to_proxy.size()) {
1127         // mapping is in an inconsistent state -- redo the whole mapping
1128         qWarning("QSortFilterProxyModel: inconsistent changes reported by source model");
1129         Q_Q(QSortFilterProxyModel);
1130         q->beginResetModel();
1131         remove_from_mapping(source_parent);
1132         q->endResetModel();
1133         return;
1134     }
1135 
1136     // Adjust "stale" indexes in proxy-to-source mapping
1137     for (int proxy_item = 0; proxy_item < proxy_count; ++proxy_item) {
1138         int source_item = proxy_to_source.at(proxy_item);
1139         if (source_item >= start) {
1140             Q_ASSERT(source_item - delta_item_count >= 0);
1141             proxy_to_source.replace(proxy_item, source_item - delta_item_count);
1142         }
1143     }
1144     build_source_to_proxy_mapping(proxy_to_source, source_to_proxy);
1145 
1146     updateChildrenMapping(source_parent, m, orient, start, end, delta_item_count, true);
1147 
1148 }
1149 
1150 
1151 /*!
1152   \internal
1153   updates the mapping of the children when inserting or removing items
1154 */
updateChildrenMapping(const QModelIndex & source_parent,Mapping * parent_mapping,Qt::Orientation orient,int start,int end,int delta_item_count,bool remove)1155 void QSortFilterProxyModelPrivate::updateChildrenMapping(const QModelIndex &source_parent, Mapping *parent_mapping,
1156                                                          Qt::Orientation orient, int start, int end, int delta_item_count, bool remove)
1157 {
1158     // see if any mapped children should be (re)moved
1159     QVector<QPair<QModelIndex, Mapping*> > moved_source_index_mappings;
1160     QVector<QModelIndex>::iterator it2 = parent_mapping->mapped_children.begin();
1161     for ( ; it2 != parent_mapping->mapped_children.end();) {
1162         const QModelIndex source_child_index = *it2;
1163         const int pos = (orient == Qt::Vertical)
1164                         ? source_child_index.row()
1165                         : source_child_index.column();
1166         if (pos < start) {
1167             // not affected
1168             ++it2;
1169         } else if (remove && pos <= end) {
1170             // in the removed interval
1171             it2 = parent_mapping->mapped_children.erase(it2);
1172             remove_from_mapping(source_child_index);
1173         } else {
1174             // below the removed items -- recompute the index
1175             QModelIndex new_index;
1176             const int newpos = remove ? pos - delta_item_count : pos + delta_item_count;
1177             if (orient == Qt::Vertical) {
1178                 new_index = model->index(newpos,
1179                                          source_child_index.column(),
1180                                          source_parent);
1181             } else {
1182                 new_index = model->index(source_child_index.row(),
1183                                          newpos,
1184                                          source_parent);
1185             }
1186             *it2 = new_index;
1187             ++it2;
1188 
1189             // update mapping
1190             Mapping *cm = source_index_mapping.take(source_child_index);
1191             Q_ASSERT(cm);
1192             // we do not reinsert right away, because the new index might be identical with another, old index
1193             moved_source_index_mappings.append(QPair<QModelIndex, Mapping*>(new_index, cm));
1194         }
1195     }
1196 
1197     // reinsert moved, mapped indexes
1198     QVector<QPair<QModelIndex, Mapping*> >::iterator it = moved_source_index_mappings.begin();
1199     for (; it != moved_source_index_mappings.end(); ++it) {
1200         (*it).second->map_iter = QHash<QModelIndex, Mapping *>::const_iterator(source_index_mapping.insert((*it).first, (*it).second));
1201     }
1202 }
1203 
1204 /*!
1205   \internal
1206 */
proxy_item_range(const QVector<int> & source_to_proxy,const QVector<int> & source_items,int & proxy_low,int & proxy_high) const1207 void QSortFilterProxyModelPrivate::proxy_item_range(
1208     const QVector<int> &source_to_proxy, const QVector<int> &source_items,
1209     int &proxy_low, int &proxy_high) const
1210 {
1211     proxy_low = INT_MAX;
1212     proxy_high = INT_MIN;
1213     for (int i = 0; i < source_items.count(); ++i) {
1214         int proxy_item = source_to_proxy.at(source_items.at(i));
1215         Q_ASSERT(proxy_item != -1);
1216         if (proxy_item < proxy_low)
1217             proxy_low = proxy_item;
1218         if (proxy_item > proxy_high)
1219             proxy_high = proxy_item;
1220     }
1221 }
1222 
1223 /*!
1224   \internal
1225 */
build_source_to_proxy_mapping(const QVector<int> & proxy_to_source,QVector<int> & source_to_proxy) const1226 void QSortFilterProxyModelPrivate::build_source_to_proxy_mapping(
1227     const QVector<int> &proxy_to_source, QVector<int> &source_to_proxy) const
1228 {
1229     source_to_proxy.fill(-1);
1230     int proxy_count = proxy_to_source.size();
1231     for (int i = 0; i < proxy_count; ++i)
1232         source_to_proxy[proxy_to_source.at(i)] = i;
1233 }
1234 
1235 /*!
1236   \internal
1237 
1238   Maps the persistent proxy indexes to source indexes and
1239   returns the list of source indexes.
1240 */
store_persistent_indexes() const1241 QModelIndexPairList QSortFilterProxyModelPrivate::store_persistent_indexes() const
1242 {
1243     Q_Q(const QSortFilterProxyModel);
1244     QModelIndexPairList source_indexes;
1245     source_indexes.reserve(persistent.indexes.count());
1246     for (const QPersistentModelIndexData *data : qAsConst(persistent.indexes)) {
1247         const QModelIndex &proxy_index = data->index;
1248         QModelIndex source_index = q->mapToSource(proxy_index);
1249         source_indexes.append(qMakePair(proxy_index, QPersistentModelIndex(source_index)));
1250     }
1251     return source_indexes;
1252 }
1253 
1254 /*!
1255   \internal
1256 
1257   Maps \a source_indexes to proxy indexes and stores those
1258   as persistent indexes.
1259 */
update_persistent_indexes(const QModelIndexPairList & source_indexes)1260 void QSortFilterProxyModelPrivate::update_persistent_indexes(
1261         const QModelIndexPairList &source_indexes)
1262 {
1263     Q_Q(QSortFilterProxyModel);
1264     QModelIndexList from, to;
1265     const int numSourceIndexes = source_indexes.count();
1266     from.reserve(numSourceIndexes);
1267     to.reserve(numSourceIndexes);
1268     for (const auto &indexPair : source_indexes) {
1269         const QPersistentModelIndex &source_index = indexPair.second;
1270         const QModelIndex &old_proxy_index = indexPair.first;
1271         create_mapping(source_index.parent());
1272         QModelIndex proxy_index = q->mapFromSource(source_index);
1273         from << old_proxy_index;
1274         to << proxy_index;
1275     }
1276     q->changePersistentIndexList(from, to);
1277 }
1278 
1279 /*!
1280   \internal
1281 
1282   Updates the source_index mapping in case it's invalid and we
1283   need it because we have a valid filter
1284 */
filter_about_to_be_changed(const QModelIndex & source_parent)1285 void QSortFilterProxyModelPrivate::filter_about_to_be_changed(const QModelIndex &source_parent)
1286 {
1287   if (!filter_data.isEmpty() &&
1288         source_index_mapping.constFind(source_parent) == source_index_mapping.constEnd())
1289     create_mapping(source_parent);
1290 }
1291 
1292 
1293 /*!
1294   \internal
1295 
1296   Updates the proxy model (adds/removes rows) based on the
1297   new filter.
1298 */
filter_changed(const QModelIndex & source_parent)1299 void QSortFilterProxyModelPrivate::filter_changed(const QModelIndex &source_parent)
1300 {
1301     IndexMap::const_iterator it = source_index_mapping.constFind(source_parent);
1302     if (it == source_index_mapping.constEnd())
1303         return;
1304     Mapping *m = it.value();
1305     QSet<int> rows_removed = handle_filter_changed(m->proxy_rows, m->source_rows, source_parent, Qt::Vertical);
1306     QSet<int> columns_removed = handle_filter_changed(m->proxy_columns, m->source_columns, source_parent, Qt::Horizontal);
1307 
1308     // We need to iterate over a copy of m->mapped_children because otherwise it may be changed by other code, invalidating
1309     // the iterator it2.
1310     // The m->mapped_children vector can be appended to with indexes which are no longer filtered
1311     // out (in create_mapping) when this function recurses for child indexes.
1312     const QVector<QModelIndex> mappedChildren = m->mapped_children;
1313     QVector<int> indexesToRemove;
1314     for (int i = 0; i < mappedChildren.size(); ++i) {
1315         const QModelIndex &source_child_index = mappedChildren.at(i);
1316         if (rows_removed.contains(source_child_index.row()) || columns_removed.contains(source_child_index.column())) {
1317             indexesToRemove.push_back(i);
1318             remove_from_mapping(source_child_index);
1319         } else {
1320             filter_changed(source_child_index);
1321         }
1322     }
1323     QVector<int>::const_iterator removeIt = indexesToRemove.constEnd();
1324     const QVector<int>::const_iterator removeBegin = indexesToRemove.constBegin();
1325 
1326     // We can't just remove these items from mappedChildren while iterating above and then
1327     // do something like m->mapped_children = mappedChildren, because mapped_children might
1328     // be appended to in create_mapping, and we would lose those new items.
1329     // Because they are always appended in create_mapping, we can still remove them by
1330     // position here.
1331     while (removeIt != removeBegin) {
1332         --removeIt;
1333         m->mapped_children.remove(*removeIt);
1334     }
1335 }
1336 
1337 /*!
1338   \internal
1339   returns the removed items indexes
1340 */
handle_filter_changed(QVector<int> & source_to_proxy,QVector<int> & proxy_to_source,const QModelIndex & source_parent,Qt::Orientation orient)1341 QSet<int> QSortFilterProxyModelPrivate::handle_filter_changed(
1342     QVector<int> &source_to_proxy, QVector<int> &proxy_to_source,
1343     const QModelIndex &source_parent, Qt::Orientation orient)
1344 {
1345     Q_Q(QSortFilterProxyModel);
1346     // Figure out which mapped items to remove
1347     QVector<int> source_items_remove;
1348     for (int i = 0; i < proxy_to_source.count(); ++i) {
1349         const int source_item = proxy_to_source.at(i);
1350         if ((orient == Qt::Vertical)
1351             ? !filterAcceptsRowInternal(source_item, source_parent)
1352             : !q->filterAcceptsColumn(source_item, source_parent)) {
1353             // This source item does not satisfy the filter, so it must be removed
1354             source_items_remove.append(source_item);
1355         }
1356     }
1357     // Figure out which non-mapped items to insert
1358     QVector<int> source_items_insert;
1359     int source_count = source_to_proxy.size();
1360     for (int source_item = 0; source_item < source_count; ++source_item) {
1361         if (source_to_proxy.at(source_item) == -1) {
1362             if ((orient == Qt::Vertical)
1363                 ? filterAcceptsRowInternal(source_item, source_parent)
1364                 : q->filterAcceptsColumn(source_item, source_parent)) {
1365                 // This source item satisfies the filter, so it must be added
1366                 source_items_insert.append(source_item);
1367             }
1368         }
1369     }
1370     if (!source_items_remove.isEmpty() || !source_items_insert.isEmpty()) {
1371         // Do item removal and insertion
1372         remove_source_items(source_to_proxy, proxy_to_source,
1373                             source_items_remove, source_parent, orient);
1374         if (orient == Qt::Vertical)
1375             sort_source_rows(source_items_insert, source_parent);
1376         insert_source_items(source_to_proxy, proxy_to_source,
1377                             source_items_insert, source_parent, orient);
1378     }
1379     return qVectorToSet(source_items_remove);
1380 }
1381 
needsReorder(const QVector<int> & source_rows,const QModelIndex & source_parent) const1382 bool QSortFilterProxyModelPrivate::needsReorder(const QVector<int> &source_rows, const QModelIndex &source_parent) const
1383 {
1384     Q_Q(const QSortFilterProxyModel);
1385     Q_ASSERT(source_sort_column != -1);
1386     const int proxyRowCount = q->rowCount(source_to_proxy(source_parent));
1387     // If any modified proxy row no longer passes lessThan(previous, current) or lessThan(current, next) then we need to reorder.
1388     return std::any_of(source_rows.begin(), source_rows.end(),
1389             [this, q, proxyRowCount, source_parent](int sourceRow) -> bool {
1390         const QModelIndex sourceIndex = model->index(sourceRow, source_sort_column, source_parent);
1391         const QModelIndex proxyIndex = source_to_proxy(sourceIndex);
1392         Q_ASSERT(proxyIndex.isValid()); // caller ensured source_rows were not filtered out
1393         if (proxyIndex.row() > 0) {
1394             const QModelIndex prevProxyIndex = q->sibling(proxyIndex.row() - 1, proxy_sort_column, proxyIndex);
1395             const QModelIndex prevSourceIndex = proxy_to_source(prevProxyIndex);
1396             if (sort_order == Qt::AscendingOrder ? q->lessThan(sourceIndex, prevSourceIndex) : q->lessThan(prevSourceIndex, sourceIndex))
1397                 return true;
1398         }
1399         if (proxyIndex.row() < proxyRowCount - 1) {
1400             const QModelIndex nextProxyIndex = q->sibling(proxyIndex.row() + 1, proxy_sort_column, proxyIndex);
1401             const QModelIndex nextSourceIndex = proxy_to_source(nextProxyIndex);
1402             if (sort_order == Qt::AscendingOrder ? q->lessThan(nextSourceIndex, sourceIndex) : q->lessThan(sourceIndex, nextSourceIndex))
1403                 return true;
1404         }
1405         return false;
1406     });
1407 }
1408 
_q_sourceDataChanged(const QModelIndex & source_top_left,const QModelIndex & source_bottom_right,const QVector<int> & roles)1409 void QSortFilterProxyModelPrivate::_q_sourceDataChanged(const QModelIndex &source_top_left,
1410                                                         const QModelIndex &source_bottom_right,
1411                                                         const QVector<int> &roles)
1412 {
1413     Q_Q(QSortFilterProxyModel);
1414     if (!source_top_left.isValid() || !source_bottom_right.isValid())
1415         return;
1416 
1417     std::vector<QSortFilterProxyModelDataChanged> data_changed_list;
1418     data_changed_list.emplace_back(source_top_left, source_bottom_right);
1419 
1420     // Do check parents if the filter role have changed and we are recursive
1421     if (filter_recursive && (roles.isEmpty() || roles.contains(filter_role))) {
1422         QModelIndex source_parent = source_top_left.parent();
1423 
1424         while (source_parent.isValid()) {
1425             data_changed_list.emplace_back(source_parent, source_parent);
1426             source_parent = source_parent.parent();
1427         }
1428     }
1429 
1430     for (const QSortFilterProxyModelDataChanged &data_changed : data_changed_list) {
1431         const QModelIndex &source_top_left = data_changed.topLeft;
1432         const QModelIndex &source_bottom_right = data_changed.bottomRight;
1433         const QModelIndex source_parent = source_top_left.parent();
1434 
1435         bool change_in_unmapped_parent = false;
1436         IndexMap::const_iterator it = source_index_mapping.constFind(source_parent);
1437         if (it == source_index_mapping.constEnd()) {
1438             // We don't have mapping for this index, so we cannot know how things
1439             // changed (in case the change affects filtering) in order to forward
1440             // the change correctly.
1441             // But we can at least forward the signal "as is", if the row isn't
1442             // filtered out, this is better than nothing.
1443             it = create_mapping_recursive(source_parent);
1444             if (it == source_index_mapping.constEnd())
1445                 continue;
1446             change_in_unmapped_parent = true;
1447         }
1448 
1449         Mapping *m = it.value();
1450 
1451         // Figure out how the source changes affect us
1452         QVector<int> source_rows_remove;
1453         QVector<int> source_rows_insert;
1454         QVector<int> source_rows_change;
1455         QVector<int> source_rows_resort;
1456         int end = qMin(source_bottom_right.row(), m->proxy_rows.count() - 1);
1457         for (int source_row = source_top_left.row(); source_row <= end; ++source_row) {
1458             if (dynamic_sortfilter && !change_in_unmapped_parent) {
1459                 if (m->proxy_rows.at(source_row) != -1) {
1460                     if (!filterAcceptsRowInternal(source_row, source_parent)) {
1461                         // This source row no longer satisfies the filter, so it must be removed
1462                         source_rows_remove.append(source_row);
1463                     } else if (source_sort_column >= source_top_left.column() && source_sort_column <= source_bottom_right.column()) {
1464                         // This source row has changed in a way that may affect sorted order
1465                         source_rows_resort.append(source_row);
1466                     } else {
1467                         // This row has simply changed, without affecting filtering nor sorting
1468                         source_rows_change.append(source_row);
1469                     }
1470                 } else {
1471                     if (!itemsBeingRemoved.contains(source_parent, source_row) && filterAcceptsRowInternal(source_row, source_parent)) {
1472                         // This source row now satisfies the filter, so it must be added
1473                         source_rows_insert.append(source_row);
1474                     }
1475                 }
1476             } else {
1477                 if (m->proxy_rows.at(source_row) != -1)
1478                     source_rows_change.append(source_row);
1479             }
1480         }
1481 
1482         if (!source_rows_remove.isEmpty()) {
1483             remove_source_items(m->proxy_rows, m->source_rows,
1484                                 source_rows_remove, source_parent, Qt::Vertical);
1485             QSet<int> source_rows_remove_set = qVectorToSet(source_rows_remove);
1486             QVector<QModelIndex>::iterator childIt = m->mapped_children.end();
1487             while (childIt != m->mapped_children.begin()) {
1488                 --childIt;
1489                 const QModelIndex source_child_index = *childIt;
1490                 if (source_rows_remove_set.contains(source_child_index.row())) {
1491                     childIt = m->mapped_children.erase(childIt);
1492                     remove_from_mapping(source_child_index);
1493                 }
1494             }
1495         }
1496 
1497         if (!source_rows_resort.isEmpty()) {
1498             if (needsReorder(source_rows_resort, source_parent)) {
1499                 // Re-sort the rows of this level
1500                 QList<QPersistentModelIndex> parents;
1501                 parents << q->mapFromSource(source_parent);
1502                 emit q->layoutAboutToBeChanged(parents, QAbstractItemModel::VerticalSortHint);
1503                 QModelIndexPairList source_indexes = store_persistent_indexes();
1504                 remove_source_items(m->proxy_rows, m->source_rows, source_rows_resort,
1505                         source_parent, Qt::Vertical, false);
1506                 sort_source_rows(source_rows_resort, source_parent);
1507                 insert_source_items(m->proxy_rows, m->source_rows, source_rows_resort,
1508                         source_parent, Qt::Vertical, false);
1509                 update_persistent_indexes(source_indexes);
1510                 emit q->layoutChanged(parents, QAbstractItemModel::VerticalSortHint);
1511             }
1512             // Make sure we also emit dataChanged for the rows
1513             source_rows_change += source_rows_resort;
1514         }
1515 
1516         if (!source_rows_change.isEmpty()) {
1517             // Find the proxy row range
1518             int proxy_start_row;
1519             int proxy_end_row;
1520             proxy_item_range(m->proxy_rows, source_rows_change,
1521                              proxy_start_row, proxy_end_row);
1522             // ### Find the proxy column range also
1523             if (proxy_end_row >= 0) {
1524                 // the row was accepted, but some columns might still be filtered out
1525                 int source_left_column = source_top_left.column();
1526                 while (source_left_column < source_bottom_right.column()
1527                        && m->proxy_columns.at(source_left_column) == -1)
1528                     ++source_left_column;
1529                 if (m->proxy_columns.at(source_left_column) != -1) {
1530                     const QModelIndex proxy_top_left = create_index(
1531                         proxy_start_row, m->proxy_columns.at(source_left_column), it);
1532                     int source_right_column = source_bottom_right.column();
1533                     while (source_right_column > source_top_left.column()
1534                            && m->proxy_columns.at(source_right_column) == -1)
1535                         --source_right_column;
1536                     if (m->proxy_columns.at(source_right_column) != -1) {
1537                         const QModelIndex proxy_bottom_right = create_index(
1538                             proxy_end_row, m->proxy_columns.at(source_right_column), it);
1539                         emit q->dataChanged(proxy_top_left, proxy_bottom_right, roles);
1540                     }
1541                 }
1542             }
1543         }
1544 
1545         if (!source_rows_insert.isEmpty()) {
1546             sort_source_rows(source_rows_insert, source_parent);
1547             insert_source_items(m->proxy_rows, m->source_rows,
1548                                 source_rows_insert, source_parent, Qt::Vertical);
1549         }
1550     }
1551 }
1552 
_q_sourceHeaderDataChanged(Qt::Orientation orientation,int start,int end)1553 void QSortFilterProxyModelPrivate::_q_sourceHeaderDataChanged(Qt::Orientation orientation,
1554                                                            int start, int end)
1555 {
1556     Q_ASSERT(start <= end);
1557 
1558     Q_Q(QSortFilterProxyModel);
1559     Mapping *m = create_mapping(QModelIndex()).value();
1560 
1561     const QVector<int> &source_to_proxy = (orientation == Qt::Vertical) ? m->proxy_rows : m->proxy_columns;
1562 
1563     QVector<int> proxy_positions;
1564     proxy_positions.reserve(end - start + 1);
1565     {
1566         Q_ASSERT(source_to_proxy.size() > end);
1567         QVector<int>::const_iterator it = source_to_proxy.constBegin() + start;
1568         const QVector<int>::const_iterator endIt = source_to_proxy.constBegin() + end + 1;
1569         for ( ; it != endIt; ++it) {
1570             if (*it != -1)
1571                 proxy_positions.push_back(*it);
1572         }
1573     }
1574 
1575     std::sort(proxy_positions.begin(), proxy_positions.end());
1576 
1577     int last_index = 0;
1578     const int numItems = proxy_positions.size();
1579     while (last_index < numItems) {
1580         const int proxyStart = proxy_positions.at(last_index);
1581         int proxyEnd = proxyStart;
1582         ++last_index;
1583         for (int i = last_index; i < numItems; ++i) {
1584             if (proxy_positions.at(i) == proxyEnd + 1) {
1585                 ++last_index;
1586                 ++proxyEnd;
1587             } else {
1588                 break;
1589             }
1590         }
1591         emit q->headerDataChanged(orientation, proxyStart, proxyEnd);
1592     }
1593 }
1594 
_q_sourceAboutToBeReset()1595 void QSortFilterProxyModelPrivate::_q_sourceAboutToBeReset()
1596 {
1597     Q_Q(QSortFilterProxyModel);
1598     q->beginResetModel();
1599 }
1600 
_q_sourceReset()1601 void QSortFilterProxyModelPrivate::_q_sourceReset()
1602 {
1603     Q_Q(QSortFilterProxyModel);
1604     invalidatePersistentIndexes();
1605     _q_clearMapping();
1606     // All internal structures are deleted in clear()
1607     q->endResetModel();
1608     update_source_sort_column();
1609     if (dynamic_sortfilter && update_source_sort_column())
1610         sort();
1611 }
1612 
_q_sourceLayoutAboutToBeChanged(const QList<QPersistentModelIndex> & sourceParents,QAbstractItemModel::LayoutChangeHint hint)1613 void QSortFilterProxyModelPrivate::_q_sourceLayoutAboutToBeChanged(const QList<QPersistentModelIndex> &sourceParents, QAbstractItemModel::LayoutChangeHint hint)
1614 {
1615     Q_Q(QSortFilterProxyModel);
1616     Q_UNUSED(hint); // We can't forward Hint because we might filter additional rows or columns
1617     saved_persistent_indexes.clear();
1618 
1619     saved_layoutChange_parents.clear();
1620     for (const QPersistentModelIndex &parent : sourceParents) {
1621         if (!parent.isValid()) {
1622             saved_layoutChange_parents << QPersistentModelIndex();
1623             continue;
1624         }
1625         const QModelIndex mappedParent = q->mapFromSource(parent);
1626         // Might be filtered out.
1627         if (mappedParent.isValid())
1628             saved_layoutChange_parents << mappedParent;
1629     }
1630 
1631     // All parents filtered out.
1632     if (!sourceParents.isEmpty() && saved_layoutChange_parents.isEmpty())
1633         return;
1634 
1635     emit q->layoutAboutToBeChanged(saved_layoutChange_parents);
1636     if (persistent.indexes.isEmpty())
1637         return;
1638 
1639     saved_persistent_indexes = store_persistent_indexes();
1640 }
1641 
_q_sourceLayoutChanged(const QList<QPersistentModelIndex> & sourceParents,QAbstractItemModel::LayoutChangeHint hint)1642 void QSortFilterProxyModelPrivate::_q_sourceLayoutChanged(const QList<QPersistentModelIndex> &sourceParents, QAbstractItemModel::LayoutChangeHint hint)
1643 {
1644     Q_Q(QSortFilterProxyModel);
1645     Q_UNUSED(hint); // We can't forward Hint because we might filter additional rows or columns
1646 
1647     if (!sourceParents.isEmpty() && saved_layoutChange_parents.isEmpty())
1648         return;
1649 
1650     // Optimize: We only actually have to clear the mapping related to the contents of
1651     // sourceParents, not everything.
1652     qDeleteAll(source_index_mapping);
1653     source_index_mapping.clear();
1654 
1655     update_persistent_indexes(saved_persistent_indexes);
1656     saved_persistent_indexes.clear();
1657 
1658     if (dynamic_sortfilter)
1659         source_sort_column = find_source_sort_column();
1660 
1661     emit q->layoutChanged(saved_layoutChange_parents);
1662     saved_layoutChange_parents.clear();
1663 }
1664 
_q_sourceRowsAboutToBeInserted(const QModelIndex & source_parent,int start,int end)1665 void QSortFilterProxyModelPrivate::_q_sourceRowsAboutToBeInserted(
1666     const QModelIndex &source_parent, int start, int end)
1667 {
1668     Q_UNUSED(start);
1669     Q_UNUSED(end);
1670 
1671     const bool toplevel = !source_parent.isValid();
1672     const bool recursive_accepted = filter_recursive && !toplevel && filterAcceptsRowInternal(source_parent.row(), source_parent.parent());
1673     //Force the creation of a mapping now, even if it's empty.
1674     //We need it because the proxy can be accessed at the moment it emits rowsAboutToBeInserted in insert_source_items
1675     if (!filter_recursive || toplevel || recursive_accepted) {
1676         if (can_create_mapping(source_parent))
1677             create_mapping(source_parent);
1678         if (filter_recursive)
1679             complete_insert = true;
1680     } else {
1681         // The row could have been rejected or the parent might be not yet known... let's try to discover it
1682         QModelIndex top_source_parent = source_parent;
1683         QModelIndex parent = source_parent.parent();
1684         QModelIndex grandParent = parent.parent();
1685 
1686         while (parent.isValid() && !filterAcceptsRowInternal(parent.row(), grandParent)) {
1687             top_source_parent = parent;
1688             parent = grandParent;
1689             grandParent = parent.parent();
1690         }
1691 
1692         last_top_source = top_source_parent;
1693     }
1694 }
1695 
_q_sourceRowsInserted(const QModelIndex & source_parent,int start,int end)1696 void QSortFilterProxyModelPrivate::_q_sourceRowsInserted(
1697     const QModelIndex &source_parent, int start, int end)
1698 {
1699     if (!filter_recursive || complete_insert) {
1700         if (filter_recursive)
1701             complete_insert = false;
1702         source_items_inserted(source_parent, start, end, Qt::Vertical);
1703         if (update_source_sort_column() && dynamic_sortfilter) //previous call to update_source_sort_column may fail if the model has no column.
1704             sort();                      // now it should succeed so we need to make sure to sort again
1705         return;
1706     }
1707 
1708     if (filter_recursive) {
1709         bool accept = false;
1710 
1711         for (int row = start; row <= end; ++row) {
1712             if (filterAcceptsRowInternal(row, source_parent)) {
1713                 accept = true;
1714                 break;
1715             }
1716         }
1717 
1718         if (!accept) // the new rows have no descendants that match the filter, filter them out.
1719             return;
1720 
1721         // last_top_source should now become visible
1722         _q_sourceDataChanged(last_top_source, last_top_source, QVector<int>());
1723     }
1724 }
1725 
_q_sourceRowsAboutToBeRemoved(const QModelIndex & source_parent,int start,int end)1726 void QSortFilterProxyModelPrivate::_q_sourceRowsAboutToBeRemoved(
1727     const QModelIndex &source_parent, int start, int end)
1728 {
1729     itemsBeingRemoved = QRowsRemoval(source_parent, start, end);
1730     source_items_about_to_be_removed(source_parent, start, end,
1731                                      Qt::Vertical);
1732 }
1733 
_q_sourceRowsRemoved(const QModelIndex & source_parent,int start,int end)1734 void QSortFilterProxyModelPrivate::_q_sourceRowsRemoved(
1735     const QModelIndex &source_parent, int start, int end)
1736 {
1737     itemsBeingRemoved = QRowsRemoval();
1738     source_items_removed(source_parent, start, end, Qt::Vertical);
1739 
1740     if (filter_recursive) {
1741         // Find out if removing this visible row means that some ascendant
1742         // row can now be hidden.
1743         // We go up until we find a row that should still be visible
1744         // and then make QSFPM re-evaluate the last one we saw before that, to hide it.
1745 
1746         QModelIndex to_hide;
1747         QModelIndex source_ascendant = source_parent;
1748 
1749         while (source_ascendant.isValid()) {
1750             if (filterAcceptsRowInternal(source_ascendant.row(), source_ascendant.parent()))
1751                 break;
1752 
1753             to_hide = source_ascendant;
1754             source_ascendant = source_ascendant.parent();
1755         }
1756 
1757         if (to_hide.isValid())
1758             _q_sourceDataChanged(to_hide, to_hide, QVector<int>());
1759     }
1760 }
1761 
_q_sourceRowsAboutToBeMoved(const QModelIndex & sourceParent,int,int,const QModelIndex & destParent,int)1762 void QSortFilterProxyModelPrivate::_q_sourceRowsAboutToBeMoved(
1763     const QModelIndex &sourceParent, int /* sourceStart */, int /* sourceEnd */, const QModelIndex &destParent, int /* dest */)
1764 {
1765     // Because rows which are contiguous in the source model might not be contiguous
1766     // in the proxy due to sorting, the best thing we can do here is be specific about what
1767     // parents are having their children changed.
1768     // Optimize: Emit move signals if the proxy is not sorted. Will need to account for rows
1769     // being filtered out though.
1770 
1771     QList<QPersistentModelIndex> parents;
1772     parents << sourceParent;
1773     if (sourceParent != destParent)
1774         parents << destParent;
1775     _q_sourceLayoutAboutToBeChanged(parents, QAbstractItemModel::NoLayoutChangeHint);
1776 }
1777 
_q_sourceRowsMoved(const QModelIndex & sourceParent,int,int,const QModelIndex & destParent,int)1778 void QSortFilterProxyModelPrivate::_q_sourceRowsMoved(
1779     const QModelIndex &sourceParent, int /* sourceStart */, int /* sourceEnd */, const QModelIndex &destParent, int /* dest */)
1780 {
1781     QList<QPersistentModelIndex> parents;
1782     parents << sourceParent;
1783     if (sourceParent != destParent)
1784         parents << destParent;
1785     _q_sourceLayoutChanged(parents, QAbstractItemModel::NoLayoutChangeHint);
1786 }
1787 
_q_sourceColumnsAboutToBeInserted(const QModelIndex & source_parent,int start,int end)1788 void QSortFilterProxyModelPrivate::_q_sourceColumnsAboutToBeInserted(
1789     const QModelIndex &source_parent, int start, int end)
1790 {
1791     Q_UNUSED(start);
1792     Q_UNUSED(end);
1793     //Force the creation of a mapping now, even if it's empty.
1794     //We need it because the proxy can be accessed at the moment it emits columnsAboutToBeInserted in insert_source_items
1795     if (can_create_mapping(source_parent))
1796         create_mapping(source_parent);
1797 }
1798 
_q_sourceColumnsInserted(const QModelIndex & source_parent,int start,int end)1799 void QSortFilterProxyModelPrivate::_q_sourceColumnsInserted(
1800     const QModelIndex &source_parent, int start, int end)
1801 {
1802     Q_Q(const QSortFilterProxyModel);
1803     source_items_inserted(source_parent, start, end, Qt::Horizontal);
1804 
1805     if (source_parent.isValid())
1806         return; //we sort according to the root column only
1807     if (source_sort_column == -1) {
1808         //we update the source_sort_column depending on the proxy_sort_column
1809         if (update_source_sort_column() && dynamic_sortfilter)
1810             sort();
1811     } else {
1812         if (start <= source_sort_column)
1813             source_sort_column += end - start + 1;
1814 
1815         proxy_sort_column = q->mapFromSource(model->index(0,source_sort_column, source_parent)).column();
1816     }
1817 }
1818 
_q_sourceColumnsAboutToBeRemoved(const QModelIndex & source_parent,int start,int end)1819 void QSortFilterProxyModelPrivate::_q_sourceColumnsAboutToBeRemoved(
1820     const QModelIndex &source_parent, int start, int end)
1821 {
1822     source_items_about_to_be_removed(source_parent, start, end,
1823                                      Qt::Horizontal);
1824 }
1825 
_q_sourceColumnsRemoved(const QModelIndex & source_parent,int start,int end)1826 void QSortFilterProxyModelPrivate::_q_sourceColumnsRemoved(
1827     const QModelIndex &source_parent, int start, int end)
1828 {
1829     Q_Q(const QSortFilterProxyModel);
1830     source_items_removed(source_parent, start, end, Qt::Horizontal);
1831 
1832     if (source_parent.isValid())
1833         return; //we sort according to the root column only
1834     if (start <= source_sort_column) {
1835         if (end < source_sort_column)
1836             source_sort_column -= end - start + 1;
1837         else
1838             source_sort_column = -1;
1839     }
1840 
1841     if (source_sort_column >= 0)
1842         proxy_sort_column = q->mapFromSource(model->index(0,source_sort_column, source_parent)).column();
1843     else
1844         proxy_sort_column = -1;
1845 }
1846 
_q_sourceColumnsAboutToBeMoved(const QModelIndex & sourceParent,int,int,const QModelIndex & destParent,int)1847 void QSortFilterProxyModelPrivate::_q_sourceColumnsAboutToBeMoved(
1848     const QModelIndex &sourceParent, int /* sourceStart */, int /* sourceEnd */, const QModelIndex &destParent, int /* dest */)
1849 {
1850     QList<QPersistentModelIndex> parents;
1851     parents << sourceParent;
1852     if (sourceParent != destParent)
1853         parents << destParent;
1854     _q_sourceLayoutAboutToBeChanged(parents, QAbstractItemModel::NoLayoutChangeHint);
1855 }
1856 
_q_sourceColumnsMoved(const QModelIndex & sourceParent,int,int,const QModelIndex & destParent,int)1857 void QSortFilterProxyModelPrivate::_q_sourceColumnsMoved(
1858     const QModelIndex &sourceParent, int /* sourceStart */, int /* sourceEnd */, const QModelIndex &destParent, int /* dest */)
1859 {
1860     QList<QPersistentModelIndex> parents;
1861     parents << sourceParent;
1862     if (sourceParent != destParent)
1863         parents << destParent;
1864     _q_sourceLayoutChanged(parents, QAbstractItemModel::NoLayoutChangeHint);
1865 }
1866 
1867 /*!
1868     \since 4.1
1869     \class QSortFilterProxyModel
1870     \inmodule QtCore
1871     \brief The QSortFilterProxyModel class provides support for sorting and
1872     filtering data passed between another model and a view.
1873 
1874     \ingroup model-view
1875 
1876     QSortFilterProxyModel can be used for sorting items, filtering out items,
1877     or both. The model transforms the structure of a source model by mapping
1878     the model indexes it supplies to new indexes, corresponding to different
1879     locations, for views to use. This approach allows a given source model to
1880     be restructured as far as views are concerned without requiring any
1881     transformations on the underlying data, and without duplicating the data in
1882     memory.
1883 
1884     Let's assume that we want to sort and filter the items provided by a custom
1885     model. The code to set up the model and the view, \e without sorting and
1886     filtering, would look like this:
1887 
1888     \snippet qsortfilterproxymodel-details/main.cpp 1
1889 
1890     To add sorting and filtering support to \c MyItemModel, we need to create
1891     a QSortFilterProxyModel, call setSourceModel() with the \c MyItemModel as
1892     argument, and install the QSortFilterProxyModel on the view:
1893 
1894     \snippet qsortfilterproxymodel-details/main.cpp 0
1895     \snippet qsortfilterproxymodel-details/main.cpp 2
1896 
1897     At this point, neither sorting nor filtering is enabled; the original data
1898     is displayed in the view. Any changes made through the
1899     QSortFilterProxyModel are applied to the original model.
1900 
1901     The QSortFilterProxyModel acts as a wrapper for the original model. If you
1902     need to convert source \l{QModelIndex}es to sorted/filtered model indexes
1903     or vice versa, use mapToSource(), mapFromSource(), mapSelectionToSource(),
1904     and mapSelectionFromSource().
1905 
1906     \note By default, the model dynamically re-sorts and re-filters data
1907     whenever the original model changes. This behavior can be changed by
1908     setting the \l{QSortFilterProxyModel::dynamicSortFilter}{dynamicSortFilter}
1909     property.
1910 
1911     The \l{itemviews/basicsortfiltermodel}{Basic Sort/Filter Model} and
1912     \l{itemviews/customsortfiltermodel}{Custom Sort/Filter Model} examples
1913     illustrate how to use QSortFilterProxyModel to perform basic sorting and
1914     filtering and how to subclass it to implement custom behavior.
1915 
1916     \section1 Sorting
1917 
1918     QTableView and QTreeView have a
1919     \l{QTreeView::sortingEnabled}{sortingEnabled} property that controls
1920     whether the user can sort the view by clicking the view's horizontal
1921     header. For example:
1922 
1923     \snippet qsortfilterproxymodel-details/main.cpp 3
1924 
1925     When this feature is on (the default is off), clicking on a header section
1926     sorts the items according to that column. By clicking repeatedly, the user
1927     can alternate between ascending and descending order.
1928 
1929     \image qsortfilterproxymodel-sorting.png A sorted QTreeView
1930 
1931     Behind the scene, the view calls the sort() virtual function on the model
1932     to reorder the data in the model. To make your data sortable, you can
1933     either implement sort() in your model, or use a QSortFilterProxyModel to
1934     wrap your model -- QSortFilterProxyModel provides a generic sort()
1935     reimplementation that operates on the sortRole() (Qt::DisplayRole by
1936     default) of the items and that understands several data types, including
1937     \c int, QString, and QDateTime. For hierarchical models, sorting is applied
1938     recursively to all child items. String comparisons are case sensitive by
1939     default; this can be changed by setting the \l{QSortFilterProxyModel::}
1940     {sortCaseSensitivity} property.
1941 
1942     Custom sorting behavior is achieved by subclassing
1943     QSortFilterProxyModel and reimplementing lessThan(), which is
1944     used to compare items. For example:
1945 
1946     \snippet ../widgets/itemviews/customsortfiltermodel/mysortfilterproxymodel.cpp 5
1947 
1948     (This code snippet comes from the
1949     \l{itemviews/customsortfiltermodel}{Custom Sort/Filter Model}
1950     example.)
1951 
1952     An alternative approach to sorting is to disable sorting on the view and to
1953     impose a certain order to the user. This is done by explicitly calling
1954     sort() with the desired column and order as arguments on the
1955     QSortFilterProxyModel (or on the original model if it implements sort()).
1956     For example:
1957 
1958     \snippet qsortfilterproxymodel-details/main.cpp 4
1959 
1960     QSortFilterProxyModel can be sorted by column -1, in which case it returns
1961     to the sort order of the underlying source model.
1962 
1963     \section1 Filtering
1964 
1965     In addition to sorting, QSortFilterProxyModel can be used to hide items
1966     that do not match a certain filter. The filter is specified using a QRegExp
1967     object and is applied to the filterRole() (Qt::DisplayRole by default) of
1968     each item, for a given column. The QRegExp object can be used to match a
1969     regular expression, a wildcard pattern, or a fixed string. For example:
1970 
1971     \snippet qsortfilterproxymodel-details/main.cpp 5
1972 
1973     For hierarchical models, the filter is applied recursively to all children.
1974     If a parent item doesn't match the filter, none of its children will be
1975     shown.
1976 
1977     A common use case is to let the user specify the filter regular expression,
1978     wildcard pattern, or fixed string in a QLineEdit and to connect the
1979     \l{QLineEdit::textChanged()}{textChanged()} signal to setFilterRegularExpression(),
1980     setFilterWildcard(), or setFilterFixedString() to reapply the filter.
1981 
1982     Custom filtering behavior can be achieved by reimplementing the
1983     filterAcceptsRow() and filterAcceptsColumn() functions. For
1984     example (from the \l{itemviews/customsortfiltermodel}
1985     {Custom Sort/Filter Model} example), the following implementation ignores
1986     the \l{QSortFilterProxyModel::filterKeyColumn}{filterKeyColumn} property
1987     and performs filtering on columns 0, 1, and 2:
1988 
1989     \snippet ../widgets/itemviews/customsortfiltermodel/mysortfilterproxymodel.cpp 3
1990 
1991     (This code snippet comes from the
1992     \l{itemviews/customsortfiltermodel}{Custom Sort/Filter Model}
1993     example.)
1994 
1995     If you are working with large amounts of filtering and have to invoke
1996     invalidateFilter() repeatedly, using beginResetModel() / endResetModel() may
1997     be more efficient, depending on the implementation of your model. However,
1998     beginResetModel() / endResetModel() returns the
1999     proxy model to its original state, losing selection information, and will
2000     cause the proxy model to be repopulated.
2001 
2002     \section1 Subclassing
2003 
2004     Since QAbstractProxyModel and its subclasses are derived from
2005     QAbstractItemModel, much of the same advice about subclassing normal models
2006     also applies to proxy models. In addition, it is worth noting that many of
2007     the default implementations of functions in this class are written so that
2008     they call the equivalent functions in the relevant source model. This
2009     simple proxying mechanism may need to be overridden for source models with
2010     more complex behavior; for example, if the source model provides a custom
2011     hasChildren() implementation, you should also provide one in the proxy
2012     model.
2013 
2014     \note Some general guidelines for subclassing models are available in the
2015     \l{Model Subclassing Reference}.
2016 
2017     \note With Qt 5, regular expression support has been improved through the
2018     QRegularExpression class. QSortFilterProxyModel dating back prior to that
2019     class creation, it originally supported only QRegExp. Since Qt 5.12,
2020     QRegularExpression APIs have been added. Therefore, QRegExp APIs should be
2021     considered deprecated and the QRegularExpression version should be used in
2022     place.
2023 
2024     \warning Don't mix calls to the getters and setters of different regexp types
2025     as this will lead to unexpected results. For maximum compatibility, the original
2026     implementation has been kept. Therefore, if, for example, a call to
2027     setFilterRegularExpression is made followed by another one to
2028     setFilterFixedString, the first call will setup a QRegularExpression object
2029     to use as filter while the second will setup a QRegExp in FixedString mode.
2030     However, this is an implementation detail that might change in the future.
2031 
2032     \sa QAbstractProxyModel, QAbstractItemModel, {Model/View Programming},
2033     {Basic Sort/Filter Model Example}, {Custom Sort/Filter Model Example}, QIdentityProxyModel
2034 */
2035 
2036 /*!
2037     Constructs a sorting filter model with the given \a parent.
2038 */
2039 
QSortFilterProxyModel(QObject * parent)2040 QSortFilterProxyModel::QSortFilterProxyModel(QObject *parent)
2041     : QAbstractProxyModel(*new QSortFilterProxyModelPrivate, parent)
2042 {
2043     Q_D(QSortFilterProxyModel);
2044     d->proxy_sort_column = d->source_sort_column = -1;
2045     d->sort_order = Qt::AscendingOrder;
2046     d->sort_casesensitivity = Qt::CaseSensitive;
2047     d->sort_role = Qt::DisplayRole;
2048     d->sort_localeaware = false;
2049     d->filter_column = 0;
2050     d->filter_role = Qt::DisplayRole;
2051     d->filter_recursive = false;
2052     d->dynamic_sortfilter = true;
2053     d->complete_insert = false;
2054     connect(this, SIGNAL(modelReset()), this, SLOT(_q_clearMapping()));
2055 }
2056 
2057 /*!
2058     Destroys this sorting filter model.
2059 */
~QSortFilterProxyModel()2060 QSortFilterProxyModel::~QSortFilterProxyModel()
2061 {
2062     Q_D(QSortFilterProxyModel);
2063     qDeleteAll(d->source_index_mapping);
2064     d->source_index_mapping.clear();
2065 }
2066 
2067 /*!
2068   \reimp
2069 */
setSourceModel(QAbstractItemModel * sourceModel)2070 void QSortFilterProxyModel::setSourceModel(QAbstractItemModel *sourceModel)
2071 {
2072     Q_D(QSortFilterProxyModel);
2073 
2074     if (sourceModel == d->model)
2075         return;
2076 
2077     beginResetModel();
2078 
2079     disconnect(d->model, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)),
2080                this, SLOT(_q_sourceDataChanged(QModelIndex,QModelIndex,QVector<int>)));
2081 
2082     disconnect(d->model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)),
2083                this, SLOT(_q_sourceHeaderDataChanged(Qt::Orientation,int,int)));
2084 
2085     disconnect(d->model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
2086                this, SLOT(_q_sourceRowsAboutToBeInserted(QModelIndex,int,int)));
2087 
2088     disconnect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)),
2089                this, SLOT(_q_sourceRowsInserted(QModelIndex,int,int)));
2090 
2091     disconnect(d->model, SIGNAL(columnsAboutToBeInserted(QModelIndex,int,int)),
2092                this, SLOT(_q_sourceColumnsAboutToBeInserted(QModelIndex,int,int)));
2093 
2094     disconnect(d->model, SIGNAL(columnsInserted(QModelIndex,int,int)),
2095                this, SLOT(_q_sourceColumnsInserted(QModelIndex,int,int)));
2096 
2097     disconnect(d->model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
2098                this, SLOT(_q_sourceRowsAboutToBeRemoved(QModelIndex,int,int)));
2099 
2100     disconnect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
2101                this, SLOT(_q_sourceRowsRemoved(QModelIndex,int,int)));
2102 
2103     disconnect(d->model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
2104                this, SLOT(_q_sourceColumnsAboutToBeRemoved(QModelIndex,int,int)));
2105 
2106     disconnect(d->model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
2107                this, SLOT(_q_sourceColumnsRemoved(QModelIndex,int,int)));
2108 
2109     disconnect(d->model, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
2110                this, SLOT(_q_sourceRowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)));
2111 
2112     disconnect(d->model, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
2113                this, SLOT(_q_sourceRowsMoved(QModelIndex,int,int,QModelIndex,int)));
2114 
2115     disconnect(d->model, SIGNAL(columnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
2116                this, SLOT(_q_sourceColumnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)));
2117 
2118     disconnect(d->model, SIGNAL(columnsMoved(QModelIndex,int,int,QModelIndex,int)),
2119                this, SLOT(_q_sourceColumnsMoved(QModelIndex,int,int,QModelIndex,int)));
2120 
2121     disconnect(d->model, SIGNAL(layoutAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)),
2122                this, SLOT(_q_sourceLayoutAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)));
2123 
2124     disconnect(d->model, SIGNAL(layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)),
2125                this, SLOT(_q_sourceLayoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)));
2126 
2127     disconnect(d->model, SIGNAL(modelAboutToBeReset()), this, SLOT(_q_sourceAboutToBeReset()));
2128     disconnect(d->model, SIGNAL(modelReset()), this, SLOT(_q_sourceReset()));
2129 
2130     // same as in _q_sourceReset()
2131     d->invalidatePersistentIndexes();
2132     d->_q_clearMapping();
2133 
2134     QAbstractProxyModel::setSourceModel(sourceModel);
2135 
2136     connect(d->model, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)),
2137             this, SLOT(_q_sourceDataChanged(QModelIndex,QModelIndex,QVector<int>)));
2138 
2139     connect(d->model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)),
2140             this, SLOT(_q_sourceHeaderDataChanged(Qt::Orientation,int,int)));
2141 
2142     connect(d->model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
2143             this, SLOT(_q_sourceRowsAboutToBeInserted(QModelIndex,int,int)));
2144 
2145     connect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)),
2146             this, SLOT(_q_sourceRowsInserted(QModelIndex,int,int)));
2147 
2148     connect(d->model, SIGNAL(columnsAboutToBeInserted(QModelIndex,int,int)),
2149             this, SLOT(_q_sourceColumnsAboutToBeInserted(QModelIndex,int,int)));
2150 
2151     connect(d->model, SIGNAL(columnsInserted(QModelIndex,int,int)),
2152             this, SLOT(_q_sourceColumnsInserted(QModelIndex,int,int)));
2153 
2154     connect(d->model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
2155             this, SLOT(_q_sourceRowsAboutToBeRemoved(QModelIndex,int,int)));
2156 
2157     connect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
2158             this, SLOT(_q_sourceRowsRemoved(QModelIndex,int,int)));
2159 
2160     connect(d->model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
2161             this, SLOT(_q_sourceColumnsAboutToBeRemoved(QModelIndex,int,int)));
2162 
2163     connect(d->model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
2164             this, SLOT(_q_sourceColumnsRemoved(QModelIndex,int,int)));
2165 
2166     connect(d->model, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
2167             this, SLOT(_q_sourceRowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)));
2168 
2169     connect(d->model, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
2170             this, SLOT(_q_sourceRowsMoved(QModelIndex,int,int,QModelIndex,int)));
2171 
2172     connect(d->model, SIGNAL(columnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
2173             this, SLOT(_q_sourceColumnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)));
2174 
2175     connect(d->model, SIGNAL(columnsMoved(QModelIndex,int,int,QModelIndex,int)),
2176             this, SLOT(_q_sourceColumnsMoved(QModelIndex,int,int,QModelIndex,int)));
2177 
2178     connect(d->model, SIGNAL(layoutAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)),
2179             this, SLOT(_q_sourceLayoutAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)));
2180 
2181     connect(d->model, SIGNAL(layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)),
2182             this, SLOT(_q_sourceLayoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)));
2183 
2184     connect(d->model, SIGNAL(modelAboutToBeReset()), this, SLOT(_q_sourceAboutToBeReset()));
2185     connect(d->model, SIGNAL(modelReset()), this, SLOT(_q_sourceReset()));
2186 
2187     endResetModel();
2188     if (d->update_source_sort_column() && d->dynamic_sortfilter)
2189         d->sort();
2190 }
2191 
2192 /*!
2193     \reimp
2194 */
index(int row,int column,const QModelIndex & parent) const2195 QModelIndex QSortFilterProxyModel::index(int row, int column, const QModelIndex &parent) const
2196 {
2197     Q_D(const QSortFilterProxyModel);
2198     if (row < 0 || column < 0)
2199         return QModelIndex();
2200 
2201     QModelIndex source_parent = mapToSource(parent); // parent is already mapped at this point
2202     IndexMap::const_iterator it = d->create_mapping(source_parent); // but make sure that the children are mapped
2203     if (it.value()->source_rows.count() <= row || it.value()->source_columns.count() <= column)
2204         return QModelIndex();
2205 
2206     return d->create_index(row, column, it);
2207 }
2208 
2209 /*!
2210   \reimp
2211 */
parent(const QModelIndex & child) const2212 QModelIndex QSortFilterProxyModel::parent(const QModelIndex &child) const
2213 {
2214     Q_D(const QSortFilterProxyModel);
2215     if (!d->indexValid(child))
2216         return QModelIndex();
2217     IndexMap::const_iterator it = d->index_to_iterator(child);
2218     Q_ASSERT(it != d->source_index_mapping.constEnd());
2219     QModelIndex source_parent = it.key();
2220     QModelIndex proxy_parent = mapFromSource(source_parent);
2221     return proxy_parent;
2222 }
2223 
2224 /*!
2225   \reimp
2226 */
sibling(int row,int column,const QModelIndex & idx) const2227 QModelIndex QSortFilterProxyModel::sibling(int row, int column, const QModelIndex &idx) const
2228 {
2229     Q_D(const QSortFilterProxyModel);
2230     if (!d->indexValid(idx))
2231         return QModelIndex();
2232 
2233     const IndexMap::const_iterator it = d->index_to_iterator(idx);
2234     if (it.value()->source_rows.count() <= row || it.value()->source_columns.count() <= column)
2235         return QModelIndex();
2236 
2237     return d->create_index(row, column, it);
2238 }
2239 
2240 /*!
2241   \reimp
2242 */
rowCount(const QModelIndex & parent) const2243 int QSortFilterProxyModel::rowCount(const QModelIndex &parent) const
2244 {
2245     Q_D(const QSortFilterProxyModel);
2246     QModelIndex source_parent = mapToSource(parent);
2247     if (parent.isValid() && !source_parent.isValid())
2248         return 0;
2249     IndexMap::const_iterator it = d->create_mapping(source_parent);
2250     return it.value()->source_rows.count();
2251 }
2252 
2253 /*!
2254   \reimp
2255 */
columnCount(const QModelIndex & parent) const2256 int QSortFilterProxyModel::columnCount(const QModelIndex &parent) const
2257 {
2258     Q_D(const QSortFilterProxyModel);
2259     QModelIndex source_parent = mapToSource(parent);
2260     if (parent.isValid() && !source_parent.isValid())
2261         return 0;
2262     IndexMap::const_iterator it = d->create_mapping(source_parent);
2263     return it.value()->source_columns.count();
2264 }
2265 
2266 /*!
2267   \reimp
2268 */
hasChildren(const QModelIndex & parent) const2269 bool QSortFilterProxyModel::hasChildren(const QModelIndex &parent) const
2270 {
2271     Q_D(const QSortFilterProxyModel);
2272     QModelIndex source_parent = mapToSource(parent);
2273     if (parent.isValid() && !source_parent.isValid())
2274         return false;
2275     if (!d->model->hasChildren(source_parent))
2276         return false;
2277 
2278     if (d->model->canFetchMore(source_parent))
2279         return true; //we assume we might have children that can be fetched
2280 
2281     QSortFilterProxyModelPrivate::Mapping *m = d->create_mapping(source_parent).value();
2282     return m->source_rows.count() != 0 && m->source_columns.count() != 0;
2283 }
2284 
2285 /*!
2286   \reimp
2287 */
data(const QModelIndex & index,int role) const2288 QVariant QSortFilterProxyModel::data(const QModelIndex &index, int role) const
2289 {
2290     Q_D(const QSortFilterProxyModel);
2291     QModelIndex source_index = mapToSource(index);
2292     if (index.isValid() && !source_index.isValid())
2293         return QVariant();
2294     return d->model->data(source_index, role);
2295 }
2296 
2297 /*!
2298   \reimp
2299 */
setData(const QModelIndex & index,const QVariant & value,int role)2300 bool QSortFilterProxyModel::setData(const QModelIndex &index, const QVariant &value, int role)
2301 {
2302     Q_D(QSortFilterProxyModel);
2303     QModelIndex source_index = mapToSource(index);
2304     if (index.isValid() && !source_index.isValid())
2305         return false;
2306     return d->model->setData(source_index, value, role);
2307 }
2308 
2309 /*!
2310   \reimp
2311 */
headerData(int section,Qt::Orientation orientation,int role) const2312 QVariant QSortFilterProxyModel::headerData(int section, Qt::Orientation orientation, int role) const
2313 {
2314     Q_D(const QSortFilterProxyModel);
2315     IndexMap::const_iterator it = d->create_mapping(QModelIndex());
2316     if (it.value()->source_rows.count() * it.value()->source_columns.count() > 0)
2317         return QAbstractProxyModel::headerData(section, orientation, role);
2318     int source_section;
2319     if (orientation == Qt::Vertical) {
2320         if (section < 0 || section >= it.value()->source_rows.count())
2321             return QVariant();
2322         source_section = it.value()->source_rows.at(section);
2323     } else {
2324         if (section < 0 || section >= it.value()->source_columns.count())
2325             return QVariant();
2326         source_section = it.value()->source_columns.at(section);
2327     }
2328     return d->model->headerData(source_section, orientation, role);
2329 }
2330 
2331 /*!
2332   \reimp
2333 */
setHeaderData(int section,Qt::Orientation orientation,const QVariant & value,int role)2334 bool QSortFilterProxyModel::setHeaderData(int section, Qt::Orientation orientation,
2335                                           const QVariant &value, int role)
2336 {
2337     Q_D(QSortFilterProxyModel);
2338     IndexMap::const_iterator it = d->create_mapping(QModelIndex());
2339     if (it.value()->source_rows.count() * it.value()->source_columns.count() > 0)
2340         return QAbstractProxyModel::setHeaderData(section, orientation, value, role);
2341     int source_section;
2342     if (orientation == Qt::Vertical) {
2343         if (section < 0 || section >= it.value()->source_rows.count())
2344             return false;
2345         source_section = it.value()->source_rows.at(section);
2346     } else {
2347         if (section < 0 || section >= it.value()->source_columns.count())
2348             return false;
2349         source_section = it.value()->source_columns.at(section);
2350     }
2351     return d->model->setHeaderData(source_section, orientation, value, role);
2352 }
2353 
2354 /*!
2355   \reimp
2356 */
mimeData(const QModelIndexList & indexes) const2357 QMimeData *QSortFilterProxyModel::mimeData(const QModelIndexList &indexes) const
2358 {
2359     Q_D(const QSortFilterProxyModel);
2360     QModelIndexList source_indexes;
2361     source_indexes.reserve(indexes.count());
2362     for (const QModelIndex &idx : indexes)
2363         source_indexes << mapToSource(idx);
2364     return d->model->mimeData(source_indexes);
2365 }
2366 
2367 /*!
2368   \reimp
2369 */
mimeTypes() const2370 QStringList QSortFilterProxyModel::mimeTypes() const
2371 {
2372     Q_D(const QSortFilterProxyModel);
2373     return d->model->mimeTypes();
2374 }
2375 
2376 /*!
2377   \reimp
2378 */
supportedDropActions() const2379 Qt::DropActions QSortFilterProxyModel::supportedDropActions() const
2380 {
2381     Q_D(const QSortFilterProxyModel);
2382     return d->model->supportedDropActions();
2383 }
2384 
2385 // Qt6: remove unnecessary reimplementation
2386 /*!
2387   \reimp
2388 */
dropMimeData(const QMimeData * data,Qt::DropAction action,int row,int column,const QModelIndex & parent)2389 bool QSortFilterProxyModel::dropMimeData(const QMimeData *data, Qt::DropAction action,
2390                                          int row, int column, const QModelIndex &parent)
2391 {
2392     return QAbstractProxyModel::dropMimeData(data, action, row, column, parent);
2393 }
2394 
2395 /*!
2396   \reimp
2397 */
insertRows(int row,int count,const QModelIndex & parent)2398 bool QSortFilterProxyModel::insertRows(int row, int count, const QModelIndex &parent)
2399 {
2400     Q_D(QSortFilterProxyModel);
2401     if (row < 0 || count <= 0)
2402         return false;
2403     QModelIndex source_parent = mapToSource(parent);
2404     if (parent.isValid() && !source_parent.isValid())
2405         return false;
2406     QSortFilterProxyModelPrivate::Mapping *m = d->create_mapping(source_parent).value();
2407     if (row > m->source_rows.count())
2408         return false;
2409     int source_row = (row >= m->source_rows.count()
2410                       ? m->proxy_rows.count()
2411                       : m->source_rows.at(row));
2412     return d->model->insertRows(source_row, count, source_parent);
2413 }
2414 
2415 /*!
2416   \reimp
2417 */
insertColumns(int column,int count,const QModelIndex & parent)2418 bool QSortFilterProxyModel::insertColumns(int column, int count, const QModelIndex &parent)
2419 {
2420     Q_D(QSortFilterProxyModel);
2421     if (column < 0|| count <= 0)
2422         return false;
2423     QModelIndex source_parent = mapToSource(parent);
2424     if (parent.isValid() && !source_parent.isValid())
2425         return false;
2426     QSortFilterProxyModelPrivate::Mapping *m = d->create_mapping(source_parent).value();
2427     if (column > m->source_columns.count())
2428         return false;
2429     int source_column = (column >= m->source_columns.count()
2430                          ? m->proxy_columns.count()
2431                          : m->source_columns.at(column));
2432     return d->model->insertColumns(source_column, count, source_parent);
2433 }
2434 
2435 /*!
2436   \reimp
2437 */
removeRows(int row,int count,const QModelIndex & parent)2438 bool QSortFilterProxyModel::removeRows(int row, int count, const QModelIndex &parent)
2439 {
2440     Q_D(QSortFilterProxyModel);
2441     if (row < 0 || count <= 0)
2442         return false;
2443     QModelIndex source_parent = mapToSource(parent);
2444     if (parent.isValid() && !source_parent.isValid())
2445         return false;
2446     QSortFilterProxyModelPrivate::Mapping *m = d->create_mapping(source_parent).value();
2447     if (row + count > m->source_rows.count())
2448         return false;
2449     if ((count == 1)
2450         || ((d->source_sort_column < 0) && (m->proxy_rows.count() == m->source_rows.count()))) {
2451         int source_row = m->source_rows.at(row);
2452         return d->model->removeRows(source_row, count, source_parent);
2453     }
2454     // remove corresponding source intervals
2455     // ### if this proves to be slow, we can switch to single-row removal
2456     QVector<int> rows;
2457     rows.reserve(count);
2458     for (int i = row; i < row + count; ++i)
2459         rows.append(m->source_rows.at(i));
2460     std::sort(rows.begin(), rows.end());
2461 
2462     int pos = rows.count() - 1;
2463     bool ok = true;
2464     while (pos >= 0) {
2465         const int source_end = rows.at(pos--);
2466         int source_start = source_end;
2467         while ((pos >= 0) && (rows.at(pos) == (source_start - 1))) {
2468             --source_start;
2469             --pos;
2470         }
2471         ok = ok && d->model->removeRows(source_start, source_end - source_start + 1,
2472                                         source_parent);
2473     }
2474     return ok;
2475 }
2476 
2477 /*!
2478   \reimp
2479 */
removeColumns(int column,int count,const QModelIndex & parent)2480 bool QSortFilterProxyModel::removeColumns(int column, int count, const QModelIndex &parent)
2481 {
2482     Q_D(QSortFilterProxyModel);
2483     if (column < 0 || count <= 0)
2484         return false;
2485     QModelIndex source_parent = mapToSource(parent);
2486     if (parent.isValid() && !source_parent.isValid())
2487         return false;
2488     QSortFilterProxyModelPrivate::Mapping *m = d->create_mapping(source_parent).value();
2489     if (column + count > m->source_columns.count())
2490         return false;
2491     if ((count == 1) || (m->proxy_columns.count() == m->source_columns.count())) {
2492         int source_column = m->source_columns.at(column);
2493         return d->model->removeColumns(source_column, count, source_parent);
2494     }
2495     // remove corresponding source intervals
2496     QVector<int> columns;
2497     columns.reserve(count);
2498     for (int i = column; i < column + count; ++i)
2499         columns.append(m->source_columns.at(i));
2500 
2501     int pos = columns.count() - 1;
2502     bool ok = true;
2503     while (pos >= 0) {
2504         const int source_end = columns.at(pos--);
2505         int source_start = source_end;
2506         while ((pos >= 0) && (columns.at(pos) == (source_start - 1))) {
2507             --source_start;
2508             --pos;
2509         }
2510         ok = ok && d->model->removeColumns(source_start, source_end - source_start + 1,
2511                                            source_parent);
2512     }
2513     return ok;
2514 }
2515 
2516 /*!
2517   \reimp
2518 */
fetchMore(const QModelIndex & parent)2519 void QSortFilterProxyModel::fetchMore(const QModelIndex &parent)
2520 {
2521     Q_D(QSortFilterProxyModel);
2522     QModelIndex source_parent;
2523     if (d->indexValid(parent))
2524         source_parent = mapToSource(parent);
2525     d->model->fetchMore(source_parent);
2526 }
2527 
2528 /*!
2529   \reimp
2530 */
canFetchMore(const QModelIndex & parent) const2531 bool QSortFilterProxyModel::canFetchMore(const QModelIndex &parent) const
2532 {
2533     Q_D(const QSortFilterProxyModel);
2534     QModelIndex source_parent;
2535     if (d->indexValid(parent))
2536         source_parent = mapToSource(parent);
2537     return d->model->canFetchMore(source_parent);
2538 }
2539 
2540 /*!
2541   \reimp
2542 */
flags(const QModelIndex & index) const2543 Qt::ItemFlags QSortFilterProxyModel::flags(const QModelIndex &index) const
2544 {
2545     Q_D(const QSortFilterProxyModel);
2546     QModelIndex source_index;
2547     if (d->indexValid(index))
2548         source_index = mapToSource(index);
2549     return d->model->flags(source_index);
2550 }
2551 
2552 /*!
2553   \reimp
2554 */
buddy(const QModelIndex & index) const2555 QModelIndex QSortFilterProxyModel::buddy(const QModelIndex &index) const
2556 {
2557     Q_D(const QSortFilterProxyModel);
2558     if (!d->indexValid(index))
2559         return QModelIndex();
2560     QModelIndex source_index = mapToSource(index);
2561     QModelIndex source_buddy = d->model->buddy(source_index);
2562     if (source_index == source_buddy)
2563         return index;
2564     return mapFromSource(source_buddy);
2565 }
2566 
2567 /*!
2568   \reimp
2569 */
match(const QModelIndex & start,int role,const QVariant & value,int hits,Qt::MatchFlags flags) const2570 QModelIndexList QSortFilterProxyModel::match(const QModelIndex &start, int role,
2571                                              const QVariant &value, int hits,
2572                                              Qt::MatchFlags flags) const
2573 {
2574     return QAbstractProxyModel::match(start, role, value, hits, flags);
2575 }
2576 
2577 /*!
2578   \reimp
2579 */
span(const QModelIndex & index) const2580 QSize QSortFilterProxyModel::span(const QModelIndex &index) const
2581 {
2582     Q_D(const QSortFilterProxyModel);
2583     QModelIndex source_index = mapToSource(index);
2584     if (index.isValid() && !source_index.isValid())
2585         return QSize();
2586     return d->model->span(source_index);
2587 }
2588 
2589 /*!
2590   \reimp
2591 */
sort(int column,Qt::SortOrder order)2592 void QSortFilterProxyModel::sort(int column, Qt::SortOrder order)
2593 {
2594     Q_D(QSortFilterProxyModel);
2595     if (d->dynamic_sortfilter && d->proxy_sort_column == column && d->sort_order == order)
2596         return;
2597     d->sort_order = order;
2598     d->proxy_sort_column = column;
2599     d->update_source_sort_column();
2600     d->sort();
2601 }
2602 
2603 /*!
2604     \since 4.5
2605     \brief the column currently used for sorting
2606 
2607     This returns the most recently used sort column.
2608 */
sortColumn() const2609 int QSortFilterProxyModel::sortColumn() const
2610 {
2611     Q_D(const QSortFilterProxyModel);
2612     return d->proxy_sort_column;
2613 }
2614 
2615 /*!
2616     \since 4.5
2617     \brief the order currently used for sorting
2618 
2619     This returns the most recently used sort order.
2620 */
sortOrder() const2621 Qt::SortOrder QSortFilterProxyModel::sortOrder() const
2622 {
2623     Q_D(const QSortFilterProxyModel);
2624     return d->sort_order;
2625 }
2626 
2627 /*!
2628     \property QSortFilterProxyModel::filterRegExp
2629     \brief the QRegExp used to filter the contents of the source model
2630 
2631     Setting this property overwrites the current
2632     \l{QSortFilterProxyModel::filterCaseSensitivity}{filterCaseSensitivity}.
2633     By default, the QRegExp is an empty string matching all contents.
2634 
2635     If no QRegExp or an empty string is set, everything in the source model
2636     will be accepted.
2637 
2638     \sa filterCaseSensitivity, setFilterWildcard(), setFilterFixedString()
2639 */
filterRegExp() const2640 QRegExp QSortFilterProxyModel::filterRegExp() const
2641 {
2642     Q_D(const QSortFilterProxyModel);
2643     return d->filter_data.regExp();
2644 }
2645 
setFilterRegExp(const QRegExp & regExp)2646 void QSortFilterProxyModel::setFilterRegExp(const QRegExp &regExp)
2647 {
2648     Q_D(QSortFilterProxyModel);
2649     d->filter_about_to_be_changed();
2650     d->filter_data.setRegExp(regExp);
2651     d->filter_changed();
2652 }
2653 
2654 #if QT_CONFIG(regularexpression)
2655 /*!
2656     \since 5.12
2657     \property QSortFilterProxyModel::filterRegularExpression
2658     \brief the QRegularExpression used to filter the contents of the source model
2659 
2660     Setting this property overwrites the current
2661     \l{QSortFilterProxyModel::filterCaseSensitivity}{filterCaseSensitivity}.
2662     By default, the QRegularExpression is an empty string matching all contents.
2663 
2664     If no QRegularExpression or an empty string is set, everything in the source
2665     model will be accepted.
2666 
2667     \sa filterCaseSensitivity, setFilterWildcard(), setFilterFixedString()
2668 */
filterRegularExpression() const2669 QRegularExpression QSortFilterProxyModel::filterRegularExpression() const
2670 {
2671     Q_D(const QSortFilterProxyModel);
2672     return d->filter_data.regularExpression();
2673 }
2674 
setFilterRegularExpression(const QRegularExpression & regularExpression)2675 void QSortFilterProxyModel::setFilterRegularExpression(const QRegularExpression &regularExpression)
2676 {
2677     Q_D(QSortFilterProxyModel);
2678     d->filter_about_to_be_changed();
2679     d->filter_data.setRegularExpression(regularExpression);
2680     d->filter_changed();
2681 }
2682 #endif
2683 
2684 /*!
2685     \property QSortFilterProxyModel::filterKeyColumn
2686     \brief the column where the key used to filter the contents of the
2687     source model is read from.
2688 
2689     The default value is 0. If the value is -1, the keys will be read
2690     from all columns.
2691 */
filterKeyColumn() const2692 int QSortFilterProxyModel::filterKeyColumn() const
2693 {
2694     Q_D(const QSortFilterProxyModel);
2695     return d->filter_column;
2696 }
2697 
setFilterKeyColumn(int column)2698 void QSortFilterProxyModel::setFilterKeyColumn(int column)
2699 {
2700     Q_D(QSortFilterProxyModel);
2701     d->filter_about_to_be_changed();
2702     d->filter_column = column;
2703     d->filter_changed();
2704 }
2705 
2706 /*!
2707     \property QSortFilterProxyModel::filterCaseSensitivity
2708 
2709     \brief the case sensitivity of the QRegExp pattern used to filter the
2710     contents of the source model.
2711 
2712     By default, the filter is case sensitive.
2713 
2714     \sa filterRegExp, sortCaseSensitivity
2715 */
2716 
2717 /*!
2718     \since 5.15
2719     \fn void QSortFilterProxyModel::filterCaseSensitivityChanged(Qt::CaseSensitivity filterCaseSensitivity)
2720     \brief This signal is emitted when the case sensitivity of the filter
2721            changes to \a filterCaseSensitivity.
2722  */
filterCaseSensitivity() const2723 Qt::CaseSensitivity QSortFilterProxyModel::filterCaseSensitivity() const
2724 {
2725     Q_D(const QSortFilterProxyModel);
2726     return d->filter_data.caseSensitivity();
2727 }
2728 
setFilterCaseSensitivity(Qt::CaseSensitivity cs)2729 void QSortFilterProxyModel::setFilterCaseSensitivity(Qt::CaseSensitivity cs)
2730 {
2731     Q_D(QSortFilterProxyModel);
2732     if (cs == d->filter_data.caseSensitivity())
2733         return;
2734     d->filter_about_to_be_changed();
2735     d->filter_data.setCaseSensitivity(cs);
2736     d->filter_changed();
2737     emit filterCaseSensitivityChanged(cs);
2738 }
2739 
2740 /*!
2741     \since 4.2
2742     \property QSortFilterProxyModel::sortCaseSensitivity
2743     \brief the case sensitivity setting used for comparing strings when sorting
2744 
2745     By default, sorting is case sensitive.
2746 
2747     \sa filterCaseSensitivity, lessThan()
2748 */
2749 
2750 /*!
2751     \since 5.15
2752     \fn void QSortFilterProxyModel::sortCaseSensitivityChanged(Qt::CaseSensitivity sortCaseSensitivity)
2753     \brief This signal is emitted when the case sensitivity for sorting
2754            changes to \a sortCaseSensitivity.
2755 */
sortCaseSensitivity() const2756 Qt::CaseSensitivity QSortFilterProxyModel::sortCaseSensitivity() const
2757 {
2758     Q_D(const QSortFilterProxyModel);
2759     return d->sort_casesensitivity;
2760 }
2761 
setSortCaseSensitivity(Qt::CaseSensitivity cs)2762 void QSortFilterProxyModel::setSortCaseSensitivity(Qt::CaseSensitivity cs)
2763 {
2764     Q_D(QSortFilterProxyModel);
2765     if (d->sort_casesensitivity == cs)
2766         return;
2767 
2768     d->sort_casesensitivity = cs;
2769     d->sort();
2770     emit sortCaseSensitivityChanged(cs);
2771 }
2772 
2773 /*!
2774     \since 4.3
2775     \property QSortFilterProxyModel::isSortLocaleAware
2776     \brief the local aware setting used for comparing strings when sorting
2777 
2778     By default, sorting is not local aware.
2779 
2780     \sa sortCaseSensitivity, lessThan()
2781 */
2782 
2783 /*!
2784     \since 5.15
2785     \fn void QSortFilterProxyModel::sortLocaleAwareChanged(bool sortLocaleAware)
2786     \brief This signal is emitted when the locale aware setting
2787            changes to \a sortLocaleAware.
2788 */
isSortLocaleAware() const2789 bool QSortFilterProxyModel::isSortLocaleAware() const
2790 {
2791     Q_D(const QSortFilterProxyModel);
2792     return d->sort_localeaware;
2793 }
2794 
setSortLocaleAware(bool on)2795 void QSortFilterProxyModel::setSortLocaleAware(bool on)
2796 {
2797     Q_D(QSortFilterProxyModel);
2798     if (d->sort_localeaware == on)
2799         return;
2800 
2801     d->sort_localeaware = on;
2802     d->sort();
2803     emit sortLocaleAwareChanged(on);
2804 }
2805 
2806 /*!
2807     \overload
2808 
2809     Sets the regular expression used to filter the contents
2810     of the source model to \a pattern.
2811 
2812     \sa setFilterCaseSensitivity(), setFilterWildcard(), setFilterFixedString(), filterRegExp()
2813 */
setFilterRegExp(const QString & pattern)2814 void QSortFilterProxyModel::setFilterRegExp(const QString &pattern)
2815 {
2816     Q_D(QSortFilterProxyModel);
2817     d->filter_about_to_be_changed();
2818     QRegExp rx(pattern);
2819     rx.setCaseSensitivity(d->filter_data.caseSensitivity());
2820     d->filter_data.setRegExp(rx);
2821     d->filter_changed();
2822 }
2823 
2824 #if QT_CONFIG(regularexpression)
2825 /*!
2826     \since 5.12
2827 
2828     Sets the regular expression used to filter the contents
2829     of the source model to \a pattern.
2830 
2831     This method should be preferred for new code as it will use
2832     QRegularExpression internally.
2833 
2834     \sa setFilterCaseSensitivity(), setFilterWildcard(), setFilterFixedString(), filterRegularExpression()
2835 */
setFilterRegularExpression(const QString & pattern)2836 void QSortFilterProxyModel::setFilterRegularExpression(const QString &pattern)
2837 {
2838     Q_D(QSortFilterProxyModel);
2839     d->filter_about_to_be_changed();
2840     QRegularExpression rx(pattern,
2841                           d->filter_data.caseSensitivity()
2842                                   ? QRegularExpression::NoPatternOption
2843                                   : QRegularExpression::CaseInsensitiveOption);
2844     d->filter_data.setRegularExpression(rx);
2845     d->filter_changed();
2846 }
2847 #endif
2848 
2849 /*!
2850     Sets the wildcard expression used to filter the contents
2851     of the source model to the given \a pattern.
2852 
2853     \sa setFilterCaseSensitivity(), setFilterRegExp(), setFilterFixedString(), filterRegExp()
2854 */
setFilterWildcard(const QString & pattern)2855 void QSortFilterProxyModel::setFilterWildcard(const QString &pattern)
2856 {
2857     Q_D(QSortFilterProxyModel);
2858     d->filter_about_to_be_changed();
2859     QRegExp rx(pattern, d->filter_data.caseSensitivity(), QRegExp::Wildcard);
2860     d->filter_data.setRegExp(rx);
2861     d->filter_changed();
2862 }
2863 
2864 /*!
2865     Sets the fixed string used to filter the contents
2866     of the source model to the given \a pattern.
2867 
2868     \sa setFilterCaseSensitivity(), setFilterRegExp(), setFilterWildcard(), filterRegExp()
2869 */
setFilterFixedString(const QString & pattern)2870 void QSortFilterProxyModel::setFilterFixedString(const QString &pattern)
2871 {
2872     Q_D(QSortFilterProxyModel);
2873     d->filter_about_to_be_changed();
2874     QRegExp rx(pattern, d->filter_data.caseSensitivity(), QRegExp::FixedString);
2875     d->filter_data.setRegExp(rx);
2876     d->filter_changed();
2877 }
2878 
2879 /*!
2880     \since 4.2
2881     \property QSortFilterProxyModel::dynamicSortFilter
2882     \brief whether the proxy model is dynamically sorted and filtered
2883     whenever the contents of the source model change
2884 
2885     Note that you should not update the source model through the proxy
2886     model when dynamicSortFilter is true. For instance, if you set the
2887     proxy model on a QComboBox, then using functions that update the
2888     model, e.g., \l{QComboBox::}{addItem()}, will not work as
2889     expected. An alternative is to set dynamicSortFilter to false and
2890     call \l{QSortFilterProxyModel::}{sort()} after adding items to the
2891     QComboBox.
2892 
2893     The default value is true.
2894 */
dynamicSortFilter() const2895 bool QSortFilterProxyModel::dynamicSortFilter() const
2896 {
2897     Q_D(const QSortFilterProxyModel);
2898     return d->dynamic_sortfilter;
2899 }
2900 
setDynamicSortFilter(bool enable)2901 void QSortFilterProxyModel::setDynamicSortFilter(bool enable)
2902 {
2903     Q_D(QSortFilterProxyModel);
2904     d->dynamic_sortfilter = enable;
2905     if (enable)
2906         d->sort();
2907 }
2908 
2909 /*!
2910     \since 4.2
2911     \property QSortFilterProxyModel::sortRole
2912     \brief the item role that is used to query the source model's data when
2913            sorting items.
2914 
2915     The default value is Qt::DisplayRole.
2916 
2917     \sa lessThan()
2918 */
2919 
2920 /*!
2921     \since 5.15
2922     \fn void QSortFilterProxyModel::sortRoleChanged(int sortRole)
2923     \brief This signal is emitted when the sort role changes to \a sortRole.
2924 */
sortRole() const2925 int QSortFilterProxyModel::sortRole() const
2926 {
2927     Q_D(const QSortFilterProxyModel);
2928     return d->sort_role;
2929 }
2930 
setSortRole(int role)2931 void QSortFilterProxyModel::setSortRole(int role)
2932 {
2933     Q_D(QSortFilterProxyModel);
2934     if (d->sort_role == role)
2935         return;
2936     d->sort_role = role;
2937     d->sort();
2938     emit sortRoleChanged(role);
2939 }
2940 
2941 /*!
2942     \since 4.2
2943     \property QSortFilterProxyModel::filterRole
2944     \brief the item role that is used to query the source model's data when
2945            filtering items.
2946 
2947     The default value is Qt::DisplayRole.
2948 
2949     \sa filterAcceptsRow()
2950 */
2951 
2952 /*!
2953     \since 5.15
2954     \fn void QSortFilterProxyModel::filterRoleChanged(int filterRole)
2955     \brief This signal is emitted when the filter role changes to \a filterRole.
2956 */
filterRole() const2957 int QSortFilterProxyModel::filterRole() const
2958 {
2959     Q_D(const QSortFilterProxyModel);
2960     return d->filter_role;
2961 }
2962 
setFilterRole(int role)2963 void QSortFilterProxyModel::setFilterRole(int role)
2964 {
2965     Q_D(QSortFilterProxyModel);
2966     if (d->filter_role == role)
2967         return;
2968     d->filter_about_to_be_changed();
2969     d->filter_role = role;
2970     d->filter_changed();
2971     emit filterRoleChanged(role);
2972 }
2973 
2974 /*!
2975     \since 5.10
2976     \property QSortFilterProxyModel::recursiveFilteringEnabled
2977     \brief whether the filter to be applied recursively on children, and for
2978     any matching child, its parents will be visible as well.
2979 
2980     The default value is false.
2981 
2982     \sa filterAcceptsRow()
2983 */
2984 
2985 /*!
2986     \since 5.15
2987     \fn void QSortFilterProxyModel::recursiveFilteringEnabledChanged(bool recursiveFilteringEnabled)
2988     \brief This signal is emitted when the recursive filter setting is changed
2989            to \a recursiveFilteringEnabled.
2990 */
isRecursiveFilteringEnabled() const2991 bool QSortFilterProxyModel::isRecursiveFilteringEnabled() const
2992 {
2993     Q_D(const QSortFilterProxyModel);
2994     return d->filter_recursive;
2995 }
2996 
setRecursiveFilteringEnabled(bool recursive)2997 void QSortFilterProxyModel::setRecursiveFilteringEnabled(bool recursive)
2998 {
2999     Q_D(QSortFilterProxyModel);
3000     if (d->filter_recursive == recursive)
3001         return;
3002     d->filter_about_to_be_changed();
3003     d->filter_recursive = recursive;
3004     d->filter_changed();
3005     emit recursiveFilteringEnabledChanged(recursive);
3006 }
3007 
3008 #if QT_DEPRECATED_SINCE(5, 11)
3009 /*!
3010     \obsolete
3011 
3012     This function is obsolete. Use invalidate() instead.
3013 */
clear()3014 void QSortFilterProxyModel::clear()
3015 {
3016     invalidate();
3017 }
3018 #endif
3019 /*!
3020    \since 4.3
3021 
3022     Invalidates the current sorting and filtering.
3023 
3024     \sa invalidateFilter()
3025 */
invalidate()3026 void QSortFilterProxyModel::invalidate()
3027 {
3028     Q_D(QSortFilterProxyModel);
3029     emit layoutAboutToBeChanged();
3030     d->_q_clearMapping();
3031     emit layoutChanged();
3032 }
3033 
3034 #if QT_DEPRECATED_SINCE(5, 11)
3035 /*!
3036    \obsolete
3037 
3038     This function is obsolete. Use invalidateFilter() instead.
3039 */
filterChanged()3040 void QSortFilterProxyModel::filterChanged()
3041 {
3042     invalidateFilter();
3043 }
3044 #endif
3045 
3046 /*!
3047    \since 4.3
3048 
3049    Invalidates the current filtering.
3050 
3051    This function should be called if you are implementing custom filtering
3052    (e.g. filterAcceptsRow()), and your filter parameters have changed.
3053 
3054    \sa invalidate()
3055 */
invalidateFilter()3056 void QSortFilterProxyModel::invalidateFilter()
3057 {
3058     Q_D(QSortFilterProxyModel);
3059     d->filter_changed();
3060 }
3061 
3062 /*!
3063     Returns \c true if the value of the item referred to by the given
3064     index \a source_left is less than the value of the item referred to by
3065     the given index \a source_right, otherwise returns \c false.
3066 
3067     This function is used as the < operator when sorting, and handles
3068     the following QVariant types:
3069 
3070     \list
3071     \li QMetaType::Int
3072     \li QMetaType::UInt
3073     \li QMetaType::LongLong
3074     \li QMetaType::ULongLong
3075     \li QMetaType::Float
3076     \li QMetaType::Double
3077     \li QMetaType::QChar
3078     \li QMetaType::QDate
3079     \li QMetaType::QTime
3080     \li QMetaType::QDateTime
3081     \li QMetaType::QString
3082     \endlist
3083 
3084     Any other type will be converted to a QString using
3085     QVariant::toString().
3086 
3087     Comparison of \l{QString}s is case sensitive by default; this can
3088     be changed using the \l {QSortFilterProxyModel::sortCaseSensitivity}
3089     {sortCaseSensitivity} property.
3090 
3091     By default, the Qt::DisplayRole associated with the
3092     \l{QModelIndex}es is used for comparisons. This can be changed by
3093     setting the \l {QSortFilterProxyModel::sortRole} {sortRole} property.
3094 
3095     \note The indices passed in correspond to the source model.
3096 
3097     \sa sortRole, sortCaseSensitivity, dynamicSortFilter
3098 */
lessThan(const QModelIndex & source_left,const QModelIndex & source_right) const3099 bool QSortFilterProxyModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const
3100 {
3101     Q_D(const QSortFilterProxyModel);
3102     QVariant l = (source_left.model() ? source_left.model()->data(source_left, d->sort_role) : QVariant());
3103     QVariant r = (source_right.model() ? source_right.model()->data(source_right, d->sort_role) : QVariant());
3104     return QAbstractItemModelPrivate::isVariantLessThan(l, r, d->sort_casesensitivity, d->sort_localeaware);
3105 }
3106 
3107 /*!
3108     Returns \c true if the item in the row indicated by the given \a source_row
3109     and \a source_parent should be included in the model; otherwise returns
3110     false.
3111 
3112     The default implementation returns \c true if the value held by the relevant item
3113     matches the filter string, wildcard string or regular expression.
3114 
3115     \note By default, the Qt::DisplayRole is used to determine if the row
3116     should be accepted or not. This can be changed by setting the
3117     \l{QSortFilterProxyModel::filterRole}{filterRole} property.
3118 
3119     \sa filterAcceptsColumn(), setFilterFixedString(), setFilterRegExp(), setFilterWildcard()
3120 */
filterAcceptsRow(int source_row,const QModelIndex & source_parent) const3121 bool QSortFilterProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
3122 {
3123     Q_D(const QSortFilterProxyModel);
3124 
3125     if (d->filter_data.isEmpty())
3126         return true;
3127 
3128     int column_count = d->model->columnCount(source_parent);
3129     if (d->filter_column == -1) {
3130         for (int column = 0; column < column_count; ++column) {
3131             QModelIndex source_index = d->model->index(source_row, column, source_parent);
3132             QString key = d->model->data(source_index, d->filter_role).toString();
3133             if (d->filter_data.hasMatch(key))
3134                 return true;
3135         }
3136         return false;
3137     }
3138 
3139     if (d->filter_column >= column_count) // the column may not exist
3140         return true;
3141     QModelIndex source_index = d->model->index(source_row, d->filter_column, source_parent);
3142     QString key = d->model->data(source_index, d->filter_role).toString();
3143     return d->filter_data.hasMatch(key);
3144 }
3145 
3146 /*!
3147     Returns \c true if the item in the column indicated by the given \a source_column
3148     and \a source_parent should be included in the model; otherwise returns \c false.
3149 
3150     \note The default implementation always returns \c true. You must reimplement this
3151     method to get the described behavior.
3152 
3153     \sa filterAcceptsRow(), setFilterFixedString(), setFilterRegExp(), setFilterWildcard()
3154 */
filterAcceptsColumn(int source_column,const QModelIndex & source_parent) const3155 bool QSortFilterProxyModel::filterAcceptsColumn(int source_column, const QModelIndex &source_parent) const
3156 {
3157     Q_UNUSED(source_column);
3158     Q_UNUSED(source_parent);
3159     return true;
3160 }
3161 
3162 /*!
3163    Returns the source model index corresponding to the given \a
3164    proxyIndex from the sorting filter model.
3165 
3166    \sa mapFromSource()
3167 */
mapToSource(const QModelIndex & proxyIndex) const3168 QModelIndex QSortFilterProxyModel::mapToSource(const QModelIndex &proxyIndex) const
3169 {
3170     Q_D(const QSortFilterProxyModel);
3171     return d->proxy_to_source(proxyIndex);
3172 }
3173 
3174 /*!
3175     Returns the model index in the QSortFilterProxyModel given the \a
3176     sourceIndex from the source model.
3177 
3178     \sa mapToSource()
3179 */
mapFromSource(const QModelIndex & sourceIndex) const3180 QModelIndex QSortFilterProxyModel::mapFromSource(const QModelIndex &sourceIndex) const
3181 {
3182     Q_D(const QSortFilterProxyModel);
3183     return d->source_to_proxy(sourceIndex);
3184 }
3185 
3186 /*!
3187   \reimp
3188 */
mapSelectionToSource(const QItemSelection & proxySelection) const3189 QItemSelection QSortFilterProxyModel::mapSelectionToSource(const QItemSelection &proxySelection) const
3190 {
3191     return QAbstractProxyModel::mapSelectionToSource(proxySelection);
3192 }
3193 
3194 /*!
3195   \reimp
3196 */
mapSelectionFromSource(const QItemSelection & sourceSelection) const3197 QItemSelection QSortFilterProxyModel::mapSelectionFromSource(const QItemSelection &sourceSelection) const
3198 {
3199     return QAbstractProxyModel::mapSelectionFromSource(sourceSelection);
3200 }
3201 
3202 QT_END_NAMESPACE
3203 
3204 #include "moc_qsortfilterproxymodel.cpp"
3205