summaryrefslogtreecommitdiff
path: root/extra/qt/qsortfilterproxymodel.patch
blob: 33770e47de0b95205cdb957ad445d6929e8da1bb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
From 989e6c5ee6f3e38b24632ec5caf49c5b03d17aed Mon Sep 17 00:00:00 2001
From: Stephen Kelly <stephen.kelly@kdab.com>
Date: Fri, 14 Sep 2012 15:42:34 +0200
Subject: [PATCH] Fix crash when invalidating a QSortFilterProxyModel

Backport of d7a15fbfd93fb566c7793596ea50d8786b9eb654 from qtbase.

Task-number: QTBUG-27122
Change-Id: I0b1eda292fd9648e6f08629f7a069b66bb8b59e8
Reviewed-by: Olivier Goffart <ogoffart@woboq.com>
---
 src/gui/itemviews/qsortfilterproxymodel.cpp        | 28 +++++++---
 .../tst_qsortfilterproxymodel.cpp                  | 61 ++++++++++++++++++++++
 2 files changed, 83 insertions(+), 6 deletions(-)

diff --git a/src/gui/itemviews/qsortfilterproxymodel.cpp b/src/gui/itemviews/qsortfilterproxymodel.cpp
index d937b63..9fe224e 100644
--- a/src/gui/itemviews/qsortfilterproxymodel.cpp
+++ b/src/gui/itemviews/qsortfilterproxymodel.cpp
@@ -1036,18 +1036,34 @@ void QSortFilterProxyModelPrivate::filter_changed(const QModelIndex &source_pare
     Mapping *m = it.value();
     QSet<int> rows_removed = handle_filter_changed(m->proxy_rows, m->source_rows, source_parent, Qt::Vertical);
     QSet<int> columns_removed = handle_filter_changed(m->proxy_columns, m->source_columns, source_parent, Qt::Horizontal);
-    QVector<QModelIndex> mappedChildren = m->mapped_children;
-    QVector<QModelIndex>::iterator it2 = mappedChildren.end();
-    while (it2 != mappedChildren.begin()) {
-        --it2;
-        const QModelIndex source_child_index = *it2;
+
+    // We need to iterate over a copy of m->mapped_children because otherwise it may be changed by other code, invalidating
+    // the iterator it2.
+    // The m->mapped_children vector can be appended to with indexes which are no longer filtered
+    // out (in create_mapping) when this function recurses for child indexes.
+    const QVector<QModelIndex> mappedChildren = m->mapped_children;
+    QVector<int> indexesToRemove;
+    for (int i = 0; i < mappedChildren.size(); ++i) {
+        const QModelIndex source_child_index = mappedChildren.at(i);
         if (rows_removed.contains(source_child_index.row()) || columns_removed.contains(source_child_index.column())) {
-            it2 = mappedChildren.erase(it2);
+            indexesToRemove.push_back(i);
             remove_from_mapping(source_child_index);
         } else {
             filter_changed(source_child_index);
         }
     }
+    QVector<int>::const_iterator removeIt = indexesToRemove.constEnd();
+    const QVector<int>::const_iterator removeBegin = indexesToRemove.constBegin();
+
+    // We can't just remove these items from mappedChildren while iterating above and then
+    // do something like m->mapped_children = mappedChildren, because mapped_children might
+    // be appended to in create_mapping, and we would lose those new items.
+    // Because they are always appended in create_mapping, we can still remove them by
+    // position here.
+    while (removeIt != removeBegin) {
+        --removeIt;
+        m->mapped_children.remove(*removeIt);
+    }
 }
 
 /*!
-- 
1.8.0