Fix QTreeModel calling beginRemoveRows twice

For items that are children of other items, removeRows calls
beginRemoveRows directly and then once again inside takeChild()
The signal blocker that dates back to the monolitic import from Nokia
prevents the model from emitting extra signals
but the persistent indexes are corrupted nonetheless.

Fixes: QTBUG-90030
Change-Id: I5bc4b2598bf13247683b113faeec22471f1f04a4
Reviewed-by: David Faure <david.faure@kdab.com>
(cherry picked from commit 6ec3fa2842b5c4714dc9a3953b2721ef70dd957b)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Luca Beldi 2021-04-23 20:30:17 +01:00 committed by Qt Cherry-pick Bot
parent f2e156c137
commit 3081731b02
2 changed files with 23 additions and 11 deletions

View File

@ -506,22 +506,18 @@ bool QTreeModel::insertColumns(int column, int count, const QModelIndex &parent)
bool QTreeModel::removeRows(int row, int count, const QModelIndex &parent) {
if (count < 1 || row < 0 || (row + count) > rowCount(parent))
return false;
beginRemoveRows(parent, row, row + count - 1);
QSignalBlocker blocker(this);
QTreeWidgetItem *itm = item(parent);
QTreeWidgetItem *parentItem = item(parent);
// if parentItem is valid, begin/end RemoveRows is handled by takeChild below
if (!parentItem)
beginRemoveRows(parent, row, row + count - 1);
for (int i = row + count - 1; i >= row; --i) {
QTreeWidgetItem *child = itm ? itm->takeChild(i) : rootItem->children.takeAt(i);
QTreeWidgetItem *child = parentItem ? parentItem->takeChild(i) : rootItem->children.takeAt(i);
Q_ASSERT(child);
child->view = nullptr;
delete child;
child = nullptr;
}
blocker.unblock();
endRemoveRows();
if (!parentItem)
endRemoveRows();
return true;
}

View File

@ -151,6 +151,7 @@ private slots:
void getMimeDataWithInvalidItem();
void testVisualItemRect();
void reparentHiddenItem();
void persistentChildIndex();
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
void clearItemData();
#endif
@ -3587,6 +3588,21 @@ void tst_QTreeWidget::reparentHiddenItem()
QVERIFY(grandChild->isHidden());
}
void tst_QTreeWidget::persistentChildIndex() // QTBUG-90030
{
QTreeWidget tree;
QTreeWidgetItem *toplevel = new QTreeWidgetItem(QStringList{QStringLiteral("toplevel")});
tree.addTopLevelItem(toplevel);
QModelIndex firstIndex = tree.model()->index(0, 0);
QTreeWidgetItem *child1 = new QTreeWidgetItem(QStringList{QStringLiteral("child1")});
QTreeWidgetItem *child2 = new QTreeWidgetItem(QStringList{QStringLiteral("child2")});
toplevel->addChildren({child1, child2});
QPersistentModelIndex persistentIdx = tree.model()->index(1, 0, firstIndex);
QCOMPARE(persistentIdx.data().toString(), QStringLiteral("child2"));
tree.model()->removeRows(0, 1, firstIndex);
QCOMPARE(persistentIdx.data().toString(), QStringLiteral("child2"));
}
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
void tst_QTreeWidget::clearItemData()
{