Fix crash when invalidating a QSortFilterProxyModel
Task-number: QTBUG-27122 Change-Id: Ibca46b88442f4f92422d9b3182e4bbf25716a07f Reviewed-by: Olivier Goffart <ogoffart@woboq.com>bb10
parent
5c412fd74c
commit
d7a15fbfd9
|
|
@ -1052,21 +1052,31 @@ void QSortFilterProxyModelPrivate::filter_changed(const QModelIndex &source_pare
|
|||
|
||||
// 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 when this function recurses for child indexes.
|
||||
// The handle_filter_changed implementation can cause source_parent.parent() to be called, which will create
|
||||
// a mapping (and do appending) while we are invalidating the filter.
|
||||
QVector<QModelIndex> mappedChildren = m->mapped_children;
|
||||
QVector<QModelIndex>::iterator it2 = mappedChildren.end();
|
||||
while (it2 != mappedChildren.begin()) {
|
||||
--it2;
|
||||
const QModelIndex source_child_index = *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);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
|
|||
|
|
@ -146,6 +146,7 @@ private slots:
|
|||
void moveSourceRows();
|
||||
|
||||
void hierarchyFilterInvalidation();
|
||||
void simpleFilterInvalidation();
|
||||
|
||||
protected:
|
||||
void buildHierarchy(const QStringList &data, QAbstractItemModel *model);
|
||||
|
|
@ -3582,6 +3583,64 @@ void tst_QSortFilterProxyModel::hierarchyFilterInvalidation()
|
|||
proxy.setMode(true);
|
||||
}
|
||||
|
||||
class FilterProxy2 : public QSortFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
FilterProxy2(QObject *parent = 0)
|
||||
: QSortFilterProxyModel(parent),
|
||||
mode(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public slots:
|
||||
void setMode(bool on)
|
||||
{
|
||||
mode = on;
|
||||
invalidateFilter();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual bool filterAcceptsRow ( int source_row, const QModelIndex & source_parent ) const
|
||||
{
|
||||
if (source_parent.isValid()) {
|
||||
return true;
|
||||
} else {
|
||||
if (0 == source_row) {
|
||||
return true;
|
||||
} else {
|
||||
return !mode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool mode;
|
||||
};
|
||||
|
||||
void tst_QSortFilterProxyModel::simpleFilterInvalidation()
|
||||
{
|
||||
QStandardItemModel model;
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
QStandardItem *child = new QStandardItem(QString("Row %1").arg(i));
|
||||
child->appendRow(new QStandardItem("child"));
|
||||
model.appendRow(child);
|
||||
}
|
||||
|
||||
FilterProxy2 proxy;
|
||||
proxy.setSourceModel(&model);
|
||||
|
||||
QTreeView view;
|
||||
view.setModel(&proxy);
|
||||
|
||||
view.show();
|
||||
QTest::qWaitForWindowExposed(&view);
|
||||
|
||||
proxy.setMode(true);
|
||||
model.insertRow(0, new QStandardItem("extra"));
|
||||
}
|
||||
|
||||
|
||||
QTEST_MAIN(tst_QSortFilterProxyModel)
|
||||
#include "tst_qsortfilterproxymodel.moc"
|
||||
|
|
|
|||
Loading…
Reference in New Issue