diff --git a/share/qtcreator/qmldesigner/designsystem/Main.qml b/share/qtcreator/qmldesigner/designsystem/Main.qml index 9695f95270a..31967e56b43 100644 --- a/share/qtcreator/qmldesigner/designsystem/Main.qml +++ b/share/qtcreator/qmldesigner/designsystem/Main.qml @@ -44,7 +44,21 @@ Rectangle { height: 400 color: StudioTheme.Values.themePanelBackground + function clearModel() { + root.currentCollectionName = "" + tableView.model = null + + topLeftCell.visible = false + createModeButton.enabled = false + modelConnections.target = null + } + function loadModel(name) { + if (name === undefined) { + clearModel() + return + } + root.currentCollectionName = name tableView.model = DesignSystemBackend.dsInterface.model(name) @@ -256,6 +270,7 @@ Rectangle { anchors.verticalCenter: parent.verticalCenter actionIndicatorVisible: false model: DesignSystemBackend.dsInterface.collections + enabled: collectionsComboBox.count onActivated: root.loadModel(collectionsComboBox.currentText) } @@ -264,7 +279,8 @@ Rectangle { style: StudioTheme.Values.viewBarControlStyle anchors.verticalCenter: parent.verticalCenter actionIndicatorVisible: false - model: tableView.model.themeNames + model: tableView.model?.themeNames ?? null + enabled: tableView.model onActivated: tableView.model.setActiveTheme(themesComboBox.currentText) } @@ -274,6 +290,7 @@ Rectangle { buttonIcon: StudioTheme.Constants.more_medium checkable: true checked: moreMenu.visible + tooltip: qsTr("More options") onToggled: { if (moreMenu.visible) @@ -307,12 +324,21 @@ Rectangle { } // TODO this is only for debugging purposes - Button { + Connections { + target: DesignSystemBackend.dsInterface + function onCollectionsChanged() { + root.loadModel(DesignSystemBackend.dsInterface.collections[0]) + } + } + + StudioControls.IconTextButton { + id: refreshButton anchors.verticalCenter: parent.verticalCenter - text: qsTr("load") + buttonIcon: StudioTheme.Constants.updateContent_medium + tooltip: qsTr("Refresh") onClicked: { DesignSystemBackend.dsInterface.loadDesignSystem() - root.loadModel(DesignSystemBackend.dsInterface.collections[0]) + //root.loadModel(DesignSystemBackend.dsInterface.collections[0]) } } } diff --git a/src/plugins/qmldesigner/components/designsystemview/collectionmodel.cpp b/src/plugins/qmldesigner/components/designsystemview/collectionmodel.cpp index 08caa829935..227ce1902ec 100644 --- a/src/plugins/qmldesigner/components/designsystemview/collectionmodel.cpp +++ b/src/plugins/qmldesigner/components/designsystemview/collectionmodel.cpp @@ -10,10 +10,14 @@ namespace QmlDesigner { -CollectionModel::CollectionModel(DSThemeManager *collection, const DSStore *store) +CollectionModel::CollectionModel(DSThemeManager *collection, DSStore *store) : m_collection(collection) , m_store(store) { + m_saveCompressionTimer.setSingleShot(true); + m_saveCompressionTimer.setInterval(200); + connect(&m_saveCompressionTimer, &QTimer::timeout, this, &CollectionModel::save); + updateCache(); } @@ -28,8 +32,10 @@ QStringList CollectionModel::themeNameList() const void CollectionModel::setActiveTheme(const QString &themeName) { - if (const auto themeId = m_collection->themeId(themeName.toLatin1())) + if (const auto themeId = m_collection->themeId(themeName.toLatin1())) { m_collection->setActiveTheme(*themeId); + aboutToSave(); + } } int CollectionModel::columnCount(const QModelIndex &parent) const @@ -149,6 +155,7 @@ bool CollectionModel::insertColumns([[maybe_unused]] int column, int count, cons beginResetModel(); updateCache(); endResetModel(); + aboutToSave(); emit themeNameChanged(); } return true; @@ -166,6 +173,7 @@ bool CollectionModel::removeColumns(int column, int count, const QModelIndex &pa updateCache(); endResetModel(); + aboutToSave(); emit themeNameChanged(); return true; } @@ -183,6 +191,7 @@ bool CollectionModel::removeRows(int row, int count, const QModelIndex &parent) } updateCache(); endResetModel(); + aboutToSave(); return true; } @@ -207,6 +216,8 @@ void CollectionModel::addProperty(GroupType group, const QString &name, const QV beginResetModel(); updateCache(); endResetModel(); + + aboutToSave(); } } @@ -227,6 +238,9 @@ bool CollectionModel::setData(const QModelIndex &index, const QVariant &value, i default: break; } + + aboutToSave(); + return false; } @@ -261,6 +275,8 @@ bool CollectionModel::setHeaderData(int section, beginResetModel(); updateCache(); endResetModel(); + + aboutToSave(); } return success; @@ -277,4 +293,16 @@ std::optional CollectionModel::findPropertyName(int row) const QTC_ASSERT(row > -1 && row < static_cast(m_propertyInfoList.size()), return {}); return m_propertyInfoList[row]; } + +void CollectionModel::save() +{ + QTC_ASSERT(m_store, return); + m_store->save(); +} + +void CollectionModel::aboutToSave() +{ + m_saveCompressionTimer.start(); +} + } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/designsystemview/collectionmodel.h b/src/plugins/qmldesigner/components/designsystemview/collectionmodel.h index 118f55ce152..a7b0f8a3f9b 100644 --- a/src/plugins/qmldesigner/components/designsystemview/collectionmodel.h +++ b/src/plugins/qmldesigner/components/designsystemview/collectionmodel.h @@ -5,6 +5,7 @@ #include #include +#include #include @@ -29,7 +30,7 @@ public: Q_PROPERTY(QStringList themeNames READ themeNameList NOTIFY themeNameChanged FINAL) - CollectionModel(DSThemeManager *collection, const DSStore *store); + CollectionModel(DSThemeManager *collection, DSStore *store); QStringList themeNameList() const; Q_INVOKABLE void setActiveTheme(const QString &themeName); @@ -72,12 +73,17 @@ private: ThemeId findThemeId(int column) const; std::optional findPropertyName(int row) const; + void save(); + void aboutToSave(); + private: DSThemeManager *m_collection = nullptr; - const DSStore *m_store; + DSStore *m_store; // cache std::vector m_themeIdList; std::vector m_propertyInfoList; + + QTimer m_saveCompressionTimer; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/designsystemview/designsysteminterface.cpp b/src/plugins/qmldesigner/components/designsystemview/designsysteminterface.cpp index 6a7d2695cb8..0634a5f19cc 100644 --- a/src/plugins/qmldesigner/components/designsystemview/designsysteminterface.cpp +++ b/src/plugins/qmldesigner/components/designsystemview/designsysteminterface.cpp @@ -22,7 +22,10 @@ DesignSystemInterface::~DesignSystemInterface() {} void DesignSystemInterface::loadDesignSystem() { m_models.clear(); - m_store->load(); + + if (auto err = m_store->load()) + qDebug() << err; + emit collectionsChanged(); } diff --git a/src/plugins/qmldesigner/components/designsystemview/designsystemview.cpp b/src/plugins/qmldesigner/components/designsystemview/designsystemview.cpp index dfa5267c561..77532f284f2 100644 --- a/src/plugins/qmldesigner/components/designsystemview/designsystemview.cpp +++ b/src/plugins/qmldesigner/components/designsystemview/designsystemview.cpp @@ -6,7 +6,13 @@ #include "designsystemwidget.h" #include "dsstore.h" +#include + #include +#include + +#include +#include #include #include @@ -21,7 +27,21 @@ DesignSystemView::DesignSystemView(ExternalDependenciesInterface &externalDepend , m_externalDependencies(externalDependencies) , m_dsStore(std::make_unique(m_externalDependencies, projectStorageDependencies)) , m_dsInterface(m_dsStore.get()) -{} +{ + connect(ProjectExplorer::ProjectManager::instance(), + &ProjectExplorer::ProjectManager::startupProjectChanged, + this, + [this](ProjectExplorer::Project *) { loadDesignSystem(); }); + + connect(Core::EditorManager::instance(), + &Core::EditorManager::saved, + this, + [this](Core::IDocument *document) { + if (document->filePath().contains("Generated/DesignSystem")) { + loadDesignSystem(); + } + }); +} DesignSystemView::~DesignSystemView() {} @@ -33,7 +53,9 @@ WidgetInfo DesignSystemView::widgetInfo() return createWidgetInfo(m_designSystemWidget, "DesignSystemView", WidgetInfo::RightPane, - tr("Design System")); + Tr::tr("Design System"), + Tr::tr("Design System view"), + DesignerWidgetFlags::IgnoreErrors); } bool DesignSystemView::hasWidget() const @@ -43,8 +65,10 @@ bool DesignSystemView::hasWidget() const void DesignSystemView::loadDesignSystem() { - if (auto err = m_dsStore->load()) - qDebug() << *err; + /*This is only used to load internally - when saving we have to take care of reflection. + * Saving should not trigger a load again. + */ + m_dsInterface.loadDesignSystem(); } } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/libs/designsystem/dsstore.cpp b/src/plugins/qmldesigner/libs/designsystem/dsstore.cpp index 93cc29f1ffc..fafff6ea61f 100644 --- a/src/plugins/qmldesigner/libs/designsystem/dsstore.cpp +++ b/src/plugins/qmldesigner/libs/designsystem/dsstore.cpp @@ -16,6 +16,7 @@ #include #include +#include namespace { @@ -113,14 +114,17 @@ std::optional DSStore::load() std::optional DSStore::load(const Utils::FilePath &dsModuleDirPath) { + if (m_blockLoading) + return {}; + + m_collections.clear(); + // read qmldir const auto qmldirFile = dsModuleDirPath / "qmldir"; const Utils::expected_str contents = qmldirFile.fileContents(); if (!contents) return tr("Can not read Design System qmldir"); - m_collections.clear(); - // Parse qmldir QString qmldirData = QString::fromUtf8(*contents); QmlDirParser qmlDirParser; @@ -160,6 +164,9 @@ std::optional DSStore::save(const Utils::FilePath &moduleDirPath, bool if (!QDir().mkpath(moduleDirPath.absoluteFilePath().toString())) return tr("Can not create design system module directory %1.").arg(moduleDirPath.toString()); + const QScopeGuard cleanup([&] { m_blockLoading = false; }); + m_blockLoading = true; + // dump collections QStringList singletons; QStringList errors; diff --git a/src/plugins/qmldesigner/libs/designsystem/dsstore.h b/src/plugins/qmldesigner/libs/designsystem/dsstore.h index f51794edcf8..2ad120aa6ea 100644 --- a/src/plugins/qmldesigner/libs/designsystem/dsstore.h +++ b/src/plugins/qmldesigner/libs/designsystem/dsstore.h @@ -52,5 +52,6 @@ private: ExternalDependenciesInterface &m_ed; ProjectStorageDependencies m_projectStorageDependencies; DSCollections m_collections; + bool m_blockLoading = false; }; } // namespace QmlDesigner