StatusQ(MovableModel): Add ability to restore and bypass original order of source model
This commit is contained in:
parent
e46f6c311c
commit
f747791f50
|
@ -23,6 +23,7 @@ public:
|
||||||
QHash<int, QByteArray> roleNames() const override;
|
QHash<int, QByteArray> roleNames() const override;
|
||||||
|
|
||||||
Q_INVOKABLE void detach();
|
Q_INVOKABLE void detach();
|
||||||
|
Q_INVOKABLE void attach();
|
||||||
Q_INVOKABLE void move(int from, int to, int count = 1);
|
Q_INVOKABLE void move(int from, int to, int count = 1);
|
||||||
Q_INVOKABLE QVector<int> order() const;
|
Q_INVOKABLE QVector<int> order() const;
|
||||||
|
|
||||||
|
@ -38,6 +39,8 @@ protected slots:
|
||||||
private:
|
private:
|
||||||
QPointer<QAbstractItemModel> m_sourceModel;
|
QPointer<QAbstractItemModel> m_sourceModel;
|
||||||
|
|
||||||
|
void connectSignalsForAttachedState();
|
||||||
|
|
||||||
bool m_detached = false;
|
bool m_detached = false;
|
||||||
std::vector<QPersistentModelIndex> m_indexes;
|
std::vector<QPersistentModelIndex> m_indexes;
|
||||||
};
|
};
|
||||||
|
|
|
@ -20,41 +20,7 @@ void MovableModel::setSourceModel(QAbstractItemModel* sourceModel)
|
||||||
disconnect(m_sourceModel, nullptr, this, nullptr);
|
disconnect(m_sourceModel, nullptr, this, nullptr);
|
||||||
|
|
||||||
m_sourceModel = sourceModel;
|
m_sourceModel = sourceModel;
|
||||||
|
connectSignalsForAttachedState();
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
emit sourceModelChanged();
|
emit sourceModelChanged();
|
||||||
|
|
||||||
|
@ -213,6 +179,23 @@ void MovableModel::detach()
|
||||||
emit detachedChanged();
|
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)
|
void MovableModel::move(int from, int to, int count)
|
||||||
{
|
{
|
||||||
const int rows = rowCount();
|
const int rows = rowCount();
|
||||||
|
@ -278,3 +261,42 @@ void MovableModel::resetInternalData()
|
||||||
emit detachedChanged();
|
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);
|
||||||
|
}
|
||||||
|
|
|
@ -571,6 +571,98 @@ private slots:
|
||||||
// QTest::failOnWarning(QRegularExpression(".?")); // Qt 6.3
|
// QTest::failOnWarning(QRegularExpression(".?")); // Qt 6.3
|
||||||
sourceModel.move(0, 0, 2);
|
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)
|
QTEST_MAIN(TestMovableModel)
|
||||||
|
|
Loading…
Reference in New Issue