From f006cfb233f03c85f32530ec287d3608764d2666 Mon Sep 17 00:00:00 2001 From: Ali Kianian Date: Thu, 11 Apr 2024 12:59:18 +0300 Subject: [PATCH] QmlDesigner: Warn the user if the project is not imported When the project is not importd in the design document, DataStore cannot be found by the project manager. User should add it to make the Model Editor work. So we will warn the user in the Model Editor view. Task-number: QDS-12119 Change-Id: I313e5553e8b0a0ef3b97c50d61db80c0a8d382f8 Reviewed-by: Qt CI Patch Build Bot Reviewed-by: Thomas Hartmann --- .../CollectionDetailsView.qml | 30 +++++- .../collectioneditor/collectionview.cpp | 101 ++++++++++-------- .../collectioneditor/collectionview.h | 8 +- .../collectioneditor/collectionwidget.cpp | 23 ++++ .../collectioneditor/collectionwidget.h | 11 +- 5 files changed, 123 insertions(+), 50 deletions(-) diff --git a/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionDetailsView.qml b/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionDetailsView.qml index e3f1a589595..e40a3c94577 100644 --- a/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionDetailsView.qml +++ b/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionDetailsView.qml @@ -498,10 +498,38 @@ Rectangle { } } + ColumnLayout { + id: importsProblem + + visible: !topRow.visible && rootView.dataStoreExists && !rootView.projectImportExists + width: parent.width + anchors.verticalCenter: parent.verticalCenter + clip: true + + Text { + text: qsTr("Import the project to your design document to make the Model Editor enabled.") + Layout.alignment: Qt.AlignCenter + Layout.maximumWidth: parent.width + leftPadding: StudioTheme.Values.collectionItemTextPadding + rightPadding: StudioTheme.Values.collectionItemTextPadding + color: StudioTheme.Values.themeTextColor + font.pixelSize: StudioTheme.Values.mediumFontSize + wrapMode: Text.Wrap + } + + HelperWidgets.Button { + text: qsTr("Enable DataStore (This will add the required import)") + Layout.alignment: Qt.AlignCenter + onClicked: rootView.addProjectImport() + leftPadding: StudioTheme.Values.collectionItemTextPadding + rightPadding: StudioTheme.Values.collectionItemTextPadding + } + } + Text { anchors.centerIn: parent text: qsTr("There are no models in this project.\nAdd or import a model.") - visible: !topRow.visible + visible: !topRow.visible && !importsProblem.visible color: StudioTheme.Values.themeTextColor font.pixelSize: StudioTheme.Values.mediumFontSize } diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionview.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectionview.cpp index b47fb6a51fe..0c9a2eed94d 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionview.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionview.cpp @@ -35,6 +35,12 @@ bool isStudioCollectionModel(const QmlDesigner::ModelNode &node) return node.metaInfo().isQtQuickStudioUtilsJsonListModel(); } +inline bool isProjectImport(const QmlDesigner::Import &import) +{ + ProjectExplorer::Project *currentProject = ProjectExplorer::ProjectManager::startupProject(); + return currentProject && import.toString() == currentProject->displayName(); +} + inline void setVariantPropertyValue(const QmlDesigner::ModelNode &node, const QmlDesigner::PropertyName &propertyName, const QVariant &value) @@ -98,7 +104,7 @@ QmlDesigner::WidgetInfo CollectionView::widgetInfo() connect(listModel, &CollectionListModel::modelReset, this, [this] { CollectionListModel *listModel = m_widget->listModel().data(); - if (listModel->sourceNode() == m_dataStore->modelNode()) + if (listModel->sourceNode() == dataStoreNode()) m_dataStore->setCollectionNames(listModel->collections()); }); @@ -140,19 +146,14 @@ QmlDesigner::WidgetInfo CollectionView::widgetInfo() void CollectionView::modelAttached(Model *model) { AbstractView::modelAttached(model); + m_widget->setProjectImportExists(Utils::anyOf(model->imports(), isProjectImport)); resetDataStoreNode(); } void CollectionView::modelAboutToBeDetached([[maybe_unused]] Model *model) { - m_libraryInfoIsUpdated = false; - m_reloadCounter = 0; - m_rewriterAmended = false; - m_dataStoreTypeFound = false; - disconnect(m_documentUpdateConnection); - QTC_ASSERT(m_delayedTasks.isEmpty(), m_delayedTasks.clear()); - if (m_widget) - m_widget->listModel()->setDataStoreNode(); + unloadDataStore(); + m_widget->setProjectImportExists(false); } void CollectionView::selectedNodesChanged(const QList &selectedNodeList, @@ -177,6 +178,17 @@ void CollectionView::selectedNodesChanged(const QList &selectedNodeLi m_widget->setTargetNodeSelected(singleSelectedHasModelProperty); } +void CollectionView::importsChanged(const Imports &addedImports, const Imports &removedImports) +{ + if (Utils::anyOf(addedImports, isProjectImport)) { + m_widget->setProjectImportExists(true); + resetDataStoreNode(); + } else if (Utils::anyOf(removedImports, isProjectImport)) { + m_widget->setProjectImportExists(false); + unloadDataStore(); + } +} + void CollectionView::customNotification(const AbstractView *, const QString &identifier, const QList &nodeList, @@ -223,6 +235,22 @@ void CollectionView::addResource(const QUrl &url, const QString &name) }); } +void CollectionView::addProjectImport() +{ + if (!m_widget) + return; + + ProjectExplorer::Project *currentProject = ProjectExplorer::ProjectManager::startupProject(); + if (!currentProject) + return; + + executeInTransaction(__FUNCTION__, [&] { + Import import = Import::createLibraryImport(currentProject->displayName()); + if (!model()->hasImport(import, true, true)) + model()->changeImports({import}, {}); + }); +} + void CollectionView::assignCollectionToNode(const QString &collectionName, const ModelNode &node) { if (!m_widget) @@ -314,7 +342,8 @@ void CollectionView::resetDataStoreNode() m_dataStore->reloadModel(); - ModelNode dataStore = m_dataStore->modelNode(); + ModelNode dataStore = dataStoreNode(); + m_widget->setDataStoreExists(dataStore.isValid()); if (!dataStore || m_widget->listModel()->sourceNode() == dataStore) return; @@ -355,28 +384,11 @@ void CollectionView::ensureDataStoreExists() { bool filesJustCreated = false; bool filesExist = CollectionEditorUtils::ensureDataStoreExists(filesJustCreated); - if (filesExist) { - if (filesJustCreated) { - // Force code model reset to notice changes to existing module - auto modelManager = QmlJS::ModelManagerInterface::instance(); - if (modelManager) { - m_libraryInfoIsUpdated = false; - - m_expectedDocumentUpdates.clear(); - m_expectedDocumentUpdates << CollectionEditorUtils::dataStoreQmlFilePath() - << CollectionEditorUtils::dataStoreJsonFilePath(); - - m_documentUpdateConnection = connect(modelManager, - &QmlJS::ModelManagerInterface::documentUpdated, - this, - &CollectionView::onDocumentUpdated); - - modelManager->resetCodeModel(); - } - resetDataStoreNode(); - } else { - m_libraryInfoIsUpdated = true; - } + if (filesExist && filesJustCreated) { + // Force code model reset to notice changes to existing module + if (auto modelManager = QmlJS::ModelManagerInterface::instance()) + modelManager->resetCodeModel(); + resetDataStoreNode(); } } @@ -396,6 +408,18 @@ NodeMetaInfo CollectionView::jsonCollectionMetaInfo() const return model()->metaInfo(CollectionEditorConstants::JSONCOLLECTIONMODEL_TYPENAME); } +void CollectionView::unloadDataStore() +{ + m_reloadCounter = 0; + m_rewriterAmended = false; + m_dataStoreTypeFound = false; + QTC_ASSERT(m_delayedTasks.isEmpty(), m_delayedTasks.clear()); + if (m_widget) { + m_widget->setDataStoreExists(dataStoreNode().isValid()); + m_widget->listModel()->setDataStoreNode(); + } +} + void CollectionView::ensureStudioModelImport() { executeInTransaction(__FUNCTION__, [&] { @@ -420,23 +444,12 @@ void CollectionView::onItemLibraryNodeCreated(const ModelNode &node) } } -void CollectionView::onDocumentUpdated(const QSharedPointer &doc) -{ - if (m_expectedDocumentUpdates.contains(doc->fileName())) - m_expectedDocumentUpdates.remove(doc->fileName()); - - if (m_expectedDocumentUpdates.isEmpty()) { - disconnect(m_documentUpdateConnection); - m_libraryInfoIsUpdated = true; - } -} - void CollectionView::addTask(QSharedPointer task) { ensureDataStoreExists(); if (m_dataStoreTypeFound) task->process(); - else if (m_dataStore->modelNode()) + else if (dataStoreNode()) m_delayedTasks << task; } diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionview.h b/src/plugins/qmldesigner/components/collectioneditor/collectionview.h index d8be8b7055c..3de3bd7ae6d 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionview.h +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionview.h @@ -41,6 +41,8 @@ public: void selectedNodesChanged(const QList &selectedNodeList, const QList &lastSelectedNodeList) override; + void importsChanged(const Imports &addedImports, const Imports &removedImports) override; + void customNotification(const AbstractView *view, const QString &identifier, const QList &nodeList, @@ -48,6 +50,7 @@ public: void addResource(const QUrl &url, const QString &name); + void addProjectImport(); void assignCollectionToNode(const QString &collectionName, const ModelNode &node); void assignCollectionToSelectedNode(const QString &collectionName); void addNewCollection(const QString &collectionName, const QJsonObject &localCollection); @@ -65,17 +68,14 @@ private: friend class CollectionTask; NodeMetaInfo jsonCollectionMetaInfo() const; + void unloadDataStore(); void ensureStudioModelImport(); void onItemLibraryNodeCreated(const ModelNode &node); - void onDocumentUpdated(const QSharedPointer &doc); void addTask(QSharedPointer task); std::unique_ptr m_dataStore; Utils::UniqueObjectPtr m_widget; - QSet m_expectedDocumentUpdates; QList> m_delayedTasks; - QMetaObject::Connection m_documentUpdateConnection; - bool m_libraryInfoIsUpdated = false; bool m_dataStoreTypeFound = false; bool m_rewriterAmended = false; int m_reloadCounter = 0; diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.cpp index 7ecd54174aa..dd706145cf2 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.cpp @@ -251,6 +251,11 @@ bool CollectionWidget::importFile(const QString &collectionName, return false; } +void CollectionWidget::addProjectImport() +{ + m_view->addProjectImport(); +} + void CollectionWidget::addCollectionToDataStore(const QString &collectionName) { m_view->addNewCollection(collectionName, CollectionEditorUtils::defaultCollection()); @@ -289,6 +294,24 @@ void CollectionWidget::setTargetNodeSelected(bool selected) emit targetNodeSelectedChanged(m_targetNodeSelected); } +void CollectionWidget::setProjectImportExists(bool exists) +{ + if (m_projectImportExists == exists) + return; + + m_projectImportExists = exists; + emit projectImportExistsChanged(m_projectImportExists); +} + +void CollectionWidget::setDataStoreExists(bool exists) +{ + if (m_dataStoreExists == exists) + return; + + m_dataStoreExists = exists; + emit dataStoreExistsChanged(m_dataStoreExists); +} + void CollectionWidget::deleteSelectedCollection() { QMetaObject::invokeMethod(m_quickWidget->quickWidget()->rootObject(), "deleteSelectedCollection"); diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.h b/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.h index f06edd23231..13c3566c78e 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.h +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.h @@ -22,6 +22,8 @@ class CollectionWidget : public QFrame Q_OBJECT Q_PROPERTY(bool targetNodeSelected MEMBER m_targetNodeSelected NOTIFY targetNodeSelectedChanged) + Q_PROPERTY(bool projectImportExists MEMBER m_projectImportExists NOTIFY projectImportExistsChanged) + Q_PROPERTY(bool dataStoreExists MEMBER m_dataStoreExists NOTIFY dataStoreExistsChanged) public: CollectionWidget(CollectionView *view); @@ -33,7 +35,7 @@ public: void reloadQmlSource(); - virtual QSize minimumSizeHint() const; + QSize minimumSizeHint() const override; Q_INVOKABLE bool loadJsonFile(const QUrl &url, const QString &collectionName = {}); Q_INVOKABLE bool loadCsvFile(const QUrl &url, const QString &collectionName = {}); @@ -45,6 +47,7 @@ public: const QUrl &url, const bool &firstRowIsHeader = true); + Q_INVOKABLE void addProjectImport(); Q_INVOKABLE void addCollectionToDataStore(const QString &collectionName); Q_INVOKABLE void assignCollectionToSelectedNode(const QString collectionName); Q_INVOKABLE void openCollection(const QString &collectionName); @@ -52,11 +55,15 @@ public: void warn(const QString &title, const QString &body); void setTargetNodeSelected(bool selected); + void setProjectImportExists(bool exists); + void setDataStoreExists(bool exists); void deleteSelectedCollection(); signals: void targetNodeSelectedChanged(bool); + void projectImportExistsChanged(bool); + void dataStoreExistsChanged(bool); private: QString generateUniqueCollectionName(const ModelNode &node, const QString &name); @@ -67,6 +74,8 @@ private: std::unique_ptr m_collectionDetailsSortFilterModel; QScopedPointer m_quickWidget; bool m_targetNodeSelected = false; + bool m_projectImportExists = false; + bool m_dataStoreExists = false; }; } // namespace QmlDesigner