Fix segfault when delegates change properties on editors.
authorStephen Kelly <stephen.kelly@kdab.com>
Tue, 2 Oct 2012 16:15:33 +0000 (18:15 +0200)
committerThe Qt Project <gerrit-noreply@qt-project.org>
Thu, 4 Oct 2012 10:15:49 +0000 (12:15 +0200)
The solution is similar to that
in b84e180263d0da3d1e6967fcf759225a778ea6ea which affected
QSortFilterProxyModel.

Task-number: QTBUG-25370

Change-Id: I6bbb9d9786bcb2c9fa8027ab8a7cc13664784b8d
Reviewed-by: Marc Mutz <marc.mutz@kdab.com>
src/widgets/itemviews/qabstractitemview.cpp
tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp

index e34123a..b30bdbb 100644 (file)
@@ -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() ||
index 3be28b8..8ccd13f 100644 (file)
@@ -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<QWidget *>(&view), QApplication::activeWindow());
+
+    model.emitDataChanged();
+    // No segfault - the test passes.
+}
+
 QTEST_MAIN(tst_QAbstractItemView)
 #include "tst_qabstractitemview.moc"