From f37d3e2cd9aae156dc58a0e9f057e78dadda7b93 Mon Sep 17 00:00:00 2001 From: Stephen Kelly Date: Tue, 2 Oct 2012 18:15:33 +0200 Subject: [PATCH] Fix segfault when delegates change properties on editors. The solution is similar to that in b84e180263d0da3d1e6967fcf759225a778ea6ea which affected QSortFilterProxyModel. Task-number: QTBUG-25370 Change-Id: I6bbb9d9786bcb2c9fa8027ab8a7cc13664784b8d Reviewed-by: Marc Mutz --- src/widgets/itemviews/qabstractitemview.cpp | 8 +++- .../qabstractitemview/tst_qabstractitemview.cpp | 56 ++++++++++++++++++++++ 2 files changed, 62 insertions(+), 2 deletions(-) diff --git a/src/widgets/itemviews/qabstractitemview.cpp b/src/widgets/itemviews/qabstractitemview.cpp index e34123a..b30bdbb 100644 --- a/src/widgets/itemviews/qabstractitemview.cpp +++ b/src/widgets/itemviews/qabstractitemview.cpp @@ -4118,8 +4118,12 @@ void QAbstractItemViewPrivate::updateEditorData(const QModelIndex &tl, const QMo // we are counting on having relatively few editors const bool checkIndexes = tl.isValid() && br.isValid(); const QModelIndex parent = tl.parent(); - QIndexEditorHash::const_iterator it = indexEditorHash.constBegin(); - for (; it != indexEditorHash.constEnd(); ++it) { + // QTBUG-25370: We need to copy the indexEditorHash, because while we're + // iterating over it, we are calling methods which can allow user code to + // call a method on *this which can modify the member indexEditorHash. + const QIndexEditorHash indexEditorHashCopy = indexEditorHash; + QIndexEditorHash::const_iterator it = indexEditorHashCopy.constBegin(); + for (; it != indexEditorHashCopy.constEnd(); ++it) { QWidget *editor = it.value().widget.data(); const QModelIndex index = it.key(); if (it.value().isStatic || !editor || !index.isValid() || diff --git a/tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp b/tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp index 3be28b8..8ccd13f 100644 --- a/tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp +++ b/tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp @@ -226,6 +226,7 @@ private slots: void QTBUG6753_selectOnSelection(); void testDelegateDestroyEditor(); void testClickedSignal(); + void testChangeEditorState(); }; class MyAbstractItemDelegate : public QAbstractItemDelegate @@ -1534,5 +1535,60 @@ void tst_QAbstractItemView::testClickedSignal() } +class StateChangeDelegate : public QItemDelegate { + Q_OBJECT + +public: + explicit StateChangeDelegate(QObject* parent = 0) : + QItemDelegate(parent) + {} + + void setEditorData(QWidget *editor, const QModelIndex &index) const Q_DECL_OVERRIDE { + static bool w = true; + editor->setEnabled(w); + w = !w; + } +}; + +class StateChangeModel : public QStandardItemModel { + Q_OBJECT + +public: + explicit StateChangeModel(QObject *parent = 0) : + QStandardItemModel(parent) + {} + + void emitDataChanged() { + emit dataChanged(index(0, 0), index(0, 1)); + } +}; + + +void tst_QAbstractItemView::testChangeEditorState() +{ + // Test for QTBUG-25370 + StateChangeModel model; + { + QStandardItem* item = new QStandardItem("a"); + model.setItem(0, 0, item); + } + { + QStandardItem* item = new QStandardItem("b"); + model.setItem(0, 1, item); + } + + QTableView view; + view.setEditTriggers(QAbstractItemView::CurrentChanged); + view.setItemDelegate(new StateChangeDelegate); + view.setModel(&model); + view.show(); + QApplication::setActiveWindow(&view); + QVERIFY(QTest::qWaitForWindowActive(&view)); + QCOMPARE(static_cast(&view), QApplication::activeWindow()); + + model.emitDataChanged(); + // No segfault - the test passes. +} + QTEST_MAIN(tst_QAbstractItemView) #include "tst_qabstractitemview.moc" -- 2.7.4