QAbstractProxyModel: delay headerDataChanged emissions when inserting/removing rows/columns

33c88f86b5 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 <axel.spoerl@qt.io>
Reviewed-by: David Faure <david.faure@kdab.com>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
This commit is contained in:
Giuseppe D'Angelo 2023-06-22 17:01:41 +02:00
parent 5546f2df53
commit a0bcad3903
2 changed files with 13 additions and 6 deletions

View File

@ -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);
}
}

View File

@ -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::Orientation>(), Qt::Horizontal);
QCOMPARE(headerDataChangedSpy[0][1].value<int>(), 0);
QCOMPARE(headerDataChangedSpy[0][2].value<int>(), 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::Orientation>(), Qt::Horizontal);
QCOMPARE(headerDataChangedSpy[1][1].value<int>(), 0);
QCOMPARE(headerDataChangedSpy[1][2].value<int>(), 4);