diff --git a/src/corelib/itemmodels/qtransposeproxymodel.cpp b/src/corelib/itemmodels/qtransposeproxymodel.cpp index 899f93c2a5..558ec45b73 100644 --- a/src/corelib/itemmodels/qtransposeproxymodel.cpp +++ b/src/corelib/itemmodels/qtransposeproxymodel.cpp @@ -64,6 +64,7 @@ QModelIndex QTransposeProxyModelPrivate::uncheckedMapFromSource(const QModelInde void QTransposeProxyModelPrivate::onLayoutChanged(const QList &parents, QAbstractItemModel::LayoutChangeHint hint) { Q_Q(QTransposeProxyModel); + Q_ASSERT(layoutChangeProxyIndexes.size() == layoutChangePersistentIndexes.size()); QModelIndexList toList; toList.reserve(layoutChangePersistentIndexes.size()); for (const QPersistentModelIndex &persistIdx : qAsConst(layoutChangePersistentIndexes)) @@ -83,9 +84,26 @@ void QTransposeProxyModelPrivate::onLayoutChanged(const QListlayoutChanged(proxyParents, proxyHint); } -void QTransposeProxyModelPrivate::onLayoutAboutToBeChanged(const QList &parents, QAbstractItemModel::LayoutChangeHint hint) +void QTransposeProxyModelPrivate::onLayoutAboutToBeChanged(const QList &sourceParents, QAbstractItemModel::LayoutChangeHint hint) { Q_Q(QTransposeProxyModel); + QList proxyParents; + proxyParents.reserve(sourceParents.size()); + for (const QPersistentModelIndex &parent : sourceParents) { + if (!parent.isValid()) { + proxyParents << QPersistentModelIndex(); + continue; + } + const QModelIndex mappedParent = q->mapFromSource(parent); + Q_ASSERT(mappedParent.isValid()); + proxyParents << mappedParent; + } + QAbstractItemModel::LayoutChangeHint proxyHint = QAbstractItemModel::NoLayoutChangeHint; + if (hint == QAbstractItemModel::VerticalSortHint) + proxyHint = QAbstractItemModel::HorizontalSortHint; + else if (hint == QAbstractItemModel::HorizontalSortHint) + proxyHint = QAbstractItemModel::VerticalSortHint; + emit q->layoutAboutToBeChanged(proxyParents, proxyHint); const QModelIndexList proxyPersistentIndexes = q->persistentIndexList(); layoutChangeProxyIndexes.clear(); layoutChangePersistentIndexes.clear(); @@ -98,16 +116,6 @@ void QTransposeProxyModelPrivate::onLayoutAboutToBeChanged(const QList proxyParents; - proxyParents.reserve(parents.size()); - for (auto& srcParent : parents) - proxyParents << q->mapFromSource(srcParent); - QAbstractItemModel::LayoutChangeHint proxyHint = QAbstractItemModel::NoLayoutChangeHint; - if (hint == QAbstractItemModel::VerticalSortHint) - proxyHint = QAbstractItemModel::HorizontalSortHint; - else if (hint == QAbstractItemModel::HorizontalSortHint) - proxyHint = QAbstractItemModel::VerticalSortHint; - emit q->layoutAboutToBeChanged(proxyParents, proxyHint); } void QTransposeProxyModelPrivate::onDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, diff --git a/src/widgets/itemviews/qlistwidget.cpp b/src/widgets/itemviews/qlistwidget.cpp index ca7439b08c..f04cfe45d9 100644 --- a/src/widgets/itemviews/qlistwidget.cpp +++ b/src/widgets/itemviews/qlistwidget.cpp @@ -373,7 +373,7 @@ void QListModel::ensureSorted(int column, Qt::SortOrder order, int start, int en if (column != 0) return; - int count = end - start + 1; + const int count = end - start + 1; QList> sorting(count); for (int i = 0; i < count; ++i) { sorting[i].first = items.at(start + i); @@ -399,7 +399,12 @@ void QListModel::ensureSorted(int column, Qt::SortOrder order, int start, int en int newRow = qMax(lit - tmp.begin(), 0); lit = tmp.insert(lit, item); if (newRow != oldRow) { - changed = true; + if (!changed) { + emit layoutAboutToBeChanged({}, QAbstractItemModel::VerticalSortHint); + oldPersistentIndexes = persistentIndexList(); + newPersistentIndexes = oldPersistentIndexes; + changed = true; + } for (int j = i + 1; j < count; ++j) { int otherRow = sorting.at(j).second; if (oldRow < otherRow && newRow >= otherRow) @@ -425,10 +430,9 @@ void QListModel::ensureSorted(int column, Qt::SortOrder order, int start, int en } if (changed) { - emit layoutAboutToBeChanged(); items = tmp; changePersistentIndexList(oldPersistentIndexes, newPersistentIndexes); - emit layoutChanged(); + emit layoutChanged({}, QAbstractItemModel::VerticalSortHint); } } diff --git a/tests/auto/corelib/itemmodels/qconcatenatetablesproxymodel/tst_qconcatenatetablesproxymodel.cpp b/tests/auto/corelib/itemmodels/qconcatenatetablesproxymodel/tst_qconcatenatetablesproxymodel.cpp index 90972caa57..0188768db5 100644 --- a/tests/auto/corelib/itemmodels/qconcatenatetablesproxymodel/tst_qconcatenatetablesproxymodel.cpp +++ b/tests/auto/corelib/itemmodels/qconcatenatetablesproxymodel/tst_qconcatenatetablesproxymodel.cpp @@ -118,7 +118,7 @@ private Q_SLOTS: void shouldPropagateDropAfterLastRow(); void qtbug91788(); void qtbug91878(); - + void createPersistentOnLayoutAboutToBeChanged(); private: QStandardItemModel mod; QStandardItemModel mod2; @@ -860,6 +860,44 @@ void tst_QConcatenateTablesProxyModel::qtbug91878() QCOMPARE(pm.rowCount(), 4); } +void tst_QConcatenateTablesProxyModel::createPersistentOnLayoutAboutToBeChanged() // QTBUG-93466 +{ + QStandardItemModel model1(3, 1); + QStandardItemModel model2(3, 1); + for (int row = 0; row < 3; ++row) { + model1.setData(model1.index(row, 0), row); + model2.setData(model2.index(row, 0), row + 5); + } + QConcatenateTablesProxyModel proxy; + new QAbstractItemModelTester(&proxy, &proxy); + proxy.addSourceModel(&model1); + proxy.addSourceModel(&model2); + QList idxList; + QSignalSpy layoutAboutToBeChangedSpy(&proxy, &QAbstractItemModel::layoutAboutToBeChanged); + QSignalSpy layoutChangedSpy(&proxy, &QAbstractItemModel::layoutChanged); + connect(&proxy, &QAbstractItemModel::layoutAboutToBeChanged, this, [&idxList, &proxy](){ + idxList.clear(); + for (int row = 0; row < 3; ++row) + idxList << QPersistentModelIndex(proxy.index(row, 0)); + }); + connect(&proxy, &QAbstractItemModel::layoutChanged, this, [&idxList](){ + QCOMPARE(idxList.size(), 3); + QCOMPARE(idxList.at(0).row(), 1); + QCOMPARE(idxList.at(0).column(), 0); + QCOMPARE(idxList.at(0).data().toInt(), 0); + QCOMPARE(idxList.at(1).row(), 0); + QCOMPARE(idxList.at(1).column(), 0); + QCOMPARE(idxList.at(1).data().toInt(), -1); + QCOMPARE(idxList.at(2).row(), 2); + QCOMPARE(idxList.at(2).column(), 0); + QCOMPARE(idxList.at(2).data().toInt(), 2); + }); + QVERIFY(model1.setData(model1.index(1, 0), -1)); + model1.sort(0); + QCOMPARE(layoutAboutToBeChangedSpy.size(), 1); + QCOMPARE(layoutChangedSpy.size(), 1); +} + QTEST_GUILESS_MAIN(tst_QConcatenateTablesProxyModel) #include "tst_qconcatenatetablesproxymodel.moc" diff --git a/tests/auto/corelib/itemmodels/qidentityproxymodel/tst_qidentityproxymodel.cpp b/tests/auto/corelib/itemmodels/qidentityproxymodel/tst_qidentityproxymodel.cpp index 4828df8b94..3f93938ed9 100644 --- a/tests/auto/corelib/itemmodels/qidentityproxymodel/tst_qidentityproxymodel.cpp +++ b/tests/auto/corelib/itemmodels/qidentityproxymodel/tst_qidentityproxymodel.cpp @@ -77,7 +77,7 @@ private slots: void itemData(); void persistIndexOnLayoutChange(); - + void createPersistentOnLayoutAboutToBeChanged(); protected: void verifyIdentity(QAbstractItemModel *model, const QModelIndex &parent = QModelIndex()); @@ -494,5 +494,40 @@ void tst_QIdentityProxyModel::persistIndexOnLayoutChange() QVERIFY(persistentIndex.isValid()); } +void tst_QIdentityProxyModel::createPersistentOnLayoutAboutToBeChanged() // QTBUG-93466 +{ + QStandardItemModel model(3, 1); + for (int row = 0; row < 3; ++row) + model.setData(model.index(row, 0), row, Qt::UserRole); + model.setSortRole(Qt::UserRole); + QIdentityProxyModel proxy; + new QAbstractItemModelTester(&proxy, &proxy); + proxy.setSourceModel(&model); + QList idxList; + QSignalSpy layoutAboutToBeChangedSpy(&proxy, &QAbstractItemModel::layoutAboutToBeChanged); + QSignalSpy layoutChangedSpy(&proxy, &QAbstractItemModel::layoutChanged); + connect(&proxy, &QAbstractItemModel::layoutAboutToBeChanged, this, [&idxList, &proxy](){ + idxList.clear(); + for (int row = 0; row < 3; ++row) + idxList << QPersistentModelIndex(proxy.index(row, 0)); + }); + connect(&proxy, &QAbstractItemModel::layoutChanged, this, [&idxList](){ + QCOMPARE(idxList.size(), 3); + QCOMPARE(idxList.at(0).row(), 1); + QCOMPARE(idxList.at(0).column(), 0); + QCOMPARE(idxList.at(0).data(Qt::UserRole).toInt(), 0); + QCOMPARE(idxList.at(1).row(), 0); + QCOMPARE(idxList.at(1).column(), 0); + QCOMPARE(idxList.at(1).data(Qt::UserRole).toInt(), -1); + QCOMPARE(idxList.at(2).row(), 2); + QCOMPARE(idxList.at(2).column(), 0); + QCOMPARE(idxList.at(2).data(Qt::UserRole).toInt(), 2); + }); + model.setData(model.index(1, 0), -1, Qt::UserRole); + model.sort(0); + QCOMPARE(layoutAboutToBeChangedSpy.size(), 1); + QCOMPARE(layoutChangedSpy.size(), 1); +} + QTEST_MAIN(tst_QIdentityProxyModel) #include "tst_qidentityproxymodel.moc" diff --git a/tests/auto/corelib/itemmodels/qsortfilterproxymodel_common/tst_qsortfilterproxymodel.cpp b/tests/auto/corelib/itemmodels/qsortfilterproxymodel_common/tst_qsortfilterproxymodel.cpp index d937a708e9..6da65e59e8 100644 --- a/tests/auto/corelib/itemmodels/qsortfilterproxymodel_common/tst_qsortfilterproxymodel.cpp +++ b/tests/auto/corelib/itemmodels/qsortfilterproxymodel_common/tst_qsortfilterproxymodel.cpp @@ -5487,4 +5487,39 @@ void tst_QSortFilterProxyModel::filterRegularExpressionBinding() QVERIFY(proxyModel.bindableFilterCaseSensitivity().hasBinding()); } +void tst_QSortFilterProxyModel::createPersistentOnLayoutAboutToBeChanged() // QTBUG-93466 +{ + QStandardItemModel model(3, 1); + for (int row = 0; row < 3; ++row) + model.setData(model.index(row, 0), row, Qt::UserRole); + QSortFilterProxyModel proxy; + new QAbstractItemModelTester(&proxy, &proxy); + proxy.setSourceModel(&model); + proxy.setSortRole(Qt::UserRole); + QList idxList; + QSignalSpy layoutAboutToBeChangedSpy(&proxy, &QAbstractItemModel::layoutAboutToBeChanged); + QSignalSpy layoutChangedSpy(&proxy, &QAbstractItemModel::layoutChanged); + connect(&proxy, &QAbstractItemModel::layoutAboutToBeChanged, this, [&idxList, &proxy](){ + idxList.clear(); + for (int row = 0; row < 3; ++row) + idxList << QPersistentModelIndex(proxy.index(row, 0)); + }); + connect(&proxy, &QAbstractItemModel::layoutChanged, this, [&idxList](){ + QCOMPARE(idxList.size(), 3); + QCOMPARE(idxList.at(0).row(), 1); + QCOMPARE(idxList.at(0).column(), 0); + QCOMPARE(idxList.at(0).data(Qt::UserRole).toInt(), 0); + QCOMPARE(idxList.at(1).row(), 0); + QCOMPARE(idxList.at(1).column(), 0); + QCOMPARE(idxList.at(1).data(Qt::UserRole).toInt(), -1); + QCOMPARE(idxList.at(2).row(), 2); + QCOMPARE(idxList.at(2).column(), 0); + QCOMPARE(idxList.at(2).data(Qt::UserRole).toInt(), 2); + }); + model.setData(model.index(1, 0), -1, Qt::UserRole); + proxy.sort(0); + QCOMPARE(layoutAboutToBeChangedSpy.size(), 1); + QCOMPARE(layoutChangedSpy.size(), 1); +} + #include "tst_qsortfilterproxymodel.moc" diff --git a/tests/auto/corelib/itemmodels/qsortfilterproxymodel_common/tst_qsortfilterproxymodel.h b/tests/auto/corelib/itemmodels/qsortfilterproxymodel_common/tst_qsortfilterproxymodel.h index 63b328c41d..baad28ec06 100644 --- a/tests/auto/corelib/itemmodels/qsortfilterproxymodel_common/tst_qsortfilterproxymodel.h +++ b/tests/auto/corelib/itemmodels/qsortfilterproxymodel_common/tst_qsortfilterproxymodel.h @@ -55,6 +55,7 @@ private slots: void sort(); void sortHierarchy_data(); void sortHierarchy(); + void createPersistentOnLayoutAboutToBeChanged(); void insertRows_data(); void insertRows(); diff --git a/tests/auto/corelib/itemmodels/qstringlistmodel/tst_qstringlistmodel.cpp b/tests/auto/corelib/itemmodels/qstringlistmodel/tst_qstringlistmodel.cpp index 79ad4145a2..5fe8784768 100644 --- a/tests/auto/corelib/itemmodels/qstringlistmodel/tst_qstringlistmodel.cpp +++ b/tests/auto/corelib/itemmodels/qstringlistmodel/tst_qstringlistmodel.cpp @@ -93,6 +93,7 @@ private slots: void itemData(); void setItemData(); + void createPersistentOnLayoutAboutToBeChanged(); }; void tst_QStringListModel::moveRowsInvalid_data() @@ -447,5 +448,34 @@ void tst_QStringListModel::supportedDragDropActions() QCOMPARE(model.supportedDropActions(), Qt::CopyAction | Qt::MoveAction); } +void tst_QStringListModel::createPersistentOnLayoutAboutToBeChanged() // QTBUG-93466 +{ + QStringListModel model(QStringList{QStringLiteral("1"), QStringLiteral("2"), QStringLiteral("3")}); + QList idxList; + QSignalSpy layoutAboutToBeChangedSpy(&model, &QAbstractItemModel::layoutAboutToBeChanged); + QSignalSpy layoutChangedSpy(&model, &QAbstractItemModel::layoutChanged); + connect(&model, &QAbstractItemModel::layoutAboutToBeChanged, this, [&idxList, &model](){ + idxList.clear(); + for (int row = 0; row < 3; ++row) + idxList << QPersistentModelIndex(model.index(row, 0)); + }); + connect(&model, &QAbstractItemModel::layoutChanged, this, [&idxList](){ + QCOMPARE(idxList.size(), 3); + QCOMPARE(idxList.at(0).row(), 1); + QCOMPARE(idxList.at(0).column(), 0); + QCOMPARE(idxList.at(0).data().toString(), QStringLiteral("1")); + QCOMPARE(idxList.at(1).row(), 0); + QCOMPARE(idxList.at(1).column(), 0); + QCOMPARE(idxList.at(1).data().toString(), QStringLiteral("0")); + QCOMPARE(idxList.at(2).row(), 2); + QCOMPARE(idxList.at(2).column(), 0); + QCOMPARE(idxList.at(2).data().toString(), QStringLiteral("3")); + }); + model.setData(model.index(1, 0), QStringLiteral("0")); + model.sort(0); + QCOMPARE(layoutAboutToBeChangedSpy.size(), 1); + QCOMPARE(layoutChangedSpy.size(), 1); +} + QTEST_MAIN(tst_QStringListModel) #include "tst_qstringlistmodel.moc" diff --git a/tests/auto/corelib/itemmodels/qtransposeproxymodel/tst_qtransposeproxymodel.cpp b/tests/auto/corelib/itemmodels/qtransposeproxymodel/tst_qtransposeproxymodel.cpp index 8e8d1ec709..f577c3c41b 100644 --- a/tests/auto/corelib/itemmodels/qtransposeproxymodel/tst_qtransposeproxymodel.cpp +++ b/tests/auto/corelib/itemmodels/qtransposeproxymodel/tst_qtransposeproxymodel.cpp @@ -84,6 +84,8 @@ private Q_SLOTS: void setItemData(); void moveRowsBase(); void moveColumnsProxy(); + void sortPersistentIndex(); + void createPersistentOnLayoutAboutToBeChanged(); private: void testTransposed( const QAbstractItemModel *const baseModel, @@ -343,6 +345,84 @@ void tst_QTransposeProxyModel::removeColumnBase() delete model; } +void tst_QTransposeProxyModel::sortPersistentIndex() +{ + QStringListModel model(QStringList{QStringLiteral("Alice"), QStringLiteral("Charlie"), QStringLiteral("Bob")}); + QTransposeProxyModel proxy; + new QAbstractItemModelTester(&proxy, &proxy); + proxy.setSourceModel(&model); + QPersistentModelIndex aliceIdx = proxy.index(0, 0); + QPersistentModelIndex bobIdx = proxy.index(0, 2); + QPersistentModelIndex charlieIdx = proxy.index(0, 1); + connect(&proxy, &QAbstractItemModel::layoutAboutToBeChanged, this, [&aliceIdx, &bobIdx, &charlieIdx](){ + QCOMPARE(aliceIdx.row(), 0); + QCOMPARE(aliceIdx.column(), 0); + QCOMPARE(aliceIdx.data().toString(), QStringLiteral("Alice")); + QCOMPARE(bobIdx.row(), 0); + QCOMPARE(bobIdx.column(), 2); + QCOMPARE(bobIdx.data().toString(), QStringLiteral("Bob")); + QCOMPARE(charlieIdx.row(), 0); + QCOMPARE(charlieIdx.column(), 1); + QCOMPARE(charlieIdx.data().toString(), QStringLiteral("Charlie")); + }); + connect(&proxy, &QAbstractItemModel::layoutChanged, this, [&aliceIdx, &bobIdx, &charlieIdx](){ + QCOMPARE(aliceIdx.row(), 0); + QCOMPARE(aliceIdx.column(), 0); + QCOMPARE(aliceIdx.data().toString(), QStringLiteral("Alice")); + QCOMPARE(bobIdx.row(), 0); + QCOMPARE(bobIdx.column(), 1); + QCOMPARE(bobIdx.data().toString(), QStringLiteral("Bob")); + QCOMPARE(charlieIdx.row(), 0); + QCOMPARE(charlieIdx.column(), 2); + QCOMPARE(charlieIdx.data().toString(), QStringLiteral("Charlie")); + }); + model.sort(0); + QCOMPARE(aliceIdx.row(), 0); + QCOMPARE(aliceIdx.column(), 0); + QCOMPARE(aliceIdx.data().toString(), QStringLiteral("Alice")); + QCOMPARE(bobIdx.row(), 0); + QCOMPARE(bobIdx.column(), 1); + QCOMPARE(bobIdx.data().toString(), QStringLiteral("Bob")); + QCOMPARE(charlieIdx.row(), 0); + QCOMPARE(charlieIdx.column(), 2); + QCOMPARE(charlieIdx.data().toString(), QStringLiteral("Charlie")); +} + +void tst_QTransposeProxyModel::createPersistentOnLayoutAboutToBeChanged() // QTBUG-93466 +{ + QStandardItemModel model(3, 1); + for (int row = 0; row < 3; ++row) + model.setData(model.index(row, 0), row, Qt::UserRole); + model.setSortRole(Qt::UserRole); + QTransposeProxyModel proxy; + new QAbstractItemModelTester(&proxy, &proxy); + proxy.setSourceModel(&model); + QList idxList; + QSignalSpy layoutAboutToBeChangedSpy(&proxy, &QAbstractItemModel::layoutAboutToBeChanged); + QSignalSpy layoutChangedSpy(&proxy, &QAbstractItemModel::layoutChanged); + connect(&proxy, &QAbstractItemModel::layoutAboutToBeChanged, this, [&idxList, &proxy](){ + idxList.clear(); + for (int row = 0; row < 3; ++row) + idxList << QPersistentModelIndex(proxy.index(0, row)); + }); + connect(&proxy, &QAbstractItemModel::layoutChanged, this, [&idxList](){ + QCOMPARE(idxList.size(), 3); + QCOMPARE(idxList.at(0).row(), 0); + QCOMPARE(idxList.at(0).column(), 1); + QCOMPARE(idxList.at(0).data(Qt::UserRole).toInt(), 0); + QCOMPARE(idxList.at(1).row(), 0); + QCOMPARE(idxList.at(1).column(), 0); + QCOMPARE(idxList.at(1).data(Qt::UserRole).toInt(), -1); + QCOMPARE(idxList.at(2).row(), 0); + QCOMPARE(idxList.at(2).column(), 2); + QCOMPARE(idxList.at(2).data(Qt::UserRole).toInt(), 2); + }); + model.setData(model.index(1, 0), -1, Qt::UserRole); + model.sort(0); + QCOMPARE(layoutAboutToBeChangedSpy.size(), 1); + QCOMPARE(layoutChangedSpy.size(), 1); +} + void tst_QTransposeProxyModel::insertColumnBase_data() { QTest::addColumn("model"); diff --git a/tests/auto/gui/itemmodels/qstandarditemmodel/tst_qstandarditemmodel.cpp b/tests/auto/gui/itemmodels/qstandarditemmodel/tst_qstandarditemmodel.cpp index 7fc2c473de..7758a5d5cc 100644 --- a/tests/auto/gui/itemmodels/qstandarditemmodel/tst_qstandarditemmodel.cpp +++ b/tests/auto/gui/itemmodels/qstandarditemmodel/tst_qstandarditemmodel.cpp @@ -138,6 +138,7 @@ private slots: void taskQTBUG_45114_setItemData(); void setItemPersistentIndex(); void signalsOnTakeItem(); + void createPersistentOnLayoutAboutToBeChanged(); private: QStandardItemModel *m_model = nullptr; QPersistentModelIndex persistent; @@ -1785,5 +1786,40 @@ void tst_QStandardItemModel::signalsOnTakeItem() // QTBUG-89145 QCOMPARE(m.index(1, 0).data(), QVariant()); } +void tst_QStandardItemModel::createPersistentOnLayoutAboutToBeChanged() // QTBUG-93466 +{ + QStandardItemModel model; + QAbstractItemModelTester mTester(&model, nullptr); + model.insertColumn(0); + QCOMPARE(model.columnCount(), 1); + model.insertRows(0, 3); + for (int row = 0; row < 3; ++row) + model.setData(model.index(row, 0), row); + QList idxList; + QSignalSpy layoutAboutToBeChangedSpy(&model, &QAbstractItemModel::layoutAboutToBeChanged); + QSignalSpy layoutChangedSpy(&model, &QAbstractItemModel::layoutChanged); + connect(&model, &QAbstractItemModel::layoutAboutToBeChanged, this, [&idxList, &model](){ + idxList.clear(); + for (int row = 0; row < 3; ++row) + idxList << QPersistentModelIndex(model.index(row, 0)); + }); + connect(&model, &QAbstractItemModel::layoutChanged, this, [&idxList](){ + QCOMPARE(idxList.size(), 3); + QCOMPARE(idxList.at(0).row(), 1); + QCOMPARE(idxList.at(0).column(), 0); + QCOMPARE(idxList.at(0).data().toInt(), 0); + QCOMPARE(idxList.at(1).row(), 0); + QCOMPARE(idxList.at(1).column(), 0); + QCOMPARE(idxList.at(1).data().toInt(), -1); + QCOMPARE(idxList.at(2).row(), 2); + QCOMPARE(idxList.at(2).column(), 0); + QCOMPARE(idxList.at(2).data().toInt(), 2); + }); + model.setData(model.index(1, 0), -1); + model.sort(0); + QCOMPARE(layoutAboutToBeChangedSpy.size(), 1); + QCOMPARE(layoutChangedSpy.size(), 1); +} + QTEST_MAIN(tst_QStandardItemModel) #include "tst_qstandarditemmodel.moc" diff --git a/tests/auto/widgets/itemviews/qlistwidget/tst_qlistwidget.cpp b/tests/auto/widgets/itemviews/qlistwidget/tst_qlistwidget.cpp index 48b0cb8d6b..b121766265 100644 --- a/tests/auto/widgets/itemviews/qlistwidget/tst_qlistwidget.cpp +++ b/tests/auto/widgets/itemviews/qlistwidget/tst_qlistwidget.cpp @@ -118,6 +118,8 @@ private slots: void QTBUG14363_completerWithAnyKeyPressedEditTriggers(); void mimeData(); void QTBUG50891_ensureSelectionModelSignalConnectionsAreSet(); + void createPersistentOnLayoutAboutToBeChanged(); + void createPersistentOnLayoutAboutToBeChangedAutoSort(); #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) void clearItemData(); #endif @@ -1844,6 +1846,72 @@ void tst_QListWidget::QTBUG50891_ensureSelectionModelSignalConnectionsAreSet() } +void tst_QListWidget::createPersistentOnLayoutAboutToBeChanged() // QTBUG-93466 +{ + QListWidget widget; + QCOMPARE(widget.model()->columnCount(), 1); + widget.model()->insertRows(0, 3); + for (int row = 0; row < 3; ++row) + widget.model()->setData(widget.model()->index(row, 0), row); + QList idxList; + QSignalSpy layoutAboutToBeChangedSpy(widget.model(), &QAbstractItemModel::layoutAboutToBeChanged); + QSignalSpy layoutChangedSpy(widget.model(), &QAbstractItemModel::layoutChanged); + connect(widget.model(), &QAbstractItemModel::layoutAboutToBeChanged, this, [&idxList, &widget](){ + idxList.clear(); + for (int row = 0; row < 3; ++row) + idxList << QPersistentModelIndex(widget.model()->index(row, 0)); + }); + connect(widget.model(), &QAbstractItemModel::layoutChanged, this, [&idxList](){ + QCOMPARE(idxList.size(), 3); + QCOMPARE(idxList.at(0).row(), 1); + QCOMPARE(idxList.at(0).column(), 0); + QCOMPARE(idxList.at(0).data().toInt(), 0); + QCOMPARE(idxList.at(1).row(), 0); + QCOMPARE(idxList.at(1).column(), 0); + QCOMPARE(idxList.at(1).data().toInt(), -1); + QCOMPARE(idxList.at(2).row(), 2); + QCOMPARE(idxList.at(2).column(), 0); + QCOMPARE(idxList.at(2).data().toInt(), 2); + }); + widget.model()->setData(widget.model()->index(1, 0), -1); + widget.model()->sort(0); + QCOMPARE(layoutAboutToBeChangedSpy.size(), 1); + QCOMPARE(layoutChangedSpy.size(), 1); +} + +void tst_QListWidget::createPersistentOnLayoutAboutToBeChangedAutoSort() // QTBUG-93466 +{ + QListWidget widget; + QCOMPARE(widget.model()->columnCount(), 1); + widget.model()->insertRows(0, 3); + for (int row = 0; row < 3; ++row) + widget.model()->setData(widget.model()->index(row, 0), row); + widget.setSortingEnabled(true); + QList idxList; + QSignalSpy layoutAboutToBeChangedSpy(widget.model(), &QAbstractItemModel::layoutAboutToBeChanged); + QSignalSpy layoutChangedSpy(widget.model(), &QAbstractItemModel::layoutChanged); + connect(widget.model(), &QAbstractItemModel::layoutAboutToBeChanged, this, [&idxList, &widget](){ + idxList.clear(); + for (int row = 0; row < 3; ++row) + idxList << QPersistentModelIndex(widget.model()->index(row, 0)); + }); + connect(widget.model(), &QAbstractItemModel::layoutChanged, this, [&idxList](){ + QCOMPARE(idxList.size(), 3); + QCOMPARE(idxList.at(0).row(), 1); + QCOMPARE(idxList.at(0).column(), 0); + QCOMPARE(idxList.at(0).data().toInt(), 0); + QCOMPARE(idxList.at(1).row(), 0); + QCOMPARE(idxList.at(1).column(), 0); + QCOMPARE(idxList.at(1).data().toInt(), -1); + QCOMPARE(idxList.at(2).row(), 2); + QCOMPARE(idxList.at(2).column(), 0); + QCOMPARE(idxList.at(2).data().toInt(), 2); + }); + widget.model()->setData(widget.model()->index(1, 0), -1); + QCOMPARE(layoutAboutToBeChangedSpy.size(), 1); + QCOMPARE(layoutChangedSpy.size(), 1); +} + #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) void tst_QListWidget::clearItemData() { diff --git a/tests/auto/widgets/itemviews/qtablewidget/tst_qtablewidget.cpp b/tests/auto/widgets/itemviews/qtablewidget/tst_qtablewidget.cpp index 6ee923662e..b827d87910 100644 --- a/tests/auto/widgets/itemviews/qtablewidget/tst_qtablewidget.cpp +++ b/tests/auto/widgets/itemviews/qtablewidget/tst_qtablewidget.cpp @@ -91,6 +91,8 @@ private slots: #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) void clearItemData(); #endif + void createPersistentOnLayoutAboutToBeChanged(); + void createPersistentOnLayoutAboutToBeChangedAutoSort(); private: std::unique_ptr testWidget; @@ -1756,5 +1758,74 @@ void tst_QTableWidget::clearItemData() } #endif +void tst_QTableWidget::createPersistentOnLayoutAboutToBeChanged() // QTBUG-93466 +{ + QTableWidget widget; + widget.model()->insertColumn(0); + QCOMPARE(widget.model()->columnCount(), 1); + widget.model()->insertRows(0, 3); + for (int row = 0; row < 3; ++row) + widget.model()->setData(widget.model()->index(row, 0), row); + QList idxList; + QSignalSpy layoutAboutToBeChangedSpy(widget.model(), &QAbstractItemModel::layoutAboutToBeChanged); + QSignalSpy layoutChangedSpy(widget.model(), &QAbstractItemModel::layoutChanged); + connect(widget.model(), &QAbstractItemModel::layoutAboutToBeChanged, this, [&idxList, &widget](){ + idxList.clear(); + for (int row = 0; row < 3; ++row) + idxList << QPersistentModelIndex(widget.model()->index(row, 0)); + }); + connect(widget.model(), &QAbstractItemModel::layoutChanged, this, [&idxList](){ + QCOMPARE(idxList.size(), 3); + QCOMPARE(idxList.at(0).row(), 1); + QCOMPARE(idxList.at(0).column(), 0); + QCOMPARE(idxList.at(0).data().toInt(), 0); + QCOMPARE(idxList.at(1).row(), 0); + QCOMPARE(idxList.at(1).column(), 0); + QCOMPARE(idxList.at(1).data().toInt(), -1); + QCOMPARE(idxList.at(2).row(), 2); + QCOMPARE(idxList.at(2).column(), 0); + QCOMPARE(idxList.at(2).data().toInt(), 2); + }); + widget.model()->setData(widget.model()->index(1, 0), -1); + widget.model()->sort(0); + QCOMPARE(layoutAboutToBeChangedSpy.size(), 1); + QCOMPARE(layoutChangedSpy.size(), 1); +} + +void tst_QTableWidget::createPersistentOnLayoutAboutToBeChangedAutoSort() // QTBUG-93466 +{ + QTableWidget widget; + widget.model()->insertColumn(0); + QCOMPARE(widget.model()->columnCount(), 1); + widget.model()->insertRows(0, 3); + for (int row = 0; row < 3; ++row) + widget.model()->setData(widget.model()->index(row, 0), row); + widget.sortByColumn(0, Qt::AscendingOrder); + widget.setSortingEnabled(true); + QList idxList; + QSignalSpy layoutAboutToBeChangedSpy(widget.model(), &QAbstractItemModel::layoutAboutToBeChanged); + QSignalSpy layoutChangedSpy(widget.model(), &QAbstractItemModel::layoutChanged); + connect(widget.model(), &QAbstractItemModel::layoutAboutToBeChanged, this, [&idxList, &widget](){ + idxList.clear(); + for (int row = 0; row < 3; ++row) + idxList << QPersistentModelIndex(widget.model()->index(row, 0)); + }); + connect(widget.model(), &QAbstractItemModel::layoutChanged, this, [&idxList](){ + QCOMPARE(idxList.size(), 3); + QCOMPARE(idxList.at(0).row(), 1); + QCOMPARE(idxList.at(0).column(), 0); + QCOMPARE(idxList.at(0).data().toInt(), 0); + QCOMPARE(idxList.at(1).row(), 0); + QCOMPARE(idxList.at(1).column(), 0); + QCOMPARE(idxList.at(1).data().toInt(), -1); + QCOMPARE(idxList.at(2).row(), 2); + QCOMPARE(idxList.at(2).column(), 0); + QCOMPARE(idxList.at(2).data().toInt(), 2); + }); + widget.model()->setData(widget.model()->index(1, 0), -1); + QCOMPARE(layoutAboutToBeChangedSpy.size(), 1); + QCOMPARE(layoutChangedSpy.size(), 1); +} + QTEST_MAIN(tst_QTableWidget) #include "tst_qtablewidget.moc" diff --git a/tests/auto/widgets/itemviews/qtreewidget/tst_qtreewidget.cpp b/tests/auto/widgets/itemviews/qtreewidget/tst_qtreewidget.cpp index a60d09ec0d..8b4fcd2459 100644 --- a/tests/auto/widgets/itemviews/qtreewidget/tst_qtreewidget.cpp +++ b/tests/auto/widgets/itemviews/qtreewidget/tst_qtreewidget.cpp @@ -152,6 +152,8 @@ private slots: void testVisualItemRect(); void reparentHiddenItem(); void persistentChildIndex(); + void createPersistentOnLayoutAboutToBeChanged(); + void createPersistentOnLayoutAboutToBeChangedAutoSort(); #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) void clearItemData(); #endif @@ -3641,5 +3643,72 @@ void tst_QTreeWidget::clearItemData() } #endif +void tst_QTreeWidget::createPersistentOnLayoutAboutToBeChanged() // QTBUG-93466 +{ + QTreeWidget widget; + QCOMPARE(widget.model()->columnCount(), 1); + widget.model()->insertRows(0, 3); + for (int row = 0; row < 3; ++row) + widget.model()->setData(widget.model()->index(row, 0), row); + QList idxList; + QSignalSpy layoutAboutToBeChangedSpy(widget.model(), &QAbstractItemModel::layoutAboutToBeChanged); + QSignalSpy layoutChangedSpy(widget.model(), &QAbstractItemModel::layoutChanged); + connect(widget.model(), &QAbstractItemModel::layoutAboutToBeChanged, this, [&idxList, &widget](){ + idxList.clear(); + for (int row = 0; row < 3; ++row) + idxList << QPersistentModelIndex(widget.model()->index(row, 0)); + }); + connect(widget.model(), &QAbstractItemModel::layoutChanged, this, [&idxList](){ + QCOMPARE(idxList.size(), 3); + QCOMPARE(idxList.at(0).row(), 1); + QCOMPARE(idxList.at(0).column(), 0); + QCOMPARE(idxList.at(0).data().toInt(), 0); + QCOMPARE(idxList.at(1).row(), 0); + QCOMPARE(idxList.at(1).column(), 0); + QCOMPARE(idxList.at(1).data().toInt(), -1); + QCOMPARE(idxList.at(2).row(), 2); + QCOMPARE(idxList.at(2).column(), 0); + QCOMPARE(idxList.at(2).data().toInt(), 2); + }); + widget.model()->setData(widget.model()->index(1, 0), -1); + widget.model()->sort(0); + QCOMPARE(layoutAboutToBeChangedSpy.size(), 1); + QCOMPARE(layoutChangedSpy.size(), 1); +} + +void tst_QTreeWidget::createPersistentOnLayoutAboutToBeChangedAutoSort() // QTBUG-93466 +{ + QTreeWidget widget; + QCOMPARE(widget.model()->columnCount(), 1); + widget.model()->insertRows(0, 3); + for (int row = 0; row < 3; ++row) + widget.model()->setData(widget.model()->index(row, 0), row); + widget.sortByColumn(0, Qt::AscendingOrder); + widget.setSortingEnabled(true); + QList idxList; + QSignalSpy layoutAboutToBeChangedSpy(widget.model(), &QAbstractItemModel::layoutAboutToBeChanged); + QSignalSpy layoutChangedSpy(widget.model(), &QAbstractItemModel::layoutChanged); + connect(widget.model(), &QAbstractItemModel::layoutAboutToBeChanged, this, [&idxList, &widget](){ + idxList.clear(); + for (int row = 0; row < 3; ++row) + idxList << QPersistentModelIndex(widget.model()->index(row, 0)); + }); + connect(widget.model(), &QAbstractItemModel::layoutChanged, this, [&idxList](){ + QCOMPARE(idxList.size(), 3); + QCOMPARE(idxList.at(0).row(), 1); + QCOMPARE(idxList.at(0).column(), 0); + QCOMPARE(idxList.at(0).data().toInt(), 0); + QCOMPARE(idxList.at(1).row(), 0); + QCOMPARE(idxList.at(1).column(), 0); + QCOMPARE(idxList.at(1).data().toInt(), -1); + QCOMPARE(idxList.at(2).row(), 2); + QCOMPARE(idxList.at(2).column(), 0); + QCOMPARE(idxList.at(2).data().toInt(), 2); + }); + widget.model()->setData(widget.model()->index(1, 0), -1); + QCOMPARE(layoutAboutToBeChangedSpy.size(), 1); + QCOMPARE(layoutChangedSpy.size(), 1); +} + QTEST_MAIN(tst_QTreeWidget) #include "tst_qtreewidget.moc"