From a0bcad39033bddd9b9d14a524b829513105913d3 Mon Sep 17 00:00:00 2001 From: Giuseppe D'Angelo Date: Thu, 22 Jun 2023 17:01:41 +0200 Subject: [PATCH] QAbstractProxyModel: delay headerDataChanged emissions when inserting/removing rows/columns 33c88f86b5b8714977719a8ccff0f7c15c9cbd44 added some logic to QAPM in order to have it automatically emit headerDataChanged when rows/columns were added or removed in the model. This was done as a stopgap measure to prevent QAPM from asking for illegal indices in order to implement automatic remapping of the section headings (since there's no mapSectionToSource). The commit seems to have introduced a regression in QHeaderView, which isn't prepared to receive headerDataChanged while a row/column count change is in progress. When receiving headerDataChanged, QHeaderView will try to read the row/column count and will store it internally. When it will then receive the signals for insertion/removal of rows/columns, it will interpret it as a modification of the previously stored value -- even if the value it stored was already correct. Fix this by avoiding to have two signals in flight at the same time; emit headerDataChanged as a queued invocation. Task-number: QTBUG-114225 Change-Id: I521465a852b8c7135f22f730ead41dca760ba428 Pick-to: 6.5 6.6 Reviewed-by: Axel Spoerl Reviewed-by: David Faure Reviewed-by: Qt CI Bot --- src/corelib/itemmodels/qabstractproxymodel.cpp | 15 +++++++++++---- .../tst_qabstractproxymodel.cpp | 4 ++-- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/corelib/itemmodels/qabstractproxymodel.cpp b/src/corelib/itemmodels/qabstractproxymodel.cpp index c0321ee282..12974b5aaa 100644 --- a/src/corelib/itemmodels/qabstractproxymodel.cpp +++ b/src/corelib/itemmodels/qabstractproxymodel.cpp @@ -55,6 +55,13 @@ void QAbstractProxyModelPrivate::_q_sourceModelDestroyed() model = QAbstractItemModelPrivate::staticEmptyModel(); } +static auto emitHeaderDataChanged(QAbstractItemModel *model, + Qt::Orientation orientation, + int count) +{ + return [=](){ emit model->headerDataChanged(orientation, 0, count); }; +} + void QAbstractProxyModelPrivate::_q_sourceModelRowsAboutToBeInserted(const QModelIndex &parent, int, int) { if (parent.isValid()) @@ -70,7 +77,7 @@ void QAbstractProxyModelPrivate::_q_sourceModelRowsInserted(const QModelIndex &p Q_Q(QAbstractProxyModel); const int columnCount = q->columnCount(); if (columnCount > 0) - emit q->headerDataChanged(Qt::Horizontal, 0, columnCount - 1); + QMetaObject::invokeMethod(q, emitHeaderDataChanged(q, Qt::Horizontal, columnCount - 1), Qt::QueuedConnection); } } @@ -83,7 +90,7 @@ void QAbstractProxyModelPrivate::_q_sourceModelRowsRemoved(const QModelIndex &pa Q_Q(QAbstractProxyModel); const int columnCount = q->columnCount(); if (columnCount > 0) - emit q->headerDataChanged(Qt::Horizontal, 0, columnCount - 1); + QMetaObject::invokeMethod(q, emitHeaderDataChanged(q, Qt::Horizontal, columnCount - 1), Qt::QueuedConnection); } } @@ -102,7 +109,7 @@ void QAbstractProxyModelPrivate::_q_sourceModelColumnsInserted(const QModelIndex Q_Q(QAbstractProxyModel); const int rowCount = q->rowCount(); if (rowCount > 0) - emit q->headerDataChanged(Qt::Vertical, 0, rowCount - 1); + QMetaObject::invokeMethod(q, emitHeaderDataChanged(q, Qt::Vertical, rowCount - 1), Qt::QueuedConnection); } } @@ -114,7 +121,7 @@ void QAbstractProxyModelPrivate::_q_sourceModelColumnsRemoved(const QModelIndex Q_Q(QAbstractProxyModel); const int rowCount = q->rowCount(); if (rowCount > 0) - emit q->headerDataChanged(Qt::Vertical, 0, rowCount - 1); + QMetaObject::invokeMethod(q, emitHeaderDataChanged(q, Qt::Vertical, rowCount - 1), Qt::QueuedConnection); } } diff --git a/tests/auto/corelib/itemmodels/qabstractproxymodel/tst_qabstractproxymodel.cpp b/tests/auto/corelib/itemmodels/qabstractproxymodel/tst_qabstractproxymodel.cpp index 3bea468e5b..d04d148fc3 100644 --- a/tests/auto/corelib/itemmodels/qabstractproxymodel/tst_qabstractproxymodel.cpp +++ b/tests/auto/corelib/itemmodels/qabstractproxymodel/tst_qabstractproxymodel.cpp @@ -225,7 +225,7 @@ void tst_QAbstractProxyModel::headerDataInBounds() QCOMPARE(proxy.rowCount(), 1); QCOMPARE(proxy.columnCount(), 5); - QCOMPARE(headerDataChangedSpy.size(), 1); + QTRY_COMPARE(headerDataChangedSpy.size(), 1); QCOMPARE(headerDataChangedSpy[0][0].value(), Qt::Horizontal); QCOMPARE(headerDataChangedSpy[0][1].value(), 0); QCOMPARE(headerDataChangedSpy[0][2].value(), 4); @@ -266,7 +266,7 @@ void tst_QAbstractProxyModel::headerDataInBounds() QCOMPARE(proxy.rowCount(), 0); QCOMPARE(proxy.columnCount(), 5); - QCOMPARE(headerDataChangedSpy.size(), 2); + QTRY_COMPARE(headerDataChangedSpy.size(), 2); QCOMPARE(headerDataChangedSpy[1][0].value(), Qt::Horizontal); QCOMPARE(headerDataChangedSpy[1][1].value(), 0); QCOMPARE(headerDataChangedSpy[1][2].value(), 4);