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