From 14ee33105256d3e23e6ef3d6a10e4f71b688da3d Mon Sep 17 00:00:00 2001 From: Ievgenii Meshcheriakov Date: Fri, 8 Dec 2023 12:06:20 +0100 Subject: [PATCH] QAbstractProxyModel: Emit headerDataChanged() signal with valid data This amends commit a0bcad39033bddd9b9d14a524b829513105913d3. Delayed signals emitted by the previous commit may have invalid parameters if the source model was updated several times before entering the event loop. This commit fixes that by evaluating the section range immediately before emitting the signal. This commit also ensures that the signal is emitted only once after entering the event loop. Fixes: QTBUG-119155 Pick-to: 6.5 Change-Id: I9e84703cca26fde8464a6b9a414bb7462cbb9abd Reviewed-by: David Faure (cherry picked from commit 734354c0bae543795222a47cca2a013352d49745) Reviewed-by: Qt Cherry-pick Bot (cherry picked from commit f77af7014848d1ebba96a932b4b836efd963582f) --- .../itemmodels/qabstractproxymodel.cpp | 69 +++++++++++-------- .../itemmodels/qabstractproxymodel_p.h | 9 ++- 2 files changed, 48 insertions(+), 30 deletions(-) diff --git a/src/corelib/itemmodels/qabstractproxymodel.cpp b/src/corelib/itemmodels/qabstractproxymodel.cpp index 83e8cb8db3c..abdeefb4da6 100644 --- a/src/corelib/itemmodels/qabstractproxymodel.cpp +++ b/src/corelib/itemmodels/qabstractproxymodel.cpp @@ -55,11 +55,39 @@ void QAbstractProxyModelPrivate::_q_sourceModelDestroyed() model = QAbstractItemModelPrivate::staticEmptyModel(); } -static auto emitHeaderDataChanged(QAbstractItemModel *model, - Qt::Orientation orientation, - int count) +void QAbstractProxyModelPrivate::emitHeaderDataChanged() { - return [=](){ emit model->headerDataChanged(orientation, 0, count); }; + Q_Q(QAbstractProxyModel); + + if (updateHorizontalHeader) { + if (auto columnCount = q->columnCount(); columnCount > 0) + emit q->headerDataChanged(Qt::Horizontal, 0, columnCount - 1); + } + + if (updateVerticalHeader) { + if (auto rowCount = q->rowCount(); rowCount > 0) + emit q->headerDataChanged(Qt::Vertical, 0, rowCount - 1); + } + + updateHorizontalHeader = false; + updateVerticalHeader = false; +} + +void QAbstractProxyModelPrivate::scheduleHeaderUpdate(Qt::Orientation orientation) +{ + const bool isUpdateScheduled = updateHorizontalHeader || updateVerticalHeader; + + if (orientation == Qt::Horizontal && !updateHorizontalHeader) + updateHorizontalHeader = true; + else if (orientation == Qt::Vertical && !updateVerticalHeader) + updateVerticalHeader = true; + else + return; + + if (!isUpdateScheduled) { + Q_Q(QAbstractProxyModel); + QMetaObject::invokeMethod(q, [this]() { emitHeaderDataChanged(); }, Qt::QueuedConnection); + } } void QAbstractProxyModelPrivate::_q_sourceModelRowsAboutToBeInserted(const QModelIndex &parent, int, int) @@ -73,25 +101,16 @@ void QAbstractProxyModelPrivate::_q_sourceModelRowsInserted(const QModelIndex &p { if (parent.isValid()) return; - if (sourceHadZeroRows) { - Q_Q(QAbstractProxyModel); - const int columnCount = q->columnCount(); - if (columnCount > 0) - QMetaObject::invokeMethod(q, emitHeaderDataChanged(q, Qt::Horizontal, columnCount - 1), Qt::QueuedConnection); - } + if (sourceHadZeroRows) + scheduleHeaderUpdate(Qt::Horizontal); } - void QAbstractProxyModelPrivate::_q_sourceModelRowsRemoved(const QModelIndex &parent, int, int) { if (parent.isValid()) return; - if (model->rowCount() == 0) { - Q_Q(QAbstractProxyModel); - const int columnCount = q->columnCount(); - if (columnCount > 0) - QMetaObject::invokeMethod(q, emitHeaderDataChanged(q, Qt::Horizontal, columnCount - 1), Qt::QueuedConnection); - } + if (model->rowCount() == 0) + scheduleHeaderUpdate(Qt::Horizontal); } void QAbstractProxyModelPrivate::_q_sourceModelColumnsAboutToBeInserted(const QModelIndex &parent, int, int) @@ -105,24 +124,16 @@ void QAbstractProxyModelPrivate::_q_sourceModelColumnsInserted(const QModelIndex { if (parent.isValid()) return; - if (sourceHadZeroColumns) { - Q_Q(QAbstractProxyModel); - const int rowCount = q->rowCount(); - if (rowCount > 0) - QMetaObject::invokeMethod(q, emitHeaderDataChanged(q, Qt::Vertical, rowCount - 1), Qt::QueuedConnection); - } + if (sourceHadZeroColumns) + scheduleHeaderUpdate(Qt::Vertical); } void QAbstractProxyModelPrivate::_q_sourceModelColumnsRemoved(const QModelIndex &parent, int, int) { if (parent.isValid()) return; - if (model->columnCount() == 0) { - Q_Q(QAbstractProxyModel); - const int rowCount = q->rowCount(); - if (rowCount > 0) - QMetaObject::invokeMethod(q, emitHeaderDataChanged(q, Qt::Vertical, rowCount - 1), Qt::QueuedConnection); - } + if (model->columnCount() == 0) + scheduleHeaderUpdate(Qt::Vertical); } /*! diff --git a/src/corelib/itemmodels/qabstractproxymodel_p.h b/src/corelib/itemmodels/qabstractproxymodel_p.h index 678ec4804fb..c495c78f75d 100644 --- a/src/corelib/itemmodels/qabstractproxymodel_p.h +++ b/src/corelib/itemmodels/qabstractproxymodel_p.h @@ -30,7 +30,9 @@ public: QAbstractProxyModelPrivate() : QAbstractItemModelPrivate(), sourceHadZeroRows(false), - sourceHadZeroColumns(false) + sourceHadZeroColumns(false), + updateVerticalHeader(false), + updateHorizontalHeader(false) {} void setModelForwarder(QAbstractItemModel *sourceModel) { @@ -57,8 +59,13 @@ public: void mapDropCoordinatesToSource(int row, int column, const QModelIndex &parent, int *source_row, int *source_column, QModelIndex *source_parent) const; + void scheduleHeaderUpdate(Qt::Orientation orientation); + void emitHeaderDataChanged(); + unsigned int sourceHadZeroRows : 1; unsigned int sourceHadZeroColumns : 1; + unsigned int updateVerticalHeader : 1; + unsigned int updateHorizontalHeader : 1; }; QT_END_NAMESPACE