From 853641fb890fc1a879ae02567798137bda7721f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Cie=C5=9Blak?= Date: Tue, 3 Oct 2023 11:48:40 +0200 Subject: [PATCH] feat(Storybook): read Figma links directly from pages --- storybook/CMakeLists.txt | 6 - storybook/figmadecoratormodel.cpp | 94 ----- storybook/figmadecoratormodel.h | 34 -- storybook/figmalinkssource.cpp | 139 ------- storybook/figmalinkssource.h | 37 -- storybook/main.cpp | 4 - storybook/main.qml | 24 +- storybook/pages/ImagesGridViewPage.qml | 66 +--- storybook/pagesmodel.cpp | 45 ++- storybook/pagesmodel.h | 9 +- .../src/Storybook/FigmaImagesProxyModel.qml | 6 +- storybook/src/Storybook/FigmaLinksCache.qml | 2 +- .../src/Storybook/FigmaPreviewWindow.qml | 112 ------ storybook/src/Storybook/ImagesGridView.qml | 30 +- storybook/tests/tst_FigmaDecoratorModel.cpp | 341 ------------------ 15 files changed, 71 insertions(+), 878 deletions(-) delete mode 100644 storybook/figmadecoratormodel.cpp delete mode 100644 storybook/figmadecoratormodel.h delete mode 100644 storybook/figmalinkssource.cpp delete mode 100644 storybook/figmalinkssource.h delete mode 100644 storybook/tests/tst_FigmaDecoratorModel.cpp diff --git a/storybook/CMakeLists.txt b/storybook/CMakeLists.txt index 6423b2a721..ff587e1518 100644 --- a/storybook/CMakeLists.txt +++ b/storybook/CMakeLists.txt @@ -45,11 +45,9 @@ set(PROJECT_LIB "${PROJECT_NAME}Lib") add_library(${PROJECT_LIB} cachecleaner.cpp cachecleaner.h directorieswatcher.cpp directorieswatcher.h - figmadecoratormodel.cpp figmadecoratormodel.h figmaio.cpp figmaio.h figmalinks.cpp figmalinks.h figmalinksmodel.cpp figmalinksmodel.h - figmalinkssource.cpp figmalinkssource.h modelutils.cpp modelutils.h pagesmodel.h pagesmodel.cpp sectionsdecoratormodel.cpp sectionsdecoratormodel.h @@ -99,10 +97,6 @@ add_executable(SectionsDecoratorModelTest tests/tst_SectionsDecoratorModel.cpp) target_link_libraries(SectionsDecoratorModelTest PRIVATE Qt5::Test ${PROJECT_LIB}) add_test(NAME SectionsDecoratorModelTest COMMAND SectionsDecoratorModelTest) -add_executable(FigmaDecoratorModelTest tests/tst_FigmaDecoratorModel.cpp) -target_link_libraries(FigmaDecoratorModelTest PRIVATE Qt5::Test ${PROJECT_LIB}) -add_test(NAME FigmaModelTest COMMAND FigmaModelTest) - add_executable(QmlTests qmlTests/main.cpp qmlTests/src/TextUtils.cpp qmlTests/src/TextUtils.h diff --git a/storybook/figmadecoratormodel.cpp b/storybook/figmadecoratormodel.cpp deleted file mode 100644 index d8e0110afc..0000000000 --- a/storybook/figmadecoratormodel.cpp +++ /dev/null @@ -1,94 +0,0 @@ -#include "figmadecoratormodel.h" - -#include "figmalinks.h" -#include "figmalinksmodel.h" -#include "modelutils.h" - -FigmaDecoratorModel::FigmaDecoratorModel(QObject *parent) - : QIdentityProxyModel{parent} -{ -} - -QHash FigmaDecoratorModel::roleNames() const -{ - auto roles = QIdentityProxyModel::roleNames(); - roles.insert(FigmaRole, QByteArrayLiteral("figma")); - - return roles; -} - -QVariant FigmaDecoratorModel::data(const QModelIndex &proxyIndex, int role) const -{ - if (!checkIndex(proxyIndex, CheckIndexOption::IndexIsValid)) - return {}; - - if (role == FigmaRole) { - static FigmaLinksModel empty({}); - - if (!m_titleRole) - return QVariant::fromValue(&empty); - - const auto title = data(proxyIndex, m_titleRole.value()).toString(); - auto it = m_submodels.find(title); - - if (it == m_submodels.end()) { - QStringList links; - - if (m_figmaLinks) - links = m_figmaLinks->getLinksMap().value(title, {}); - - auto linksModel = new FigmaLinksModel( - links, const_cast(this)); - it = m_submodels.insert(title, linksModel); - } - - return QVariant::fromValue(it.value()); - } - - return QIdentityProxyModel::data(proxyIndex, role); -} - -FigmaLinks* FigmaDecoratorModel::getFigmaLinks() const -{ - return m_figmaLinks; -} - -void FigmaDecoratorModel::setFigmaLinks(FigmaLinks *figmaLinks) -{ - if (figmaLinks == m_figmaLinks) - return; - - m_figmaLinks = figmaLinks; - const auto& linksMap = m_figmaLinks - ? m_figmaLinks->getLinksMap() - : QMap{}; - - auto linksIt = linksMap.constBegin(); - while (linksIt != linksMap.constEnd()) { - if (m_submodels.contains(linksIt.key())) - m_submodels.value(linksIt.key())->setContent(linksIt.value()); - ++linksIt; - } - - auto submodelsIt = m_submodels.constBegin(); - while (submodelsIt != m_submodels.constEnd()) { - if (!linksMap.contains(submodelsIt.key())) - submodelsIt.value()->setContent({}); - ++submodelsIt; - } - - emit figmaLinksChanged(); -} - -void FigmaDecoratorModel::setSourceModel(QAbstractItemModel *sourceModel) -{ - qDeleteAll(m_submodels); - m_submodels.clear(); - - m_titleRole = ModelUtils::findRole(QByteArrayLiteral("title"), sourceModel); - - if(!m_titleRole) - qWarning("The source model is missing title role!"); - - QIdentityProxyModel::setSourceModel(sourceModel); -} diff --git a/storybook/figmadecoratormodel.h b/storybook/figmadecoratormodel.h deleted file mode 100644 index eab7d09f08..0000000000 --- a/storybook/figmadecoratormodel.h +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once - -#include -#include - -class FigmaLinks; -class FigmaLinksModel; - -class FigmaDecoratorModel : public QIdentityProxyModel -{ - Q_OBJECT - Q_PROPERTY(FigmaLinks* figmaLinks READ getFigmaLinks - WRITE setFigmaLinks NOTIFY figmaLinksChanged) -public: - static constexpr auto FigmaRole = Qt::UserRole + 100; - - explicit FigmaDecoratorModel(QObject *parent = nullptr); - - QHash roleNames() const override; - QVariant data(const QModelIndex &proxyIndex, int role) const override; - - FigmaLinks* getFigmaLinks() const; - void setFigmaLinks(FigmaLinks *figmaLinks); - - void setSourceModel(QAbstractItemModel *sourceModel) override; - -signals: - void figmaLinksChanged(); - -private: - std::optional m_titleRole; - FigmaLinks* m_figmaLinks = nullptr; - mutable QMap m_submodels; -}; diff --git a/storybook/figmalinkssource.cpp b/storybook/figmalinkssource.cpp deleted file mode 100644 index 797a334437..0000000000 --- a/storybook/figmalinkssource.cpp +++ /dev/null @@ -1,139 +0,0 @@ -#include "figmalinkssource.h" - -#include - -#include "figmaio.h" -#include "figmalinks.h" - -FigmaLinksSource::FigmaLinksSource(QObject *parent) - : QObject{parent} -{ - connect(&m_watcher, &QFileSystemWatcher::fileChanged, - this, [this](const QString &path) { - this->readFile(); - - if (!this->m_watcher.files().contains(path)) - this->m_watcher.addPath(path); - }); -} - -const QUrl& FigmaLinksSource::getFilePath() const -{ - return m_filePath; -} - -void FigmaLinksSource::setFilePath(const QUrl& path) -{ - if (path == m_filePath) - return; - - m_filePath = path; - readFile(); - setupWatcher(); - emit filePathChanged(); -} - -FigmaLinks* FigmaLinksSource::getFigmaLinks() const -{ - return m_figmaLinks; -} - -void FigmaLinksSource::remove(const QString &key, const QList &indexes) -{ - if (m_filePath.isEmpty()) { - qWarning("FigmaLinksSource::remove - file path is not set!"); - return; - } - - QMap linksMap; - - if (m_figmaLinks) - linksMap = m_figmaLinks->getLinksMap(); - - auto it = linksMap.find(key); - - if (it == linksMap.end()) { - qWarning("FigmaLinksSource::remove - provided key doesn't exist!"); - return; - } - - if (indexes.isEmpty()) - return; - - auto indexesSorted = indexes; - std::sort(indexesSorted.begin(), indexesSorted.end()); - - if (std::adjacent_find(indexesSorted.cbegin(), indexesSorted.cend()) - != indexesSorted.cend()) { - qWarning("FigmaLinksSource::remove - provided indexes list contains duplicates!"); - return; - } - - auto& linksList = it.value(); - - if (indexesSorted.first() < 0 || indexesSorted.last() >= linksList.size()) { - qWarning("FigmaLinksSource::remove - at least one provided index is out of range!"); - return; - } - - if (linksList.size() == indexesSorted.size()) { - linksMap.erase(it); - } else { - std::for_each(std::crbegin(indexesSorted), std::crend(indexesSorted), - [&linksList](int idx) { - linksList.removeAt(idx); - }); - } - - FigmaIO::write(m_filePath.path(), linksMap); -} - -void FigmaLinksSource::append(const QString &key, const QList &links) -{ - QMap linksMap; - - - if (m_filePath.isEmpty()) { - qWarning("FigmaLinksSource::append - file path is not set!"); - return; - } - - if (m_figmaLinks) - linksMap = m_figmaLinks->getLinksMap(); - - linksMap[key].append(links); - - FigmaIO::write(m_filePath.path(), linksMap); -} - -void FigmaLinksSource::updateFigmaLinks(const QMap& map) -{ - FigmaLinks *mapping = new FigmaLinks(map, this); - - if (m_figmaLinks && qjsEngine(m_figmaLinks)) { - m_figmaLinks->setParent(nullptr); - QQmlEngine::setObjectOwnership(m_figmaLinks, QQmlEngine::JavaScriptOwnership); - } - - m_figmaLinks = mapping; - emit figmaLinksChanged(); -} - -void FigmaLinksSource::readFile() -{ - QMap figmaLinks = FigmaIO::read(m_filePath.path()); - updateFigmaLinks(figmaLinks); -} - -void FigmaLinksSource::setupWatcher() -{ - auto currentlyWatched = m_watcher.files(); - - if (!currentlyWatched.isEmpty()) - m_watcher.removePaths(currentlyWatched); - - if (m_filePath.isEmpty()) - return; - - m_watcher.addPath(m_filePath.path()); -} diff --git a/storybook/figmalinkssource.h b/storybook/figmalinkssource.h deleted file mode 100644 index 20437e54c8..0000000000 --- a/storybook/figmalinkssource.h +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -#include -#include -#include - -class FigmaLinks; - -class FigmaLinksSource : public QObject -{ - Q_OBJECT - Q_PROPERTY(QUrl filePath READ getFilePath WRITE setFilePath NOTIFY filePathChanged) - Q_PROPERTY(FigmaLinks* figmaLinks READ getFigmaLinks NOTIFY figmaLinksChanged) - -public: - explicit FigmaLinksSource(QObject *parent = nullptr); - - const QUrl& getFilePath() const; - void setFilePath(const QUrl& path); - FigmaLinks* getFigmaLinks() const; - - Q_INVOKABLE void remove(const QString &key, const QList &indexes); - Q_INVOKABLE void append(const QString &key, const QList &links); - -signals: - void filePathChanged(); - void figmaLinksChanged(); - -private: - void updateFigmaLinks(const QMap& map); - void readFile(); - void setupWatcher(); - - FigmaLinks *m_figmaLinks = nullptr; - QUrl m_filePath; - QFileSystemWatcher m_watcher; -}; diff --git a/storybook/main.cpp b/storybook/main.cpp index 116776c337..13e30db204 100644 --- a/storybook/main.cpp +++ b/storybook/main.cpp @@ -4,9 +4,7 @@ #include "cachecleaner.h" #include "directorieswatcher.h" -#include "figmadecoratormodel.h" #include "figmalinks.h" -#include "figmalinkssource.h" #include "pagesmodel.h" #include "sectionsdecoratormodel.h" @@ -46,8 +44,6 @@ int main(int argc, char *argv[]) engine.rootContext()->setContextProperty( "pagesFolder", QML_IMPORT_ROOT + QStringLiteral("/pages")); - qmlRegisterType("Storybook", 1, 0, "FigmaDecoratorModel"); - qmlRegisterType("Storybook", 1, 0, "FigmaLinksSource"); qmlRegisterType("Storybook", 1, 0, "PagesModel"); qmlRegisterType("Storybook", 1, 0, "SectionsDecoratorModel"); qmlRegisterUncreatableType("Storybook", 1, 0, "FigmaLinks", {}); diff --git a/storybook/main.qml b/storybook/main.qml index 284b182a68..489852a4c5 100644 --- a/storybook/main.qml +++ b/storybook/main.qml @@ -1,6 +1,6 @@ -import QtQuick 2.14 -import QtQuick.Controls 2.14 -import QtQuick.Layouts 1.14 +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.15 import Qt.labs.settings 1.0 @@ -78,19 +78,6 @@ ApplicationWindow { id: pagesModel } - FigmaLinksSource { - id: figmaLinksSource - - filePath: "figma.json" - } - - FigmaDecoratorModel { - id: figmaModel - - sourceModel: pagesModel - figmaLinks: figmaLinksSource.figmaLinks - } - HotReloader { id: reloader @@ -212,7 +199,7 @@ ApplicationWindow { id: currentPageModelItem model: SingleItemProxyModel { - sourceModel: figmaModel + sourceModel: pagesModel roleName: "title" value: root.currentPage } @@ -320,9 +307,6 @@ Tips: figmaLinksCache: figmaImageLinksCache } - onRemoveLinksRequested: figmaLinksSource.remove(pageTitle, indexes) - onAppendLinksRequested: figmaLinksSource.append(pageTitle, links) - onClosing: Qt.callLater(destroy) } } diff --git a/storybook/pages/ImagesGridViewPage.qml b/storybook/pages/ImagesGridViewPage.qml index 8efe9f7aa3..c2f52031b4 100644 --- a/storybook/pages/ImagesGridViewPage.qml +++ b/storybook/pages/ImagesGridViewPage.qml @@ -1,6 +1,6 @@ -import QtQuick 2.14 -import QtQuick.Controls 2.14 -import QtQuick.Layouts 1.14 +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.15 import Storybook 1.0 @@ -50,63 +50,13 @@ Pane { } } - ColumnLayout { + ImagesGridView { + id: grid + anchors.fill: parent - RowLayout { - Layout.fillWidth: true - - CheckBox { - id: selectableCheckBox - - Layout.alignment: Qt.AlignVCenter - - text: "selectable" - } - - ToolSeparator { - Layout.alignment: Qt.AlignVCenter - } - - Label { - id: selectionText - - Layout.fillWidth: true - Layout.alignment: Qt.AlignVCenter - - property string selectionAsString: "" - - text: `selected indexes: [${selectionAsString}]` - - Connections { - target: grid.selection - - function onSelectionChanged() { - const indexes = grid.selection.selectedIndexes - const rows = indexes.map(idx => idx.row) - - selectionText.selectionAsString = rows.join(", ") - } - } - } - - Button { - text: "Clear selection" - - onClicked: grid.selection.clear() - } - } - - ImagesGridView { - id: grid - - Layout.fillWidth: true - Layout.fillHeight: true - - selectable: selectableCheckBox.checked - clip: true - model: imagesModel - } + clip: true + model: imagesModel } } diff --git a/storybook/pagesmodel.cpp b/storybook/pagesmodel.cpp index 05d1c495b5..c4b763255d 100644 --- a/storybook/pagesmodel.cpp +++ b/storybook/pagesmodel.cpp @@ -4,6 +4,8 @@ #include #include +#include + namespace { const auto categoryUncategorized QStringLiteral("Uncategorized"); } @@ -15,6 +17,10 @@ PagesModel::PagesModel(const QString &path, QObject *parent) m_items = load(); readMetadata(m_items); + for (const auto& item : qAsConst(m_items)) { + setFigmaLinks(item.title, item.figmaLinks); + } + fsWatcher->addPath(path); connect(fsWatcher, &QFileSystemWatcher::directoryChanged, @@ -62,6 +68,21 @@ void PagesModel::readMetadata(PagesModelItem& item) { ? categoryMatch.captured(2).trimmed() : categoryUncategorized; item.category = category; + + static QRegularExpression figmaRegex( + "^(\\/\\/\\s*)((?:https:\\/\\/)?(?:www\\.)?figma\\.com\\/.*)$", + QRegularExpression::MultilineOption); + + QRegularExpressionMatchIterator i = figmaRegex.globalMatch(content); + QStringList links; + + while (i.hasNext()) { + QRegularExpressionMatch match = i.next(); + QString link = match.captured(2); + links << link; + } + + item.figmaLinks = links; } void PagesModel::readMetadata(QList &items) { @@ -129,6 +150,7 @@ void PagesModel::reload() { auto index = std::distance(m_items.begin(), it); const auto& previous = *it; readMetadata(item); + setFigmaLinks(item.title, item.figmaLinks); if (previous.category != item.category) { // For simplicity category change is handled by removing and @@ -149,7 +171,8 @@ QHash PagesModel::roleNames() const { static const QHash roles { { TitleRole, QByteArrayLiteral("title") }, - { CategoryRole, QByteArrayLiteral("category") } + { CategoryRole, QByteArrayLiteral("category") }, + { FigmaRole, QByteArrayLiteral("figma") } }; return roles; @@ -167,8 +190,28 @@ QVariant PagesModel::data(const QModelIndex &index, int role) const if (role == TitleRole) return m_items.at(index.row()).title; + if (role == CategoryRole) return m_items.at(index.row()).category; + if (role == FigmaRole) { + auto title = m_items.at(index.row()).title; + auto it = m_figmaSubmodels.find(title); + assert(it != m_figmaSubmodels.end()); + + return QVariant::fromValue(it.value()); + } + return {}; } + +void PagesModel::setFigmaLinks(const QString& title, const QStringList& links) +{ + auto it = m_figmaSubmodels.find(title); + + if (it == m_figmaSubmodels.end()) { + m_figmaSubmodels.insert(title, new FigmaLinksModel(links, this)); + } else { + it.value()->setContent(links); + } +} diff --git a/storybook/pagesmodel.h b/storybook/pagesmodel.h index b523a19b57..54bb8da65f 100644 --- a/storybook/pagesmodel.h +++ b/storybook/pagesmodel.h @@ -3,6 +3,8 @@ #include #include +#include "figmalinksmodel.h" + class QFileSystemWatcher; struct PagesModelItem { @@ -10,6 +12,7 @@ struct PagesModelItem { QDateTime lastModified; QString title; QString category; + QStringList figmaLinks; }; class PagesModel : public QAbstractListModel @@ -20,7 +23,8 @@ public: enum Roles { TitleRole = Qt::UserRole + 1, - CategoryRole + CategoryRole, + FigmaRole }; QHash roleNames() const override; @@ -34,7 +38,10 @@ private: static void readMetadata(PagesModelItem &item); static void readMetadata(QList &items); + void setFigmaLinks(const QString& title, const QStringList& links); + QString m_path; QList m_items; + QMap m_figmaSubmodels; QFileSystemWatcher* fsWatcher; }; diff --git a/storybook/src/Storybook/FigmaImagesProxyModel.qml b/storybook/src/Storybook/FigmaImagesProxyModel.qml index 084c806660..16191ab45e 100644 --- a/storybook/src/Storybook/FigmaImagesProxyModel.qml +++ b/storybook/src/Storybook/FigmaImagesProxyModel.qml @@ -1,9 +1,9 @@ -import QtQuick 2.14 +import QtQuick 2.15 ListModel { id: root - /* required */ property FigmaLinksCache figmaLinksCache + required property FigmaLinksCache figmaLinksCache property alias sourceModel: d.model readonly property Instantiator _d: Instantiator { @@ -29,7 +29,7 @@ ListModel { d.idCounter++ figmaLinksCache.getImageUrl(model.link, link => { - if (delegate) + if (delegate && link !== null) root.setProperty(model.index, "imageLink", link) }) } diff --git a/storybook/src/Storybook/FigmaLinksCache.qml b/storybook/src/Storybook/FigmaLinksCache.qml index 41b091df93..4c47cebb34 100644 --- a/storybook/src/Storybook/FigmaLinksCache.qml +++ b/storybook/src/Storybook/FigmaLinksCache.qml @@ -1,4 +1,4 @@ -import QtQml 2.14 +import QtQml 2.15 QtObject { id: root diff --git a/storybook/src/Storybook/FigmaPreviewWindow.qml b/storybook/src/Storybook/FigmaPreviewWindow.qml index 12ce150659..c83f6eee44 100644 --- a/storybook/src/Storybook/FigmaPreviewWindow.qml +++ b/storybook/src/Storybook/FigmaPreviewWindow.qml @@ -14,10 +14,6 @@ ApplicationWindow { signal removeLinksRequested(var indexes) signal appendLinksRequested(var links) - readonly property var urlRegex: - /^https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b(?:[-a-zA-Z0-9()@:%_\+.~#?&\/=]*)$/ - - SwipeView { id: topSwipeView @@ -40,37 +36,6 @@ ApplicationWindow { topSwipeView.incrementCurrentIndex() } } - - footer: ToolBar { - RowLayout { - anchors.fill: parent - - Button { - id: removeButton - - readonly property int selectionCount: - grid.selection.selectedIndexes.length - - text: "Remove selected" - + (enabled ? ` (${selectionCount})` : "") - enabled: grid.selection.hasSelection - - onClicked: removeConfirmDialog.open() - } - - ToolSeparator {} - - Button { - text: "Add new links" - - onClicked: addNewLinksDialog.open() - } - - Item { - Layout.fillWidth: true - } - } - } } Item { @@ -106,81 +71,4 @@ ApplicationWindow { } } } - - Dialog { - id: removeConfirmDialog - - readonly property var selected: grid.selection.selectedIndexes - - anchors.centerIn: Overlay.overlay - - title: "Links removal" - standardButtons: Dialog.Ok | Dialog.Cancel - - Label { - text: "Are you sure that you want to remove " - + removeButton.selectionCount + " link(s)?" - } - - onAccepted: root.removeLinksRequested(selected.map(idx => idx.row)) - onSelectedChanged: close() - } - - Dialog { - id: addNewLinksDialog - - anchors.centerIn: Overlay.overlay - - title: "Add new Figma links" - standardButtons: Dialog.Save | Dialog.Cancel - - width: parent.width * 0.8 - height: parent.height * 0.4 - - GroupBox { - anchors.fill: parent - - title: "Figma links, 1 per line" - - ScrollView { - id: scrollView - - anchors.fill: parent - clip: true - - contentHeight: linksTextEdit.implicitHeight - contentWidth: linksTextEdit.implicitWidth - - TextEdit { - id: linksTextEdit - - property var links: [] - - width: scrollView.width - height: scrollView.height - - font.pixelSize: 13 - selectByMouse: true - - onTextChanged: { - const allLines = text.split("\n") - const nonEmptyLines = allLines.filter( - line => line.trim().length > 0) - const trimmed = nonEmptyLines.map(line => line.trim()) - - links = trimmed.every(line => root.urlRegex.test(line)) - ? trimmed : [] - } - } - } - } - - onClosed: Qt.callLater(linksTextEdit.clear) - onAccepted: root.appendLinksRequested(linksTextEdit.links) - - Component.onCompleted: { - standardButton(Dialog.Save).enabled - = Qt.binding(() => linksTextEdit.links.length > 0) - } - } } diff --git a/storybook/src/Storybook/ImagesGridView.qml b/storybook/src/Storybook/ImagesGridView.qml index f314bea8be..4d0add4e57 100644 --- a/storybook/src/Storybook/ImagesGridView.qml +++ b/storybook/src/Storybook/ImagesGridView.qml @@ -1,6 +1,6 @@ -import QtQuick 2.14 -import QtQuick.Controls 2.14 -import QtQml.Models 2.14 +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQml.Models 2.15 GridView { id: root @@ -10,15 +10,6 @@ GridView { signal clicked(int index) - property bool selectable: true - readonly property alias selection: selectionModel - - ItemSelectionModel { - id: selectionModel - - model: root.model - } - delegate: Item { width: root.cellWidth height: root.cellHeight @@ -60,21 +51,6 @@ GridView { ToolTip.visible: hovered ToolTip.text: model.rawLink } - - CheckBox { - visible: root.selectable - - anchors.top: parent.top - anchors.right: parent.right - - checked: { - selectionModel.selection - return selectionModel.isSelected(root.model.index(index, 0)) - } - - onToggled: selectionModel.select(root.model.index(index, 0), - ItemSelectionModel.Toggle) - } } } } diff --git a/storybook/tests/tst_FigmaDecoratorModel.cpp b/storybook/tests/tst_FigmaDecoratorModel.cpp deleted file mode 100644 index 318b4696a9..0000000000 --- a/storybook/tests/tst_FigmaDecoratorModel.cpp +++ /dev/null @@ -1,341 +0,0 @@ -#include -#include -#include -#include - -#include "figmadecoratormodel.h" -#include "figmaio.h" -#include "figmalinks.h" -#include "figmalinksmodel.h" -#include "figmalinkssource.h" - -namespace { - -auto constexpr sampleJson1 = R"( -{ - "Component_1": [ - "link_1", "link_2" - ], - "Component_2": [ - "link_3", "link_4" - ] -} -)"; - -auto constexpr sampleJson2 = R"( -{ - "Component_1": [ - "link_1" - ], - "Component_2": [ - "link_3", "link_5" - ] -} -)"; - -class TestSourceModel : public QAbstractListModel { - -public: - static constexpr auto TitleRole = 0; - - TestSourceModel(int count = 1) : m_count(count) {} - - int rowCount(const QModelIndex &parent = QModelIndex()) const override { - return m_count; - } - - QVariant data(const QModelIndex &index, int role) const override { - if (!index.isValid()) - return {}; - - return QString("title_%1").arg(index.row()); - } - - QHash roleNames() const override { - QHash roles; - roles.insert(TitleRole, QByteArrayLiteral("title")); - return roles; - } - - int m_count; -}; - -} // unnamed namespace - -class FigmaDecoratorModelTest: public QObject -{ - Q_OBJECT - -private slots: - void figmaIOTest() { - QTemporaryFile file; - QVERIFY(file.open()); - file.close(); - - const auto readEmpty = FigmaIO::read(file.fileName()); - QCOMPARE(readEmpty, {}); - - const QMap content = { - { "k_1", { "l_1", "l_2"}}, - { "k_2", { "l_3", "l_4"}} - }; - - FigmaIO::write(file.fileName(), content); - const auto readContent = FigmaIO::read(file.fileName()); - - QCOMPARE(readContent, content); - } - - void readingFigmaFileTest() { - FigmaLinksSource figmaLinksSource; - - QSignalSpy spy(&figmaLinksSource, &FigmaLinksSource::figmaLinksChanged); - - QCOMPARE(figmaLinksSource.getFigmaLinks(), nullptr); - - QTemporaryFile file; - if (file.open()) { - QTextStream stream(&file); - stream << sampleJson1; - } - - figmaLinksSource.setFilePath(file.fileName()); - - QVERIFY(figmaLinksSource.getFigmaLinks() != nullptr); - - const FigmaLinks *links = figmaLinksSource.getFigmaLinks(); - - QCOMPARE(links->getLinksMap(), (QMap { - {{"Component_1"}, {"link_1", "link_2"}}, - {{"Component_2"}, {"link_3", "link_4"}}})); - QCOMPARE(spy.count(), 1); - - QTemporaryFile file2; - if (file2.open()) { - QTextStream stream(&file2); - stream << sampleJson2; - } - - figmaLinksSource.setFilePath(file2.fileName()); - - QVERIFY(figmaLinksSource.getFigmaLinks() != nullptr); - - const FigmaLinks *links2 = figmaLinksSource.getFigmaLinks(); - - QCOMPARE(links2->getLinksMap(), (QMap { - {{"Component_1"}, {"link_1"}}, - {{"Component_2"}, {"link_3", "link_5"}}})); - QCOMPARE(spy.count(), 2); - } - - void readingAfterFigmaFileChangedTest() { - - FigmaLinksSource figmaLinksSource; - - QSignalSpy spy(&figmaLinksSource, &FigmaLinksSource::figmaLinksChanged); - - QCOMPARE(figmaLinksSource.getFigmaLinks(), nullptr); - - QTemporaryFile file; - if (file.open()) { - QTextStream stream(&file); - stream << sampleJson1; - } - - figmaLinksSource.setFilePath(file.fileName()); - - QVERIFY(figmaLinksSource.getFigmaLinks() != nullptr); - - const FigmaLinks *links = figmaLinksSource.getFigmaLinks(); - - QCOMPARE(links->getLinksMap(), (QMap { - {{"Component_1"}, {"link_1", "link_2"}}, - {{"Component_2"}, {"link_3", "link_4"}}})); - - QCOMPARE(spy.count(), 1); - - if (QFile f(file.fileName()); - f.open(QIODevice::WriteOnly | QIODevice::Truncate)) { - QTextStream stream(&f); - stream << sampleJson2; - } - - QVERIFY(spy.wait()); - QCOMPARE(spy.count(), 2); - - const FigmaLinks *links2 = figmaLinksSource.getFigmaLinks(); - - QCOMPARE(links2->getLinksMap(), (QMap { - {{"Component_1"}, {"link_1"}}, - {{"Component_2"}, {"link_3", "link_5"}}})); - - - if (QFile f(file.fileName()); - f.open(QIODevice::WriteOnly | QIODevice::Truncate)) { - QTextStream stream(&f); - stream << sampleJson1; - } - - QVERIFY(spy.wait()); - QCOMPARE(spy.count(), 3); - - const FigmaLinks *links3 = figmaLinksSource.getFigmaLinks(); - - QCOMPARE(links3->getLinksMap(), (QMap { - {{"Component_1"}, {"link_1", "link_2"}}, - {{"Component_2"}, {"link_3", "link_4"}}})); - } - - void emptyFigmaModelTest() { - FigmaDecoratorModel model; - QCOMPARE(model.rowCount(), 0); - QVERIFY(model.roleNames().contains(FigmaDecoratorModel::FigmaRole)); - QCOMPARE(model.roleNames().value( - FigmaDecoratorModel::FigmaRole), QStringLiteral("figma")); - } - - void figmaModelWithoutSourceModel() { - FigmaLinks links({ - {{"Component_1"}, {"link_1", "link_2"}}, - {{"Component_2"}, {"link_3", "link_4"}} - }); - - FigmaDecoratorModel model; - model.setFigmaLinks(&links); - - QCOMPARE(model.rowCount(), 0); - QVERIFY(model.roleNames().contains(FigmaDecoratorModel::FigmaRole)); - QCOMPARE(model.roleNames().value( - FigmaDecoratorModel::FigmaRole), QStringLiteral("figma")); - } - - void figmaModelWithIncompatibleSourceModel() { - QStringListModel stringsModel({"s1", "s2"}); - FigmaDecoratorModel model; - - QTest::ignoreMessage(QtWarningMsg, - "The source model is missing title role!"); - model.setSourceModel(&stringsModel); - - QCOMPARE(model.rowCount(), 2); - QVERIFY(model.roleNames().contains(FigmaDecoratorModel::FigmaRole)); - QCOMPARE(model.roleNames().value( - FigmaDecoratorModel::FigmaRole), QStringLiteral("figma")); - - QCOMPARE(model.data( - model.index(0, 0), - FigmaDecoratorModel::FigmaRole) - .value()->rowCount(), 0); - } - - void figmaModelWithoutLinksTest() { - TestSourceModel sourceModel; - FigmaDecoratorModel model; - - model.setSourceModel(&sourceModel); - - QCOMPARE(model.rowCount(), 1); - QCOMPARE(model.roleNames().count(), 2); - QVERIFY(model.roleNames().contains(FigmaDecoratorModel::FigmaRole)); - QCOMPARE(model.roleNames().value( - FigmaDecoratorModel::FigmaRole), QStringLiteral("figma")); - - QCOMPARE(model.data( - model.index(0, 0), - FigmaDecoratorModel::FigmaRole) - .value()->rowCount(), 0); - } - - void figmaModelTest() { - TestSourceModel sourceModel{2}; - FigmaLinks links({ - {{"title_0"}, {"link_1", "link_2"}}, - {{"title_x"}, {"link_3", "link_4"}} - }); - - FigmaDecoratorModel model; - - QSignalSpy spy(&model, &FigmaDecoratorModel::dataChanged); - - model.setSourceModel(&sourceModel); - - QCOMPARE(spy.size(), 0); - - QCOMPARE(model.rowCount(), 2); - QCOMPARE(model.roleNames().count(), 2); - QVERIFY(model.roleNames().contains(FigmaDecoratorModel::FigmaRole)); - QVERIFY(model.roleNames().contains(TestSourceModel::TitleRole)); - - QCOMPARE(model.roleNames().value( - FigmaDecoratorModel::FigmaRole), QStringLiteral("figma")); - QCOMPARE(model.roleNames().value( - TestSourceModel::TitleRole), QStringLiteral("title")); - - QCOMPARE(model.data(model.index(0, 0), - TestSourceModel::TitleRole).toString(), "title_0"); - QCOMPARE(model.data(model.index(1, 0), - TestSourceModel::TitleRole).toString(), "title_1"); - - auto figmaLinksModel1 = model.data(model.index(0, 0), FigmaDecoratorModel::FigmaRole) - .value(); - - QVERIFY(figmaLinksModel1 != nullptr); - QCOMPARE(figmaLinksModel1->rowCount(), 0); - - auto figmaLinksModel2 = model.data(model.index(1, 0), FigmaDecoratorModel::FigmaRole) - .value(); - - QVERIFY(figmaLinksModel2 != nullptr); - QCOMPARE(figmaLinksModel2->rowCount(), 0); - - QSignalSpy linksModelspy1(figmaLinksModel1, - &QAbstractItemModel::modelReset); - QSignalSpy linksModelspy2(figmaLinksModel2, - &QAbstractItemModel::modelReset); - - model.setFigmaLinks(&links); - - QCOMPARE(spy.size(), 0); - - QCOMPARE(linksModelspy1.size(), 1); - QCOMPARE(linksModelspy2.size(), 0); - - QCOMPARE(model.data(model.index(0, 0), FigmaDecoratorModel::FigmaRole) - .value(), figmaLinksModel1); - QCOMPARE(model.data(model.index(1, 0), FigmaDecoratorModel::FigmaRole) - .value(), figmaLinksModel2); - - QCOMPARE(figmaLinksModel1->rowCount(), 2); - QCOMPARE(figmaLinksModel2->rowCount(), 0); - - QCOMPARE(model.data(model.index(0, 0), - TestSourceModel::TitleRole).toString(), "title_0"); - QCOMPARE(model.data(model.index(1, 0), - TestSourceModel::TitleRole).toString(), "title_1"); - - QCOMPARE(figmaLinksModel1->roleNames().size(), 1); - QCOMPARE(figmaLinksModel2->roleNames().size(), 1); - - QCOMPARE(figmaLinksModel1->data(figmaLinksModel1->index(0, 0), - FigmaLinksModel::LinkRole).toString(), "link_1"); - QCOMPARE(figmaLinksModel1->data(figmaLinksModel1->index(1, 0), - FigmaLinksModel::LinkRole).toString(), "link_2"); - - model.setFigmaLinks(nullptr); - - QCOMPARE(spy.size(), 0); - QCOMPARE(linksModelspy1.size(), 2); - QCOMPARE(linksModelspy2.size(), 0); - - QCOMPARE(model.data(model.index(0, 0), FigmaDecoratorModel::FigmaRole) - .value(), figmaLinksModel1); - QCOMPARE(model.data(model.index(1, 0), FigmaDecoratorModel::FigmaRole) - .value(), figmaLinksModel2); - - QCOMPARE(figmaLinksModel1->rowCount(), 0); - QCOMPARE(figmaLinksModel2->rowCount(), 0); - } -}; - -QTEST_MAIN(FigmaDecoratorModelTest) -#include "tst_FigmaDecoratorModel.moc"