From 3604bde01ab4ebcf8c686855302aee9713804470 Mon Sep 17 00:00:00 2001 From: Ali Kianian Date: Mon, 27 Nov 2023 23:50:53 +0200 Subject: QmlDesigner: Add DataStore Dynamically to the project Task-number: QDS-11400 Change-Id: I0ad20a6aad604aa66d4d0f24ca32a19fb9e94a08 Reviewed-by: Mahmoud Badri (cherry picked from commit 4129c7703b0f51ea523b8dda72dc384e4a3cbcf7) Reviewed-by: Qt CI Patch Build Bot Reviewed-by: Thomas Hartmann --- .../collectioneditor/collectioneditorutils.cpp | 144 +++++++++++++++++++-- .../collectioneditor/collectioneditorutils.h | 10 ++ .../components/collectioneditor/collectionview.cpp | 5 + .../components/collectioneditor/collectionview.h | 1 + .../collectioneditor/collectionwidget.cpp | 16 ++- .../components/collectioneditor/collectionwidget.h | 2 + .../collectioneditor/datastoremodelnode.cpp | 22 +--- 7 files changed, 166 insertions(+), 34 deletions(-) diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.cpp index 6e0328e008..4eeca52964 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.cpp @@ -11,6 +11,7 @@ #include +#include #include #include @@ -66,6 +67,43 @@ struct LessThanVisitor } }; +Utils::FilePath findFile(const Utils::FilePath &path, const QString &fileName) +{ + QDirIterator it(path.toString(), QDirIterator::Subdirectories); + + while (it.hasNext()) { + QFileInfo file(it.next()); + if (file.isDir()) + continue; + + if (file.fileName() == fileName) + return Utils::FilePath::fromFileInfo(file); + } + return {}; +} + +Utils::FilePath dataStoreDir() +{ + using Utils::FilePath; + ProjectExplorer::Project *currentProject = ProjectExplorer::ProjectManager::startupProject(); + + if (!currentProject) + return {}; + + return currentProject->projectDirectory().pathAppended("/imports/" + + currentProject->displayName()); +} + +inline Utils::FilePath collectionPath(const QString &filePath) +{ + return dataStoreDir().pathAppended("/" + filePath); +} + +inline Utils::FilePath qmlDirFilePath() +{ + return collectionPath("qmldir"); +} + } // namespace namespace QmlDesigner::CollectionEditor { @@ -126,6 +164,16 @@ void assignCollectionToNode(AbstractView *view, }); } +Utils::FilePath dataStoreJsonFilePath() +{ + return collectionPath("models.json"); +} + +Utils::FilePath dataStoreQmlFilePath() +{ + return collectionPath("DataStore.qml"); +} + bool canAcceptCollectionAsModel(const ModelNode &node) { const NodeMetaInfo nodeMetaInfo = node.metaInfo(); @@ -143,13 +191,10 @@ bool canAcceptCollectionAsModel(const ModelNode &node) QString getSourceCollectionPath(const ModelNode &dataStoreNode) { using Utils::FilePath; - ProjectExplorer::Project *currentProject = ProjectExplorer::ProjectManager::startupProject(); - - if (!currentProject || !dataStoreNode.isValid()) + if (!dataStoreNode.isValid()) return {}; - const FilePath expectedFile = currentProject->projectDirectory().pathAppended( - "/imports/" + currentProject->displayName() + "/DataStore.json"); + const FilePath expectedFile = dataStoreJsonFilePath(); if (expectedFile.exists()) return expectedFile.toFSPathString(); @@ -160,13 +205,14 @@ QString getSourceCollectionPath(const ModelNode &dataStoreNode) bool isDataStoreNode(const ModelNode &dataStoreNode) { using Utils::FilePath; - ProjectExplorer::Project *currentProject = ProjectExplorer::ProjectManager::startupProject(); - if (!currentProject || !dataStoreNode.isValid()) + if (!dataStoreNode.isValid()) return false; - const FilePath expectedFile = currentProject->projectDirectory().pathAppended( - "/imports/" + currentProject->displayName() + "/DataStore.qml"); + const FilePath expectedFile = dataStoreQmlFilePath(); + + if (!expectedFile.exists()) + return false; FilePath modelPath = FilePath::fromUserInput(dataStoreNode.model()->fileUrl().toLocalFile()); @@ -183,4 +229,84 @@ QJsonArray defaultCollectionArray() return initialCollection; } +bool ensureDataStoreExists(bool &justCreated) +{ + using Utils::FilePath; + using Utils::FileReader; + using Utils::FileSaver; + + FilePath qmlDestinationPath = dataStoreQmlFilePath(); + justCreated = false; + + auto extractDependency = [&justCreated](const FilePath &filePath) -> bool { + if (filePath.exists()) + return true; + + const QString templateFileName = filePath.fileName() + u".tpl"; + const FilePath templatePath = findFile(Core::ICore::resourcePath(), templateFileName); + if (!templatePath.exists()) { + qWarning() << Q_FUNC_INFO << __LINE__ << templateFileName << "does not exist"; + return false; + } + + templatePath.copyFile(filePath); + if (filePath.exists()) { + justCreated = true; + return true; + } + + qWarning() << Q_FUNC_INFO << __LINE__ << "Cannot copy" << templateFileName << "to" << filePath; + return false; + }; + + if (!extractDependency(dataStoreJsonFilePath())) + return false; + + if (!extractDependency(collectionPath("data.json"))) + return false; + + if (!extractDependency(collectionPath("JsonData.qml"))) + return false; + + if (!qmlDestinationPath.exists()) { + if (qmlDestinationPath.ensureExistingFile()) { + justCreated = true; + } else { + qWarning() << Q_FUNC_INFO << __LINE__ << "Can't create DataStore Qml File"; + return false; + } + } + + FilePath qmlDirPath = qmlDirFilePath(); + qmlDirPath.ensureExistingFile(); + + FileReader qmlDirReader; + if (!qmlDirReader.fetch(qmlDirPath)) { + qWarning() << Q_FUNC_INFO << __LINE__ << "Can't read the content of the qmldir"; + return false; + } + + QByteArray qmlDirContent = qmlDirReader.data(); + const QList qmlDirLines = qmlDirContent.split('\n'); + for (const QByteArray &line : qmlDirLines) { + if (line.startsWith("singleton DataStore ")) + return true; + } + + if (!qmlDirContent.isEmpty() && qmlDirContent.back() != '\n') + qmlDirContent.append("\n"); + qmlDirContent.append("singleton DataStore 1.0 DataStore.qml\n"); + + FileSaver qmlDirSaver(qmlDirPath); + qmlDirSaver.write(qmlDirContent); + + if (qmlDirSaver.finalize()) { + justCreated = true; + return true; + } + + qWarning() << Q_FUNC_INFO << __LINE__ << "Can't write to the qmldir file"; + return false; +} + } // namespace QmlDesigner::CollectionEditor diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.h b/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.h index 8d226e7a34..835960f671 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.h +++ b/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.h @@ -10,6 +10,10 @@ QT_BEGIN_NAMESPACE class QJsonArray; QT_END_NAMESPACE +namespace Utils { +class FilePath; +} + namespace QmlDesigner::CollectionEditor { bool variantIslessThan(const QVariant &a, const QVariant &b, CollectionDetails::DataType type); @@ -25,8 +29,14 @@ void assignCollectionToNode(AbstractView *view, const ModelNode &collectionSourceNode, const QString &collectionName); +Utils::FilePath dataStoreJsonFilePath(); + +Utils::FilePath dataStoreQmlFilePath(); + bool isDataStoreNode(const ModelNode &dataStoreNode); +bool ensureDataStoreExists(bool &justCreated); + bool canAcceptCollectionAsModel(const ModelNode &node); QJsonArray defaultCollectionArray(); diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionview.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectionview.cpp index 8a470c4915..f6a24280d1 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionview.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionview.cpp @@ -211,6 +211,11 @@ void CollectionView::resetDataStoreNode() refreshModel(); } +ModelNode CollectionView::dataStoreNode() const +{ + return m_dataStore->modelNode(); +} + void CollectionView::refreshModel() { if (!model()) diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionview.h b/src/plugins/qmldesigner/components/collectioneditor/collectionview.h index bb52f82ac0..dd946776ed 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionview.h +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionview.h @@ -46,6 +46,7 @@ public: static void registerDeclarativeType(); void resetDataStoreNode(); + ModelNode dataStoreNode() const; private: void refreshModel(); diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.cpp index 94edd5da4c..30ae4418ed 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.cpp @@ -316,6 +316,7 @@ bool CollectionWidget::importCollectionToDataStore(const QString &collectionName bool CollectionWidget::addCollectionToDataStore(const QString &collectionName) { + ensureDataStoreExists(); const ModelNode node = dataStoreNode(); if (!node.isValid()) { warn(tr("Can not import to the main model"), tr("The default model node is not available.")); @@ -349,14 +350,17 @@ void CollectionWidget::assignCollectionToSelectedNode(const QString collectionNa CollectionEditor::assignCollectionToNode(m_view, targetNode, dsNode, collectionName); } +void CollectionWidget::ensureDataStoreExists() +{ + bool filesJustCreated = false; + bool filesExist = CollectionEditor::ensureDataStoreExists(filesJustCreated); + if (filesExist && filesJustCreated) + m_view->resetDataStoreNode(); +} + ModelNode CollectionWidget::dataStoreNode() const { - for (int i = 0; i < m_sourceModel->rowCount(); ++i) { - const ModelNode node = m_sourceModel->sourceNodeAt(i); - if (CollectionEditor::getSourceCollectionFormat(node) == CollectionEditor::SourceFormat::Json) - return node; - } - return {}; + return m_view->dataStoreNode(); } void CollectionWidget::warn(const QString &title, const QString &body) diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.h b/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.h index 6700bf91a4..2be98df190 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.h +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.h @@ -54,6 +54,8 @@ public: Q_INVOKABLE void assignCollectionToSelectedNode(const QString collectionName); + Q_INVOKABLE void ensureDataStoreExists(); + Q_INVOKABLE ModelNode dataStoreNode() const; void warn(const QString &title, const QString &body); diff --git a/src/plugins/qmldesigner/components/collectioneditor/datastoremodelnode.cpp b/src/plugins/qmldesigner/components/collectioneditor/datastoremodelnode.cpp index 4b2ab6edbe..446d7ef08f 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/datastoremodelnode.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/datastoremodelnode.cpp @@ -4,6 +4,7 @@ #include "datastoremodelnode.h" #include "collectioneditorconstants.h" +#include "collectioneditorutils.h" #include "model/qmltextgenerator.h" #include @@ -23,21 +24,6 @@ namespace { -Utils::FilePath findFile(const Utils::FilePath &path, const QString &fileName) -{ - QDirIterator it(path.toString(), QDirIterator::Subdirectories); - - while (it.hasNext()) { - QFileInfo file(it.next()); - if (file.isDir()) - continue; - - if (file.fileName() == fileName) - return Utils::FilePath::fromFileInfo(file); - } - return {}; -} - QmlDesigner::PropertyNameList createNameList(const QmlDesigner::ModelNode &node) { using QmlDesigner::AbstractProperty; @@ -74,10 +60,8 @@ void DataStoreModelNode::reloadModel() } bool forceUpdate = false; - const FilePath projectFilePath = ProjectExplorer::ProjectManager::startupProject()->projectDirectory(); - const FilePath importsPath = FilePath::fromString(projectFilePath.path() + "/imports"); - FilePath dataStoreQmlPath = findFile(importsPath, "DataStore.qml"); - FilePath dataStoreJsonPath = findFile(importsPath, "DataStore.json"); + const FilePath dataStoreQmlPath = CollectionEditor::dataStoreQmlFilePath(); + const FilePath dataStoreJsonPath = CollectionEditor::dataStoreJsonFilePath(); QUrl dataStoreQmlUrl = dataStoreQmlPath.toUrl(); if (dataStoreQmlPath.exists() && dataStoreJsonPath.exists()) { -- cgit v1.2.3