From d53c3809de5bd81d59d5cc7562e88862dd412333 Mon Sep 17 00:00:00 2001 From: David Faure Date: Tue, 10 Sep 2024 11:01:00 +0200 Subject: [PATCH] QConcatenateTablesProxyModel: react to row and column moves Fixes: QTBUG-128742 Change-Id: I6282c3c9f27c435da5d511c61fbb051da127229c Reviewed-by: Christian Ehrlicher (cherry picked from commit b9ba28315d889d0b87ae048dffe33eac55efcda2) Reviewed-by: Qt Cherry-pick Bot --- .../qconcatenatetablesproxymodel.cpp | 70 ++++++++++++++++++- .../tst_qconcatenatetablesproxymodel.cpp | 65 +++++++++++++++++ 2 files changed, 134 insertions(+), 1 deletion(-) diff --git a/src/corelib/itemmodels/qconcatenatetablesproxymodel.cpp b/src/corelib/itemmodels/qconcatenatetablesproxymodel.cpp index 3a49d37cff7..3b90858984a 100644 --- a/src/corelib/itemmodels/qconcatenatetablesproxymodel.cpp +++ b/src/corelib/itemmodels/qconcatenatetablesproxymodel.cpp @@ -30,10 +30,18 @@ public: void slotRowsInserted(const QModelIndex &, int start, int end); void slotRowsAboutToBeRemoved(const QModelIndex &, int start, int end); void slotRowsRemoved(const QModelIndex &, int start, int end); + void slotRowsAboutToBeMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, + const QModelIndex &destinationParent, int destinationRow); + void slotRowsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, + const QModelIndex &destinationParent, int destinationRow); void slotColumnsAboutToBeInserted(const QModelIndex &parent, int start, int end); void slotColumnsInserted(const QModelIndex &parent, int, int); void slotColumnsAboutToBeRemoved(const QModelIndex &parent, int start, int end); void slotColumnsRemoved(const QModelIndex &parent, int, int); + void slotColumnsAboutToBeMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, + const QModelIndex &destinationParent, int destination); + void slotColumnsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, + const QModelIndex &destinationParent, int destination); void slotDataChanged(const QModelIndex &from, const QModelIndex &to, const QList &roles); void slotSourceLayoutAboutToBeChanged(const QList &sourceParents, QAbstractItemModel::LayoutChangeHint hint); void slotSourceLayoutChanged(const QList &sourceParents, QAbstractItemModel::LayoutChangeHint hint); @@ -46,7 +54,7 @@ public: int *sourceRow, int *sourceColumn, QModelIndex *sourceParent, QAbstractItemModel **sourceModel) const; struct ModelInfo { - using ConnArray = std::array; + using ConnArray = std::array; ModelInfo(QAbstractItemModel *m, ConnArray &&con) : model(m), connections(std::move(con)) {} QAbstractItemModel *model = nullptr; @@ -472,6 +480,10 @@ void QConcatenateTablesProxyModel::addSourceModel(QAbstractItemModel *sourceMode d, &QConcatenateTablesProxyModelPrivate::slotRowsAboutToBeInserted), QObjectPrivate::connect(sourceModel, &QAbstractItemModel::rowsAboutToBeRemoved, d, &QConcatenateTablesProxyModelPrivate::slotRowsAboutToBeRemoved), + QObjectPrivate::connect(sourceModel, &QAbstractItemModel::rowsMoved, + d, &QConcatenateTablesProxyModelPrivate::slotRowsMoved), + QObjectPrivate::connect(sourceModel, &QAbstractItemModel::rowsAboutToBeMoved, + d, &QConcatenateTablesProxyModelPrivate::slotRowsAboutToBeMoved), QObjectPrivate::connect(sourceModel, &QAbstractItemModel::columnsInserted, d, &QConcatenateTablesProxyModelPrivate::slotColumnsInserted), @@ -481,6 +493,10 @@ void QConcatenateTablesProxyModel::addSourceModel(QAbstractItemModel *sourceMode d, &QConcatenateTablesProxyModelPrivate::slotColumnsAboutToBeInserted), QObjectPrivate::connect(sourceModel, &QAbstractItemModel::columnsAboutToBeRemoved, d, &QConcatenateTablesProxyModelPrivate::slotColumnsAboutToBeRemoved), + QObjectPrivate::connect(sourceModel, &QAbstractItemModel::columnsMoved, + d, &QConcatenateTablesProxyModelPrivate::slotColumnsMoved), + QObjectPrivate::connect(sourceModel, &QAbstractItemModel::columnsAboutToBeMoved, + d, &QConcatenateTablesProxyModelPrivate::slotColumnsAboutToBeMoved), QObjectPrivate::connect(sourceModel, &QAbstractItemModel::layoutAboutToBeChanged, d, &QConcatenateTablesProxyModelPrivate::slotSourceLayoutAboutToBeChanged), @@ -565,6 +581,33 @@ void QConcatenateTablesProxyModelPrivate::slotRowsRemoved(const QModelIndex &par q->endRemoveRows(); } +void QConcatenateTablesProxyModelPrivate::slotRowsAboutToBeMoved( + const QModelIndex &sourceParent, int sourceStart, int sourceEnd, + const QModelIndex &destinationParent, int destinationRow) +{ + Q_Q(QConcatenateTablesProxyModel); + if (sourceParent.isValid() || destinationParent.isValid()) + return; + const QAbstractItemModel *const model = static_cast(q->sender()); + const int rowsPrior = computeRowsPrior(model); + q->beginMoveRows(sourceParent, rowsPrior + sourceStart, rowsPrior + sourceEnd, + destinationParent, rowsPrior + destinationRow); +} + +void QConcatenateTablesProxyModelPrivate::slotRowsMoved(const QModelIndex &sourceParent, + int sourceStart, int sourceEnd, + const QModelIndex &destinationParent, + int destinationRow) +{ + Q_Q(QConcatenateTablesProxyModel); + Q_UNUSED(sourceStart) + Q_UNUSED(sourceEnd) + Q_UNUSED(destinationRow) + if (sourceParent.isValid() || destinationParent.isValid()) + return; + q->endMoveRows(); +} + void QConcatenateTablesProxyModelPrivate::slotColumnsAboutToBeInserted(const QModelIndex &parent, int start, int end) { @@ -625,6 +668,31 @@ void QConcatenateTablesProxyModelPrivate::slotColumnsRemoved(const QModelIndex & } } +void QConcatenateTablesProxyModelPrivate::slotColumnsAboutToBeMoved( + const QModelIndex &sourceParent, int sourceStart, int sourceEnd, + const QModelIndex &destinationParent, int destination) +{ + Q_UNUSED(sourceStart) + Q_UNUSED(sourceEnd) + Q_UNUSED(destination) + if (sourceParent.isValid() || destinationParent.isValid()) + return; + slotSourceLayoutAboutToBeChanged({}, QAbstractItemModel::HorizontalSortHint); +} + +void QConcatenateTablesProxyModelPrivate::slotColumnsMoved(const QModelIndex &sourceParent, + int sourceStart, int sourceEnd, + const QModelIndex &destinationParent, + int destination) +{ + Q_UNUSED(sourceStart) + Q_UNUSED(sourceEnd) + Q_UNUSED(destination) + if (sourceParent.isValid() || destinationParent.isValid()) + return; + slotSourceLayoutChanged({}, QAbstractItemModel::HorizontalSortHint); +} + void QConcatenateTablesProxyModelPrivate::slotDataChanged(const QModelIndex &from, const QModelIndex &to, const QList &roles) diff --git a/tests/auto/corelib/itemmodels/qconcatenatetablesproxymodel/tst_qconcatenatetablesproxymodel.cpp b/tests/auto/corelib/itemmodels/qconcatenatetablesproxymodel/tst_qconcatenatetablesproxymodel.cpp index 989a57b30f4..b15ba191e5d 100644 --- a/tests/auto/corelib/itemmodels/qconcatenatetablesproxymodel/tst_qconcatenatetablesproxymodel.cpp +++ b/tests/auto/corelib/itemmodels/qconcatenatetablesproxymodel/tst_qconcatenatetablesproxymodel.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include @@ -72,6 +73,8 @@ private Q_SLOTS: void shouldIncreaseColumnCountWhenRemovingFirstModel(); void shouldHandleColumnInsertionAndRemoval(); void shouldPropagateLayoutChanged(); + void shouldPropagateRowMove(); + void shouldPropagateColumnMove(); void shouldReactToModelReset(); void shouldUpdateColumnsOnModelReset(); void shouldPropagateDropOnItem_data(); @@ -545,6 +548,68 @@ void tst_QConcatenateTablesProxyModel::shouldPropagateLayoutChanged() } } +void tst_QConcatenateTablesProxyModel::shouldPropagateRowMove() +{ + // Given two source models (which support moving rows) + QStringListModel model1({ "0", "1", "2" }); + QStringListModel model2({ "A", "B", "C" }); + QConcatenateTablesProxyModel proxy; + new QAbstractItemModelTester(&proxy, &proxy); + proxy.addSourceModel(&model1); + proxy.addSourceModel(&model2); + QCOMPARE(extractColumnTexts(&proxy, 0), QStringLiteral("012ABC")); + QSignalSpy rowsATBMSpy(&proxy, &QAbstractItemModel::rowsAboutToBeMoved); + QSignalSpy rowsMovedSpy(&proxy, &QAbstractItemModel::rowsMoved); + + // When moving a row + QVERIFY(model2.moveRow({}, 0, {}, 2)); + + // Then + QCOMPARE(extractColumnTexts(&proxy, 0), QStringLiteral("012BAC")); + QCOMPARE(rowsATBMSpy.count(), 1); + QCOMPARE(rowsMovedSpy.count(), 1); + QCOMPARE(rowsATBMSpy[0][1].toInt(), 3); // sourceStart + QCOMPARE(rowsATBMSpy[0][2].toInt(), 3); // sourceEnd + QCOMPARE(rowsATBMSpy[0][4].toInt(), 5); // destinationRow + QCOMPARE(rowsMovedSpy[0][1].toInt(), 3); // sourceStart + QCOMPARE(rowsMovedSpy[0][2].toInt(), 3); // sourceEnd + QCOMPARE(rowsMovedSpy[0][4].toInt(), 5); // destinationRow +} + +void tst_QConcatenateTablesProxyModel::shouldPropagateColumnMove() +{ + // Given two source models (which support moving rows) + // and two transpose proxies (so it becomes columns) + QStringListModel model1({ "0", "1", "2" }); + QStringListModel model2({ "A", "B", "C" }); + QTransposeProxyModel transpose1; + QTransposeProxyModel transpose2; + transpose1.setSourceModel(&model1); + transpose2.setSourceModel(&model2); + + QConcatenateTablesProxyModel proxy; + new QAbstractItemModelTester(&proxy, &proxy); + proxy.addSourceModel(&transpose1); + proxy.addSourceModel(&transpose2); + QCOMPARE(extractRowTexts(&proxy, 0), QStringLiteral("012")); + QCOMPARE(extractRowTexts(&proxy, 1), QStringLiteral("ABC")); + QSignalSpy columnsATBMSpy(&proxy, &QAbstractItemModel::columnsAboutToBeMoved); + QSignalSpy columnsMovedSpy(&proxy, &QAbstractItemModel::columnsMoved); + QPersistentModelIndex A(proxy.index(1, 0)); + QCOMPARE(A.data().toString(), "A"); + + // When moving a row in a stringlist model, which moves a column in a transpose proxy + QVERIFY(model2.moveRow({}, 0, {}, 2)); + + // Then, well, we didn't fully move a column in the concatenate proxy. + // It will emit layoutChanged and update persistent indexes, instead. + QCOMPARE(extractRowTexts(&proxy, 0), QStringLiteral("012")); + QCOMPARE(extractRowTexts(&proxy, 1), QStringLiteral("BAC")); + QCOMPARE(columnsATBMSpy.count(), 0); + QCOMPARE(columnsMovedSpy.count(), 0); + QCOMPARE(A.data().toString(), "A"); +} + void tst_QConcatenateTablesProxyModel::shouldReactToModelReset() { // Given two source models, the second one being a QSFPM