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
|