diff --git a/ui/StatusQ/include/StatusQ/movablemodel.h b/ui/StatusQ/include/StatusQ/movablemodel.h index 6c76fe790f..5c88b4a26d 100644 --- a/ui/StatusQ/include/StatusQ/movablemodel.h +++ b/ui/StatusQ/include/StatusQ/movablemodel.h @@ -23,6 +23,7 @@ public: QHash roleNames() const override; Q_INVOKABLE void detach(); + Q_INVOKABLE void attach(); Q_INVOKABLE void move(int from, int to, int count = 1); Q_INVOKABLE QVector order() const; @@ -38,6 +39,8 @@ protected slots: private: QPointer m_sourceModel; + void connectSignalsForAttachedState(); + bool m_detached = false; std::vector m_indexes; }; diff --git a/ui/StatusQ/src/movablemodel.cpp b/ui/StatusQ/src/movablemodel.cpp index 13f77c3ee8..f0eafa2a21 100644 --- a/ui/StatusQ/src/movablemodel.cpp +++ b/ui/StatusQ/src/movablemodel.cpp @@ -20,41 +20,7 @@ void MovableModel::setSourceModel(QAbstractItemModel* sourceModel) disconnect(m_sourceModel, nullptr, this, nullptr); m_sourceModel = sourceModel; - - if (sourceModel != nullptr) { - connect(sourceModel, &QAbstractItemModel::rowsAboutToBeInserted, this, - &MovableModel::beginInsertRows); - - connect(sourceModel, &QAbstractItemModel::rowsInserted, this, - &MovableModel::endInsertRows); - - connect(sourceModel, &QAbstractItemModel::rowsAboutToBeRemoved, this, - &MovableModel::beginRemoveRows); - - connect(sourceModel, &QAbstractItemModel::rowsRemoved, this, - &MovableModel::endRemoveRows); - - connect(sourceModel, &QAbstractItemModel::rowsAboutToBeMoved, this, - &MovableModel::beginMoveRows); - - connect(sourceModel, &QAbstractItemModel::rowsMoved, this, - &MovableModel::endMoveRows); - - connect(sourceModel, &QAbstractItemModel::dataChanged, this, - &MovableModel::dataChanged); - - connect(sourceModel, &QAbstractItemModel::layoutAboutToBeChanged, this, - &MovableModel::layoutAboutToBeChanged); - - connect(sourceModel, &QAbstractItemModel::layoutChanged, this, - &MovableModel::layoutChanged); - - connect(sourceModel, &QAbstractItemModel::modelAboutToBeReset, this, - &MovableModel::beginResetModel); - - connect(sourceModel, &QAbstractItemModel::modelReset, this, - &MovableModel::endResetModel); - } + connectSignalsForAttachedState(); emit sourceModelChanged(); @@ -213,6 +179,23 @@ void MovableModel::detach() emit detachedChanged(); } +void MovableModel::attach() +{ + if (!m_detached || m_sourceModel == nullptr) + return; + + emit layoutAboutToBeChanged(); + + auto sourceModel = m_sourceModel; + + disconnect(m_sourceModel, nullptr, this, nullptr); + connectSignalsForAttachedState(); + + resetInternalData(); + + emit layoutChanged(); +} + void MovableModel::move(int from, int to, int count) { const int rows = rowCount(); @@ -278,3 +261,42 @@ void MovableModel::resetInternalData() emit detachedChanged(); } } + +void MovableModel::connectSignalsForAttachedState() +{ + if (m_sourceModel == nullptr) + return; + + connect(m_sourceModel, &QAbstractItemModel::rowsAboutToBeInserted, this, + &MovableModel::beginInsertRows); + + connect(m_sourceModel, &QAbstractItemModel::rowsInserted, this, + &MovableModel::endInsertRows); + + connect(m_sourceModel, &QAbstractItemModel::rowsAboutToBeRemoved, this, + &MovableModel::beginRemoveRows); + + connect(m_sourceModel, &QAbstractItemModel::rowsRemoved, this, + &MovableModel::endRemoveRows); + + connect(m_sourceModel, &QAbstractItemModel::rowsAboutToBeMoved, this, + &MovableModel::beginMoveRows); + + connect(m_sourceModel, &QAbstractItemModel::rowsMoved, this, + &MovableModel::endMoveRows); + + connect(m_sourceModel, &QAbstractItemModel::dataChanged, this, + &MovableModel::dataChanged); + + connect(m_sourceModel, &QAbstractItemModel::layoutAboutToBeChanged, this, + &MovableModel::layoutAboutToBeChanged); + + connect(m_sourceModel, &QAbstractItemModel::layoutChanged, this, + &MovableModel::layoutChanged); + + connect(m_sourceModel, &QAbstractItemModel::modelAboutToBeReset, this, + &MovableModel::beginResetModel); + + connect(m_sourceModel, &QAbstractItemModel::modelReset, this, + &MovableModel::endResetModel); +} diff --git a/ui/StatusQ/tests/tst_MovableModel.cpp b/ui/StatusQ/tests/tst_MovableModel.cpp index 6a6b5cffab..c5727010d2 100644 --- a/ui/StatusQ/tests/tst_MovableModel.cpp +++ b/ui/StatusQ/tests/tst_MovableModel.cpp @@ -571,6 +571,98 @@ private slots: // QTest::failOnWarning(QRegularExpression(".?")); // Qt 6.3 sourceModel.move(0, 0, 2); } + + void resetSourceTest() { + QQmlEngine engine; + + auto source1 = R"([ + { "name": "A", "subname": "a1" }, + { "name": "A", "subname": "a2" }, + { "name": "B", "subname": "b1" }, + { "name": "C", "subname": "c1" }, + { "name": "C", "subname": "c2" }, + { "name": "C", "subname": "c3" } + ])"; + + auto source2 = R"([ + { "name_": "A", "subname_": "a1" }, + { "name_": "A", "subname_": "a2" } + ])"; + + ListModelWrapper sourceModel1(engine, source1); + ListModelWrapper sourceModel2(engine, source2); + + MovableModel model; + model.setSourceModel(sourceModel1); + model.detach(); + + QCOMPARE(model.detached(), true); + + ModelSignalsSpy signalsSpy(&model); + QSignalSpy detachChangedSpy(&model, &MovableModel::detachedChanged); + + model.setSourceModel(sourceModel2); + + QCOMPARE(signalsSpy.count(), 2); + QCOMPARE(signalsSpy.modelAboutToBeResetSpy.count(), 1); + QCOMPARE(signalsSpy.modelResetSpy.count(), 1); + + QCOMPARE(detachChangedSpy.count(), 1); + QCOMPARE(model.detached(), false); + QCOMPARE(model.rowCount(), 2); + + QVERIFY(isSame(&model, sourceModel2)); + } + + void attachTest() + { + QQmlEngine engine; + + auto source = R"([ + { "name": "A", "subname": "a1" }, + { "name": "A", "subname": "a2" }, + { "name": "B", "subname": "b1" }, + { "name": "C", "subname": "c1" }, + { "name": "C", "subname": "c2" }, + { "name": "C", "subname": "c3" } + ])"; + + ListModelWrapper sourceModel(engine, source); + MovableModel model; + + { + ModelSignalsSpy signalsSpy(&model); + model.attach(); + QCOMPARE(signalsSpy.count(), 0); + } + + model.setSourceModel(sourceModel); + + { + ModelSignalsSpy signalsSpy(&model); + model.attach(); + QCOMPARE(signalsSpy.count(), 0); + } + + model.detach(); + sourceModel.move(0, 2, 2); + + QVERIFY(!isSame(&model, sourceModel)); + + ModelSignalsSpy signalsSpy(&model); + QSignalSpy detachChangedSpy(&model, &MovableModel::detachedChanged); + + model.attach(); + + QCOMPARE(signalsSpy.count(), 2); + QCOMPARE(signalsSpy.layoutAboutToBeChangedSpy.count(), 1); + QCOMPARE(signalsSpy.layoutChangedSpy.count(), 1); + + QCOMPARE(detachChangedSpy.count(), 1); + QCOMPARE(model.detached(), false); + + QVERIFY(isSame(&model, sourceModel)); + } }; QTEST_MAIN(TestMovableModel)