From e94554b20952ba2f9296b7c57a57e57c78707342 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Cie=C5=9Blak?= Date: Wed, 27 Sep 2023 13:00:27 +0200 Subject: [PATCH] feat(Storybook): reflect pages model changes in sections decorator model Closes: #12216 --- storybook/pagesmodel.cpp | 10 +- storybook/pagesmodel.h | 2 +- storybook/sectionsdecoratormodel.cpp | 137 ++- storybook/sectionsdecoratormodel.h | 4 +- .../tests/tst_SectionsDecoratorModel.cpp | 841 +++++++++++++++++- 5 files changed, 975 insertions(+), 19 deletions(-) diff --git a/storybook/pagesmodel.cpp b/storybook/pagesmodel.cpp index 9476a2632e..05d1c495b5 100644 --- a/storybook/pagesmodel.cpp +++ b/storybook/pagesmodel.cpp @@ -21,7 +21,7 @@ PagesModel::PagesModel(const QString &path, QObject *parent) this, &PagesModel::reload); } -QList PagesModel::load() { +QList PagesModel::load() const { static QRegularExpression fileNameRegex( QRegularExpression::anchoredPattern("(.*)Page\\.qml")); @@ -71,8 +71,8 @@ void PagesModel::readMetadata(QList &items) { } void PagesModel::reload() { - QList currentItems = load(); - std::map mapping; + const QList currentItems = load(); + std::unordered_map mapping; for (const PagesModelItem &item : qAsConst(m_items)) mapping[item.title] = item; @@ -81,7 +81,7 @@ void PagesModel::reload() { std::vector changedItems; std::vector removedItems; - for (const PagesModelItem &item : qAsConst(currentItems)) { + for (const auto &item : currentItems) { auto it = mapping.find(item.title); if (it == mapping.end()) { @@ -94,7 +94,7 @@ void PagesModel::reload() { } } - for (auto& [key, value] : mapping) + for (const auto& [key, value] : mapping) removedItems.push_back(value); for (auto& item : removedItems) { diff --git a/storybook/pagesmodel.h b/storybook/pagesmodel.h index 80cc3eb79e..b523a19b57 100644 --- a/storybook/pagesmodel.h +++ b/storybook/pagesmodel.h @@ -29,7 +29,7 @@ public: void reload(); private: - QList load(); + QList load() const; static void readMetadata(PagesModelItem &item); static void readMetadata(QList &items); diff --git a/storybook/sectionsdecoratormodel.cpp b/storybook/sectionsdecoratormodel.cpp index 50fbe60fa3..379726c2b2 100644 --- a/storybook/sectionsdecoratormodel.cpp +++ b/storybook/sectionsdecoratormodel.cpp @@ -23,10 +23,15 @@ void SectionsDecoratorModel::setSourceModel(QAbstractItemModel *sourceModel) initialize(); - connect(sourceModel, &QAbstractItemModel::modelReset, this, &SectionsDecoratorModel::initialize); - connect(sourceModel, &QAbstractItemModel::rowsInserted, this, &SectionsDecoratorModel::initialize); - connect(sourceModel, &QAbstractItemModel::rowsRemoved, this, &SectionsDecoratorModel::initialize); - connect(sourceModel, &QAbstractItemModel::rowsMoved, this, &SectionsDecoratorModel::initialize); + connect(sourceModel, &QAbstractItemModel::modelReset, this, + &SectionsDecoratorModel::initialize); + connect(sourceModel, &QAbstractItemModel::rowsMoved, this, + &SectionsDecoratorModel::initialize); + + connect(sourceModel, &QAbstractItemModel::rowsInserted, this, + &SectionsDecoratorModel::onInserted); + connect(sourceModel, &QAbstractItemModel::rowsRemoved, this, + &SectionsDecoratorModel::onRemoved); emit sourceModelChanged(); } @@ -160,3 +165,127 @@ void SectionsDecoratorModel::initialize() calculateOffsets(); } + +void SectionsDecoratorModel::onInserted(const QModelIndex &parent, + int first, int last) +{ + if (first != last) { + initialize(); + return; + } + + const QVariant sectionVariant = m_sourceModel->data( + m_sourceModel->index(first, 0), m_sectionRole); + const QString section = sectionVariant.toString(); + + auto insertNewSection = [this, §ion](int index) { + beginInsertRows(QModelIndex{}, index, index + 1); + + m_rowsMetadata.insert(m_rowsMetadata.begin() + index, RowMetadata{}); + m_rowsMetadata.insert(m_rowsMetadata.begin() + index, + RowMetadata{ true, section, false, 0, 1}); + calculateOffsets(); + endInsertRows(); + }; + + int itemsCounter = 0; + int sectionIndex = 0; + + while (sectionIndex < m_rowsMetadata.size()) { + auto& sectionMetadata = m_rowsMetadata.at(sectionIndex); + + if (sectionMetadata.sectionName == section) { + sectionMetadata.count++; + + emit dataChanged(index(sectionIndex, 0), index(sectionIndex, 0), + { Roles::SubitemsCountRole }); + + if (sectionMetadata.folded) { + // update folded section only + calculateOffsets(); + + } else { + // insert item into unfolded section + auto insertIndex = sectionIndex + (first - itemsCounter) + 1; + + beginInsertRows(QModelIndex{}, insertIndex, insertIndex); + m_rowsMetadata.insert(m_rowsMetadata.begin() + insertIndex, RowMetadata{}); + calculateOffsets(); + endInsertRows(); + } + + break; + } + + if (sectionMetadata.sectionName != section && itemsCounter == first) { + insertNewSection(sectionIndex); + break; + } + + itemsCounter += sectionMetadata.count; + sectionIndex += 1 + (sectionMetadata.folded ? 0 : sectionMetadata.count); + } + + if (sectionIndex == m_rowsMetadata.size()) + insertNewSection(sectionIndex); +} + +void SectionsDecoratorModel::onRemoved(const QModelIndex &parent, + int first, int last) +{ + if (first != last) { + initialize(); + return; + } + + int itemsCounter = 0; + int sectionIndex = 0; + + while (sectionIndex < m_rowsMetadata.size()) { + auto& sectionMetadata = m_rowsMetadata.at(sectionIndex); + + if (first < itemsCounter + sectionMetadata.count) { + + if (sectionMetadata.folded) { + if (sectionMetadata.count == 1) { + auto removeIndex = sectionIndex + (first - itemsCounter); + beginRemoveRows(QModelIndex{}, removeIndex, removeIndex); + m_rowsMetadata.erase(m_rowsMetadata.begin() + removeIndex, + m_rowsMetadata.begin() + removeIndex + 1); + calculateOffsets(); + endRemoveRows(); + } else { + sectionMetadata.count--; + calculateOffsets(); + + emit dataChanged(index(sectionIndex, 0), index(sectionIndex, 0), + { Roles::SubitemsCountRole }); + } + } else { + if (sectionMetadata.count == 1) { + auto removeIndex = sectionIndex + (first - itemsCounter); + beginRemoveRows(QModelIndex{}, removeIndex, removeIndex + 1); + m_rowsMetadata.erase(m_rowsMetadata.begin() + removeIndex, + m_rowsMetadata.begin() + removeIndex + 2); + } else { + sectionMetadata.count--; + emit dataChanged(index(sectionIndex, 0), index(sectionIndex, 0), + { Roles::SubitemsCountRole }); + + auto removeIndex = sectionIndex + (first - itemsCounter) + 1; + + beginRemoveRows(QModelIndex{}, removeIndex, removeIndex); + m_rowsMetadata.erase(m_rowsMetadata.begin() + removeIndex); + } + + calculateOffsets(); + endRemoveRows(); + } + + break; + } + + itemsCounter += sectionMetadata.count; + sectionIndex += 1 + (sectionMetadata.folded ? 0 : sectionMetadata.count); + } +} diff --git a/storybook/sectionsdecoratormodel.h b/storybook/sectionsdecoratormodel.h index d89cefb730..36fae64288 100644 --- a/storybook/sectionsdecoratormodel.h +++ b/storybook/sectionsdecoratormodel.h @@ -1,7 +1,6 @@ #pragma once #include -#include class SectionsDecoratorModel : public QAbstractListModel { @@ -42,6 +41,9 @@ private: void initialize(); void calculateOffsets(); + void onInserted(const QModelIndex &parent, int first, int last); + void onRemoved(const QModelIndex &parent, int first, int last); + QAbstractItemModel* m_sourceModel = nullptr; std::vector m_rowsMetadata; int m_sectionRole = 0; diff --git a/storybook/tests/tst_SectionsDecoratorModel.cpp b/storybook/tests/tst_SectionsDecoratorModel.cpp index 073e7dce44..22ed954a86 100644 --- a/storybook/tests/tst_SectionsDecoratorModel.cpp +++ b/storybook/tests/tst_SectionsDecoratorModel.cpp @@ -13,6 +13,13 @@ class TestSourceModel : public QAbstractListModel { public: explicit TestSourceModel(QStringList categories) : m_categories(std::move(categories)) + { + for (int i = 0; i < m_categories.size(); i++) + m_titles << QString("title %1").arg(i); + } + + explicit TestSourceModel(QStringList categories, QStringList titles) + : m_categories(std::move(categories)), m_titles(std::move(titles)) { } @@ -27,11 +34,28 @@ public: if (!index.isValid()) return {}; - if (role == TitleRole) { - return QString("title %1").arg(index.row()); - } + const auto row = index.row(); - return m_categories.at(index.row()); + if (role == TitleRole) + return m_titles.at(row); + + return m_categories.at(row); + } + + void insert(int index, QString category, QString title) + { + beginInsertRows(QModelIndex{}, index, index); + m_categories.insert(index, category); + m_titles.insert(index, title); + endInsertRows(); + } + + void remove(int index) + { + beginRemoveRows(QModelIndex{}, index, index); + m_categories.removeAt(index); + m_titles.removeAt(index); + endRemoveRows(); } QHash roleNames() const override { @@ -42,6 +66,7 @@ public: } QStringList m_categories; + QStringList m_titles; }; } // unnamed namespace @@ -691,13 +716,9 @@ private slots: SectionsDecoratorModel model; model.setSourceModel(&proxy); - QSignalSpy spy(&model, &SectionsDecoratorModel::modelReset); - proxy.setFilterRole(TestSourceModel::TitleRole); proxy.setFilterWildcard("*1"); - QVERIFY(spy.count() > 1); - QCOMPARE(model.rowCount(), 2); QCOMPARE(model.roleNames().count(), 6); @@ -713,6 +734,810 @@ private slots: QCOMPARE(model.data(model.index(0, 0), SectionsDecoratorModel::SubitemsCountRole).toInt(), 1); QCOMPARE(model.data(model.index(1, 0), SectionsDecoratorModel::SubitemsCountRole).toInt(), 0); } + + void insertionTest() { + { + TestSourceModel src( + QStringList{"Section 1", "Section 1", "Section 1", "Section 2", "Section 2", "Section 3"}, + QStringList{"Title__ 1", "Title__ 2", "Title__ 3", "Title__ 4", "Title__ 5", "Title__ 6"}); + + SectionsDecoratorModel model; + model.setSourceModel(&src); + + QSignalSpy insertionSpy(&model, &SectionsDecoratorModel::rowsInserted); + QSignalSpy changeSpy(&model, &SectionsDecoratorModel::dataChanged); + + src.insert(0, "Section 1", "New Title"); + QCOMPARE(model.rowCount(), 10); + QCOMPARE(insertionSpy.count(), 1); + QCOMPARE(changeSpy.count(), 1); + + auto insertionArguments = insertionSpy.takeFirst(); + QCOMPARE(insertionArguments.at(1).toInt(), 1); + QCOMPARE(insertionArguments.at(2).toInt(), 1); + + auto changeArguments = changeSpy.takeFirst(); + QCOMPARE(changeArguments.at(0).toModelIndex(), model.index(0, 0)); + QCOMPARE(changeArguments.at(1).toModelIndex(), model.index(0, 0)); + + QCOMPARE(model.data(model.index(0, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(1, 0), TestSourceModel::TitleRole).toString(), QString("New Title")); + QCOMPARE(model.data(model.index(2, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 1")); + QCOMPARE(model.data(model.index(3, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 2")); + QCOMPARE(model.data(model.index(4, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 3")); + QCOMPARE(model.data(model.index(5, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(6, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 4")); + QCOMPARE(model.data(model.index(7, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 5")); + QCOMPARE(model.data(model.index(8, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(9, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 6")); + } + { + TestSourceModel src( + QStringList{"Section 1", "Section 1", "Section 1", "Section 2", "Section 2", "Section 3"}, + QStringList{"Title__ 1", "Title__ 2", "Title__ 3", "Title__ 4", "Title__ 5", "Title__ 6"}); + + SectionsDecoratorModel model; + model.setSourceModel(&src); + + QSignalSpy insertionSpy(&model, &SectionsDecoratorModel::rowsInserted); + QSignalSpy changeSpy(&model, &SectionsDecoratorModel::dataChanged); + + src.insert(1, "Section 1", "New Title"); + QCOMPARE(model.rowCount(), 10); + QCOMPARE(insertionSpy.count(), 1); + + auto insertionArguments = insertionSpy.takeFirst(); + QCOMPARE(insertionArguments.at(1).toInt(), 2); + QCOMPARE(insertionArguments.at(2).toInt(), 2); + + auto changeArguments = changeSpy.takeFirst(); + QCOMPARE(changeArguments.at(0).toModelIndex(), model.index(0, 0)); + QCOMPARE(changeArguments.at(1).toModelIndex(), model.index(0, 0)); + + QCOMPARE(model.data(model.index(0, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(1, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 1")); + QCOMPARE(model.data(model.index(2, 0), TestSourceModel::TitleRole).toString(), QString("New Title")); + QCOMPARE(model.data(model.index(3, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 2")); + QCOMPARE(model.data(model.index(4, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 3")); + QCOMPARE(model.data(model.index(5, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(6, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 4")); + QCOMPARE(model.data(model.index(7, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 5")); + QCOMPARE(model.data(model.index(8, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(9, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 6")); + } + { + TestSourceModel src( + QStringList{"Section 1", "Section 1", "Section 1", "Section 2", "Section 2", "Section 3"}, + QStringList{"Title__ 1", "Title__ 2", "Title__ 3", "Title__ 4", "Title__ 5", "Title__ 6"}); + + SectionsDecoratorModel model; + model.setSourceModel(&src); + + QSignalSpy insertionSpy(&model, &SectionsDecoratorModel::rowsInserted); + QSignalSpy changeSpy(&model, &SectionsDecoratorModel::dataChanged); + + src.insert(2, "Section 1", "New Title"); + QCOMPARE(model.rowCount(), 10); + QCOMPARE(insertionSpy.count(), 1); + + auto insertionArguments = insertionSpy.takeFirst(); + QCOMPARE(insertionArguments.at(1).toInt(), 3); + QCOMPARE(insertionArguments.at(2).toInt(), 3); + + auto changeArguments = changeSpy.takeFirst(); + QCOMPARE(changeArguments.at(0).toModelIndex(), model.index(0, 0)); + QCOMPARE(changeArguments.at(1).toModelIndex(), model.index(0, 0)); + + QCOMPARE(model.data(model.index(0, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(1, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 1")); + QCOMPARE(model.data(model.index(2, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 2")); + QCOMPARE(model.data(model.index(3, 0), TestSourceModel::TitleRole).toString(), QString("New Title")); + QCOMPARE(model.data(model.index(4, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 3")); + QCOMPARE(model.data(model.index(5, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(6, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 4")); + QCOMPARE(model.data(model.index(7, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 5")); + QCOMPARE(model.data(model.index(8, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(9, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 6")); + } + { + TestSourceModel src( + QStringList{"Section 1", "Section 1", "Section 1", "Section 2", "Section 2", "Section 3"}, + QStringList{"Title__ 1", "Title__ 2", "Title__ 3", "Title__ 4", "Title__ 5", "Title__ 6"}); + + SectionsDecoratorModel model; + model.setSourceModel(&src); + + QSignalSpy insertionSpy(&model, &SectionsDecoratorModel::rowsInserted); + QSignalSpy changeSpy(&model, &SectionsDecoratorModel::dataChanged); + + src.insert(3, "Section 1", "New Title"); + QCOMPARE(model.rowCount(), 10); + QCOMPARE(insertionSpy.count(), 1); + + auto insertionArguments = insertionSpy.takeFirst(); + QCOMPARE(insertionArguments.at(1).toInt(), 4); + QCOMPARE(insertionArguments.at(2).toInt(), 4); + + auto changeArguments = changeSpy.takeFirst(); + QCOMPARE(changeArguments.at(0).toModelIndex(), model.index(0, 0)); + QCOMPARE(changeArguments.at(1).toModelIndex(), model.index(0, 0)); + + QCOMPARE(model.data(model.index(0, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(1, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 1")); + QCOMPARE(model.data(model.index(2, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 2")); + QCOMPARE(model.data(model.index(3, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 3")); + QCOMPARE(model.data(model.index(4, 0), TestSourceModel::TitleRole).toString(), QString("New Title")); + QCOMPARE(model.data(model.index(5, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(6, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 4")); + QCOMPARE(model.data(model.index(7, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 5")); + QCOMPARE(model.data(model.index(8, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(9, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 6")); + } + { + TestSourceModel src( + QStringList{"Section 1", "Section 1", "Section 1", "Section 2", "Section 2", "Section 3"}, + QStringList{"Title__ 1", "Title__ 2", "Title__ 3", "Title__ 4", "Title__ 5", "Title__ 6"}); + + SectionsDecoratorModel model; + model.setSourceModel(&src); + + QSignalSpy insertionSpy(&model, &SectionsDecoratorModel::rowsInserted); + QSignalSpy changeSpy(&model, &SectionsDecoratorModel::dataChanged); + + src.insert(3, "Section 2", "New Title"); + QCOMPARE(model.rowCount(), 10); + QCOMPARE(insertionSpy.count(), 1); + + auto insertionArguments = insertionSpy.takeFirst(); + QCOMPARE(insertionArguments.at(1).toInt(), 5); + QCOMPARE(insertionArguments.at(2).toInt(), 5); + + auto changeArguments = changeSpy.takeFirst(); + QCOMPARE(changeArguments.at(0).toModelIndex(), model.index(4, 0)); + QCOMPARE(changeArguments.at(1).toModelIndex(), model.index(4, 0)); + + QCOMPARE(model.data(model.index(0, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(1, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 1")); + QCOMPARE(model.data(model.index(2, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 2")); + QCOMPARE(model.data(model.index(3, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 3")); + QCOMPARE(model.data(model.index(4, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(5, 0), TestSourceModel::TitleRole).toString(), QString("New Title")); + QCOMPARE(model.data(model.index(6, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 4")); + QCOMPARE(model.data(model.index(7, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 5")); + QCOMPARE(model.data(model.index(8, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(9, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 6")); + } + { + TestSourceModel src( + QStringList{"Section 1", "Section 1", "Section 1", "Section 2", "Section 2", "Section 3"}, + QStringList{"Title__ 1", "Title__ 2", "Title__ 3", "Title__ 4", "Title__ 5", "Title__ 6"}); + + SectionsDecoratorModel model; + model.setSourceModel(&src); + + QSignalSpy insertionSpy(&model, &SectionsDecoratorModel::rowsInserted); + QSignalSpy changeSpy(&model, &SectionsDecoratorModel::dataChanged); + + src.insert(4, "Section 2", "New Title"); + QCOMPARE(model.rowCount(), 10); + QCOMPARE(insertionSpy.count(), 1); + + auto insertionArguments = insertionSpy.takeFirst(); + QCOMPARE(insertionArguments.at(1).toInt(), 6); + QCOMPARE(insertionArguments.at(2).toInt(), 6); + + auto changeArguments = changeSpy.takeFirst(); + QCOMPARE(changeArguments.at(0).toModelIndex(), model.index(4, 0)); + QCOMPARE(changeArguments.at(1).toModelIndex(), model.index(4, 0)); + + QCOMPARE(model.data(model.index(0, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(1, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 1")); + QCOMPARE(model.data(model.index(2, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 2")); + QCOMPARE(model.data(model.index(3, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 3")); + QCOMPARE(model.data(model.index(4, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(5, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 4")); + QCOMPARE(model.data(model.index(6, 0), TestSourceModel::TitleRole).toString(), QString("New Title")); + QCOMPARE(model.data(model.index(7, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 5")); + QCOMPARE(model.data(model.index(8, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(9, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 6")); + } + { + TestSourceModel src( + QStringList{"Section 1", "Section 1", "Section 1", "Section 2", "Section 2", "Section 3"}, + QStringList{"Title__ 1", "Title__ 2", "Title__ 3", "Title__ 4", "Title__ 5", "Title__ 6"}); + + SectionsDecoratorModel model; + model.setSourceModel(&src); + + QSignalSpy insertionSpy(&model, &SectionsDecoratorModel::rowsInserted); + QSignalSpy changeSpy(&model, &SectionsDecoratorModel::dataChanged); + + src.insert(5, "Section 3", "New Title"); + QCOMPARE(model.rowCount(), 10); + QCOMPARE(insertionSpy.count(), 1); + + auto insertionArguments = insertionSpy.takeFirst(); + QCOMPARE(insertionArguments.at(1).toInt(), 8); + QCOMPARE(insertionArguments.at(2).toInt(), 8); + + auto changeArguments = changeSpy.takeFirst(); + QCOMPARE(changeArguments.at(0).toModelIndex(), model.index(7, 0)); + QCOMPARE(changeArguments.at(1).toModelIndex(), model.index(7, 0)); + + QCOMPARE(model.data(model.index(0, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(1, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 1")); + QCOMPARE(model.data(model.index(2, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 2")); + QCOMPARE(model.data(model.index(3, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 3")); + QCOMPARE(model.data(model.index(4, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(5, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 4")); + QCOMPARE(model.data(model.index(6, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 5")); + QCOMPARE(model.data(model.index(7, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(8, 0), TestSourceModel::TitleRole).toString(), QString("New Title")); + QCOMPARE(model.data(model.index(9, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 6")); + } + { + TestSourceModel src( + QStringList{"Section 1", "Section 1", "Section 1", "Section 2", "Section 2", "Section 3"}, + QStringList{"Title__ 1", "Title__ 2", "Title__ 3", "Title__ 4", "Title__ 5", "Title__ 6"}); + + SectionsDecoratorModel model; + model.setSourceModel(&src); + + QSignalSpy insertionSpy(&model, &SectionsDecoratorModel::rowsInserted); + QSignalSpy changeSpy(&model, &SectionsDecoratorModel::dataChanged); + + src.insert(6, "Section 3", "New Title"); + QCOMPARE(model.rowCount(), 10); + QCOMPARE(insertionSpy.count(), 1); + + auto insertionArguments = insertionSpy.takeFirst(); + QCOMPARE(insertionArguments.at(1).toInt(), 9); + QCOMPARE(insertionArguments.at(2).toInt(), 9); + + auto changeArguments = changeSpy.takeFirst(); + QCOMPARE(changeArguments.at(0).toModelIndex(), model.index(7, 0)); + QCOMPARE(changeArguments.at(1).toModelIndex(), model.index(7, 0)); + + QCOMPARE(model.data(model.index(0, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(1, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 1")); + QCOMPARE(model.data(model.index(2, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 2")); + QCOMPARE(model.data(model.index(3, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 3")); + QCOMPARE(model.data(model.index(4, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(5, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 4")); + QCOMPARE(model.data(model.index(6, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 5")); + QCOMPARE(model.data(model.index(7, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(8, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 6")); + QCOMPARE(model.data(model.index(9, 0), TestSourceModel::TitleRole).toString(), QString("New Title")); + } + { + TestSourceModel src( + QStringList{"Section 1", "Section 1", "Section 1", "Section 2", "Section 2", "Section 3"}, + QStringList{"Title__ 1", "Title__ 2", "Title__ 3", "Title__ 4", "Title__ 5", "Title__ 6"}); + + SectionsDecoratorModel model; + model.setSourceModel(&src); + + + model.flipFolding(0); + + QSignalSpy insertionSpy(&model, &SectionsDecoratorModel::rowsInserted); + QSignalSpy changeSpy(&model, &SectionsDecoratorModel::dataChanged); + + src.insert(0, "Section 1", "New Title"); + QCOMPARE(model.rowCount(), 6); + QCOMPARE(insertionSpy.count(), 0); + QCOMPARE(changeSpy.count(), 1); + + QCOMPARE(model.data(model.index(0, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(1, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(2, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 4")); + QCOMPARE(model.data(model.index(3, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 5")); + QCOMPARE(model.data(model.index(4, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(5, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 6")); + } + { + TestSourceModel src( + QStringList{"Section 1", "Section 1", "Section 1", "Section 2", "Section 2", "Section 3"}, + QStringList{"Title__ 1", "Title__ 2", "Title__ 3", "Title__ 4", "Title__ 5", "Title__ 6"}); + + SectionsDecoratorModel model; + model.setSourceModel(&src); + + + model.flipFolding(0); + + QSignalSpy insertionSpy(&model, &SectionsDecoratorModel::rowsInserted); + QSignalSpy changeSpy(&model, &SectionsDecoratorModel::dataChanged); + + src.insert(1, "Section 1", "New Title"); + QCOMPARE(model.rowCount(), 6); + QCOMPARE(insertionSpy.count(), 0); + QCOMPARE(changeSpy.count(), 1); + + QCOMPARE(model.data(model.index(0, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(1, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(2, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 4")); + QCOMPARE(model.data(model.index(3, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 5")); + QCOMPARE(model.data(model.index(4, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(5, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 6")); + } + { + TestSourceModel src( + QStringList{"Section 1", "Section 1", "Section 1", "Section 2", "Section 2", "Section 3"}, + QStringList{"Title__ 1", "Title__ 2", "Title__ 3", "Title__ 4", "Title__ 5", "Title__ 6"}); + + SectionsDecoratorModel model; + model.setSourceModel(&src); + + + model.flipFolding(0); + + QSignalSpy insertionSpy(&model, &SectionsDecoratorModel::rowsInserted); + QSignalSpy changeSpy(&model, &SectionsDecoratorModel::dataChanged); + + src.insert(3, "Section 1", "New Title"); + QCOMPARE(model.rowCount(), 6); + QCOMPARE(insertionSpy.count(), 0); + QCOMPARE(changeSpy.count(), 1); + + QCOMPARE(model.data(model.index(0, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(1, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(2, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 4")); + QCOMPARE(model.data(model.index(3, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 5")); + QCOMPARE(model.data(model.index(4, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(5, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 6")); + } + { + TestSourceModel src( + QStringList{"Section 1", "Section 1", "Section 1", "Section 2", "Section 2", "Section 3"}, + QStringList{"Title__ 1", "Title__ 2", "Title__ 3", "Title__ 4", "Title__ 5", "Title__ 6"}); + + SectionsDecoratorModel model; + model.setSourceModel(&src); + + + model.flipFolding(0); + + QSignalSpy insertionSpy(&model, &SectionsDecoratorModel::rowsInserted); + QSignalSpy changeSpy(&model, &SectionsDecoratorModel::dataChanged); + + src.insert(3, "Section 2", "New Title"); + QCOMPARE(model.rowCount(), 7); + QCOMPARE(insertionSpy.count(), 1); + + QCOMPARE(changeSpy.count(), 1); + + auto changeArguments = changeSpy.takeFirst(); + QCOMPARE(changeArguments.at(0).toModelIndex(), model.index(1, 0)); + QCOMPARE(changeArguments.at(1).toModelIndex(), model.index(1, 0)); + + QCOMPARE(model.data(model.index(0, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(1, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(2, 0), TestSourceModel::TitleRole).toString(), QString("New Title")); + QCOMPARE(model.data(model.index(3, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 4")); + QCOMPARE(model.data(model.index(4, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 5")); + QCOMPARE(model.data(model.index(5, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(6, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 6")); + } + { + TestSourceModel src( + QStringList{"Section 1", "Section 1", "Section 1", "Section 2", "Section 2", "Section 3"}, + QStringList{"Title__ 1", "Title__ 2", "Title__ 3", "Title__ 4", "Title__ 5", "Title__ 6"}); + + SectionsDecoratorModel model; + model.setSourceModel(&src); + + + model.flipFolding(0); + + QSignalSpy insertionSpy(&model, &SectionsDecoratorModel::rowsInserted); + QSignalSpy changeSpy(&model, &SectionsDecoratorModel::dataChanged); + + src.insert(4, "Section 2", "New Title"); + QCOMPARE(model.rowCount(), 7); + QCOMPARE(insertionSpy.count(), 1); + QCOMPARE(changeSpy.count(), 1); + + auto changeArguments = changeSpy.takeFirst(); + QCOMPARE(changeArguments.at(0).toModelIndex(), model.index(1, 0)); + QCOMPARE(changeArguments.at(1).toModelIndex(), model.index(1, 0)); + + QCOMPARE(model.data(model.index(0, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(1, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(2, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 4")); + QCOMPARE(model.data(model.index(3, 0), TestSourceModel::TitleRole).toString(), QString("New Title")); + QCOMPARE(model.data(model.index(4, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 5")); + QCOMPARE(model.data(model.index(5, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(6, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 6")); + } + { + TestSourceModel src( + QStringList{"Section 1", "Section 1", "Section 1", "Section 2", "Section 2", "Section 3"}, + QStringList{"Title__ 1", "Title__ 2", "Title__ 3", "Title__ 4", "Title__ 5", "Title__ 6"}); + + SectionsDecoratorModel model; + model.setSourceModel(&src); + + QSignalSpy insertionSpy(&model, &SectionsDecoratorModel::rowsInserted); + QSignalSpy changeSpy(&model, &SectionsDecoratorModel::dataChanged); + + src.insert(0, "Section 0", "New Title"); + QCOMPARE(model.rowCount(), 11); + QCOMPARE(insertionSpy.count(), 1); + QCOMPARE(changeSpy.count(), 0); + + auto arguments = insertionSpy.takeFirst(); + QCOMPARE(arguments.at(1).toInt(), 0); + QCOMPARE(arguments.at(2).toInt(), 1); + + QCOMPARE(model.data(model.index(0, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(1, 0), TestSourceModel::TitleRole).toString(), QString("New Title")); + QCOMPARE(model.data(model.index(2, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(3, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 1")); + QCOMPARE(model.data(model.index(4, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 2")); + QCOMPARE(model.data(model.index(5, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 3")); + QCOMPARE(model.data(model.index(6, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(7, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 4")); + QCOMPARE(model.data(model.index(8, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 5")); + QCOMPARE(model.data(model.index(9, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(10, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 6")); + } + { + TestSourceModel src( + QStringList{"Section 1", "Section 1", "Section 1", "Section 2", "Section 2", "Section 3"}, + QStringList{"Title__ 1", "Title__ 2", "Title__ 3", "Title__ 4", "Title__ 5", "Title__ 6"}); + + SectionsDecoratorModel model; + model.setSourceModel(&src); + + QSignalSpy insertionSpy(&model, &SectionsDecoratorModel::rowsInserted); + QSignalSpy changeSpy(&model, &SectionsDecoratorModel::dataChanged); + + src.insert(3, "Section 0", "New Title"); + QCOMPARE(model.rowCount(), 11); + QCOMPARE(insertionSpy.count(), 1); + QCOMPARE(changeSpy.count(), 0); + + auto arguments = insertionSpy.takeFirst(); + QCOMPARE(arguments.at(1).toInt(), 4); + QCOMPARE(arguments.at(2).toInt(), 5); + + QCOMPARE(model.data(model.index(0, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(1, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 1")); + QCOMPARE(model.data(model.index(2, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 2")); + QCOMPARE(model.data(model.index(3, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 3")); + QCOMPARE(model.data(model.index(4, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(5, 0), TestSourceModel::TitleRole).toString(), QString("New Title")); + QCOMPARE(model.data(model.index(6, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(7, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 4")); + QCOMPARE(model.data(model.index(8, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 5")); + QCOMPARE(model.data(model.index(9, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(10, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 6")); + } + { + TestSourceModel src( + QStringList{"Section 1", "Section 1", "Section 1", "Section 2", "Section 2", "Section 3"}, + QStringList{"Title__ 1", "Title__ 2", "Title__ 3", "Title__ 4", "Title__ 5", "Title__ 6"}); + + SectionsDecoratorModel model; + model.setSourceModel(&src); + + QSignalSpy insertionSpy(&model, &SectionsDecoratorModel::rowsInserted); + QSignalSpy changeSpy(&model, &SectionsDecoratorModel::dataChanged); + + src.insert(6, "Section 0", "New Title"); + QCOMPARE(model.rowCount(), 11); + QCOMPARE(insertionSpy.count(), 1); + QCOMPARE(changeSpy.count(), 0); + + auto arguments = insertionSpy.takeFirst(); + QCOMPARE(arguments.at(1).toInt(), 9); + QCOMPARE(arguments.at(2).toInt(), 10); + + QCOMPARE(model.data(model.index(0, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(1, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 1")); + QCOMPARE(model.data(model.index(2, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 2")); + QCOMPARE(model.data(model.index(3, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 3")); + QCOMPARE(model.data(model.index(4, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(5, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 4")); + QCOMPARE(model.data(model.index(6, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 5")); + QCOMPARE(model.data(model.index(7, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(8, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 6")); + QCOMPARE(model.data(model.index(9, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(10, 0), TestSourceModel::TitleRole).toString(), QString("New Title")); + } + { + TestSourceModel src( + QStringList{"Section 1", "Section 1", "Section 1", "Section 2", "Section 2", "Section 3"}, + QStringList{"Title__ 1", "Title__ 2", "Title__ 3", "Title__ 4", "Title__ 5", "Title__ 6"}); + + SectionsDecoratorModel model; + model.setSourceModel(&src); + + model.flipFolding(4); + + QSignalSpy insertionSpy(&model, &SectionsDecoratorModel::rowsInserted); + QSignalSpy changeSpy(&model, &SectionsDecoratorModel::dataChanged); + + src.insert(6, "Section 0", "New Title"); + QCOMPARE(model.rowCount(), 9); + QCOMPARE(insertionSpy.count(), 1); + QCOMPARE(changeSpy.count(), 0); + + auto arguments = insertionSpy.takeFirst(); + QCOMPARE(arguments.at(1).toInt(), 7); + QCOMPARE(arguments.at(2).toInt(), 8); + + QCOMPARE(model.data(model.index(0, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(1, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 1")); + QCOMPARE(model.data(model.index(2, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 2")); + QCOMPARE(model.data(model.index(3, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 3")); + QCOMPARE(model.data(model.index(4, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(5, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(6, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 6")); + QCOMPARE(model.data(model.index(7, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(8, 0), TestSourceModel::TitleRole).toString(), QString("New Title")); + } + } + + void removalTest() { + { + TestSourceModel src( + QStringList{"Section 1", "Section 1", "Section 1", "Section 2", "Section 2", "Section 3"}, + QStringList{"Title__ 1", "Title__ 2", "Title__ 3", "Title__ 4", "Title__ 5", "Title__ 6"}); + + SectionsDecoratorModel model; + model.setSourceModel(&src); + + QSignalSpy removalSpy(&model, &SectionsDecoratorModel::rowsRemoved); + QSignalSpy changeSpy(&model, &SectionsDecoratorModel::dataChanged); + + src.remove(0); + QCOMPARE(model.rowCount(), 8); + QCOMPARE(removalSpy.count(), 1); + QCOMPARE(changeSpy.count(), 1); + + auto removalArguments = removalSpy.takeFirst(); + QCOMPARE(removalArguments.at(1).toInt(), 1); + QCOMPARE(removalArguments.at(2).toInt(), 1); + + auto changeArguments = changeSpy.takeFirst(); + QCOMPARE(changeArguments.at(0).toModelIndex(), model.index(0, 0)); + QCOMPARE(changeArguments.at(1).toModelIndex(), model.index(0, 0)); + + QCOMPARE(model.data(model.index(0, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(1, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 2")); + QCOMPARE(model.data(model.index(2, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 3")); + QCOMPARE(model.data(model.index(3, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(4, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 4")); + QCOMPARE(model.data(model.index(5, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 5")); + QCOMPARE(model.data(model.index(6, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(7, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 6")); + } + { + TestSourceModel src( + QStringList{"Section 1", "Section 1", "Section 1", "Section 2", "Section 2", "Section 3"}, + QStringList{"Title__ 1", "Title__ 2", "Title__ 3", "Title__ 4", "Title__ 5", "Title__ 6"}); + + SectionsDecoratorModel model; + model.setSourceModel(&src); + + QSignalSpy removalSpy(&model, &SectionsDecoratorModel::rowsRemoved); + QSignalSpy changeSpy(&model, &SectionsDecoratorModel::dataChanged); + + src.remove(1); + QCOMPARE(model.rowCount(), 8); + QCOMPARE(removalSpy.count(), 1); + QCOMPARE(changeSpy.count(), 1); + + auto removalArguments = removalSpy.takeFirst(); + QCOMPARE(removalArguments.at(1).toInt(), 2); + QCOMPARE(removalArguments.at(2).toInt(), 2); + + auto changeArguments = changeSpy.takeFirst(); + QCOMPARE(changeArguments.at(0).toModelIndex(), model.index(0, 0)); + QCOMPARE(changeArguments.at(1).toModelIndex(), model.index(0, 0)); + + QCOMPARE(model.data(model.index(0, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(1, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 1")); + QCOMPARE(model.data(model.index(2, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 3")); + QCOMPARE(model.data(model.index(3, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(4, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 4")); + QCOMPARE(model.data(model.index(5, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 5")); + QCOMPARE(model.data(model.index(6, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(7, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 6")); + } + { + TestSourceModel src( + QStringList{"Section 1", "Section 1", "Section 1", "Section 2", "Section 2", "Section 3"}, + QStringList{"Title__ 1", "Title__ 2", "Title__ 3", "Title__ 4", "Title__ 5", "Title__ 6"}); + + SectionsDecoratorModel model; + model.setSourceModel(&src); + + QSignalSpy removalSpy(&model, &SectionsDecoratorModel::rowsRemoved); + QSignalSpy changeSpy(&model, &SectionsDecoratorModel::dataChanged); + + src.remove(2); + QCOMPARE(model.rowCount(), 8); + QCOMPARE(removalSpy.count(), 1); + QCOMPARE(changeSpy.count(), 1); + + auto removalArguments = removalSpy.takeFirst(); + QCOMPARE(removalArguments.at(1).toInt(), 3); + QCOMPARE(removalArguments.at(2).toInt(), 3); + + auto changeArguments = changeSpy.takeFirst(); + QCOMPARE(changeArguments.at(0).toModelIndex(), model.index(0, 0)); + QCOMPARE(changeArguments.at(1).toModelIndex(), model.index(0, 0)); + + QCOMPARE(model.data(model.index(0, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(1, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 1")); + QCOMPARE(model.data(model.index(2, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 2")); + QCOMPARE(model.data(model.index(3, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(4, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 4")); + QCOMPARE(model.data(model.index(5, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 5")); + QCOMPARE(model.data(model.index(6, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(7, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 6")); + } + { + TestSourceModel src( + QStringList{"Section 1", "Section 1", "Section 1", "Section 2", "Section 2", "Section 3"}, + QStringList{"Title__ 1", "Title__ 2", "Title__ 3", "Title__ 4", "Title__ 5", "Title__ 6"}); + + SectionsDecoratorModel model; + model.setSourceModel(&src); + + QSignalSpy removalSpy(&model, &SectionsDecoratorModel::rowsRemoved); + QSignalSpy changeSpy(&model, &SectionsDecoratorModel::dataChanged); + + src.remove(5); + QCOMPARE(model.rowCount(), 7); + QCOMPARE(removalSpy.count(), 1); + QCOMPARE(changeSpy.count(), 0); + + auto removalArguments = removalSpy.takeFirst(); + QCOMPARE(removalArguments.at(1).toInt(), 7); + QCOMPARE(removalArguments.at(2).toInt(), 8); + + QCOMPARE(model.data(model.index(0, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(1, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 1")); + QCOMPARE(model.data(model.index(2, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 2")); + QCOMPARE(model.data(model.index(3, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 3")); + QCOMPARE(model.data(model.index(4, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(5, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 4")); + QCOMPARE(model.data(model.index(6, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 5")); + } + { + TestSourceModel src( + QStringList{"Section 1", "Section 1", "Section 1", "Section 2", "Section 3"}, + QStringList{"Title__ 1", "Title__ 2", "Title__ 3", "Title__ 4", "Title__ 5"}); + + SectionsDecoratorModel model; + model.setSourceModel(&src); + + QSignalSpy removalSpy(&model, &SectionsDecoratorModel::rowsRemoved); + QSignalSpy changeSpy(&model, &SectionsDecoratorModel::dataChanged); + + src.remove(3); + QCOMPARE(model.rowCount(), 6); + QCOMPARE(removalSpy.count(), 1); + QCOMPARE(changeSpy.count(), 0); + + auto arguments = removalSpy.takeFirst(); + QCOMPARE(arguments.at(1).toInt(), 4); + QCOMPARE(arguments.at(2).toInt(), 5); + + QCOMPARE(model.data(model.index(0, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(1, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 1")); + QCOMPARE(model.data(model.index(2, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 2")); + QCOMPARE(model.data(model.index(3, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 3")); + QCOMPARE(model.data(model.index(4, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(5, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 5")); + } + { + TestSourceModel src(QStringList{"Section 1"}, QStringList{"Title__ 1"}); + + SectionsDecoratorModel model; + model.setSourceModel(&src); + + QSignalSpy removalSpy(&model, &SectionsDecoratorModel::rowsRemoved); + QSignalSpy changeSpy(&model, &SectionsDecoratorModel::dataChanged); + + src.remove(0); + QCOMPARE(model.rowCount(), 0); + QCOMPARE(removalSpy.count(), 1); + QCOMPARE(changeSpy.count(), 0); + + auto arguments = removalSpy.takeFirst(); + QCOMPARE(arguments.at(1).toInt(), 0); + QCOMPARE(arguments.at(2).toInt(), 1); + } + { + TestSourceModel src( + QStringList{"Section 1", "Section 1", "Section 1", "Section 2", "Section 2", "Section 3"}, + QStringList{"Title__ 1", "Title__ 2", "Title__ 3", "Title__ 4", "Title__ 5", "Title__ 6"}); + + SectionsDecoratorModel model; + model.setSourceModel(&src); + model.flipFolding(0); + + QSignalSpy removalSpy(&model, &SectionsDecoratorModel::rowsRemoved); + QSignalSpy changeSpy(&model, &SectionsDecoratorModel::dataChanged); + + src.remove(0); + QCOMPARE(model.rowCount(), 6); + QCOMPARE(removalSpy.count(), 0); + QCOMPARE(changeSpy.count(), 1); + + auto changeArguments = changeSpy.takeFirst(); + QCOMPARE(changeArguments.at(0).toModelIndex(), model.index(0, 0)); + QCOMPARE(changeArguments.at(1).toModelIndex(), model.index(0, 0)); + + QCOMPARE(model.data(model.index(0, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(1, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(2, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 4")); + QCOMPARE(model.data(model.index(3, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 5")); + QCOMPARE(model.data(model.index(4, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(5, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 6")); + } + { + TestSourceModel src( + QStringList{"Section 1", "Section 1", "Section 1", "Section 2", "Section 2", "Section 3"}, + QStringList{"Title__ 1", "Title__ 2", "Title__ 3", "Title__ 4", "Title__ 5", "Title__ 6"}); + + SectionsDecoratorModel model; + model.setSourceModel(&src); + model.flipFolding(0); + model.flipFolding(1); + model.flipFolding(2); + + QSignalSpy removalSpy(&model, &SectionsDecoratorModel::rowsRemoved); + QSignalSpy changeSpy(&model, &SectionsDecoratorModel::dataChanged); + + src.remove(1); + QCOMPARE(model.rowCount(), 3); + QCOMPARE(removalSpy.count(), 0); + QCOMPARE(changeSpy.count(), 1); + + auto changeArguments = changeSpy.takeFirst(); + QCOMPARE(changeArguments.at(0).toModelIndex(), model.index(0, 0)); + QCOMPARE(changeArguments.at(1).toModelIndex(), model.index(0, 0)); + + QCOMPARE(model.data(model.index(0, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(1, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(2, 0), TestSourceModel::TitleRole), QVariant{}); + } + { + TestSourceModel src( + QStringList{"Section 1", "Section 1", "Section 1", "Section 2", "Section 2", "Section 3"}, + QStringList{"Title__ 1", "Title__ 2", "Title__ 3", "Title__ 4", "Title__ 5", "Title__ 6"}); + + SectionsDecoratorModel model; + model.setSourceModel(&src); + model.flipFolding(7); + + QSignalSpy removalSpy(&model, &SectionsDecoratorModel::rowsRemoved); + QSignalSpy changeSpy(&model, &SectionsDecoratorModel::dataChanged); + + src.remove(5); + QCOMPARE(model.rowCount(), 7); + QCOMPARE(removalSpy.count(), 1); + QCOMPARE(changeSpy.count(), 0); + + auto removalArguments = removalSpy.takeFirst(); + QCOMPARE(removalArguments.at(1).toInt(), 7); + QCOMPARE(removalArguments.at(2).toInt(), 7); + + QCOMPARE(model.data(model.index(0, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(1, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 1")); + QCOMPARE(model.data(model.index(2, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 2")); + QCOMPARE(model.data(model.index(3, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 3")); + QCOMPARE(model.data(model.index(4, 0), TestSourceModel::TitleRole), QVariant{}); + QCOMPARE(model.data(model.index(5, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 4")); + QCOMPARE(model.data(model.index(6, 0), TestSourceModel::TitleRole).toString(), QString("Title__ 5")); + } + } }; // TODO: signals emission testing using QSignalSpy