diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.cpp index 2ca2d3e8004..ab2278fb726 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.cpp @@ -407,16 +407,14 @@ void CollectionDetailsModel::renameCollection(const ModelNode &sourceNode, bool CollectionDetailsModel::saveDataStoreCollections() { const ModelNode node = m_currentCollection.reference().node; - const Utils::FilePath path = CollectionEditorUtils::dataStoreJsonFilePath(); - Utils::FileReader fileData; - - if (!fileData.fetch(path)) { - qWarning() << Q_FUNC_INFO << "Cannot read the json file:" << fileData.errorString(); + Utils::expected_str jsonContents = m_jsonFilePath.fileContents(); + if (!jsonContents.has_value()) { + qWarning() << __FUNCTION__ << jsonContents.error(); return false; } QJsonParseError jpe; - QJsonDocument document = QJsonDocument::fromJson(fileData.data(), &jpe); + QJsonDocument document = QJsonDocument::fromJson(jsonContents.value(), &jpe); if (jpe.error == QJsonParseError::NoError) { QJsonObject obj = document.object(); @@ -432,7 +430,7 @@ bool CollectionDetailsModel::saveDataStoreCollections() document.setObject(obj); - if (CollectionEditorUtils::writeToJsonDocument(path, document)) { + if (CollectionEditorUtils::writeToJsonDocument(m_jsonFilePath, document)) { const CollectionReference currentReference = m_currentCollection.reference(); for (CollectionDetails &collection : collectionsToBeSaved) { collection.markSaved(); @@ -618,6 +616,11 @@ QString CollectionDetailsModel::warningToString(DataTypeWarning::Warning warning return DataTypeWarning::getDataTypeWarningString(warning); } +void CollectionDetailsModel::setJsonFilePath(const Utils::FilePath &filePath) +{ + m_jsonFilePath = filePath; +} + void CollectionDetailsModel::setHasUnsavedChanges(bool val) { if (m_hasUnsavedChanges == val) diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.h b/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.h index 8844ff4a3ef..fbe90a6f567 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.h +++ b/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.h @@ -5,6 +5,8 @@ #include "collectiondetails.h" +#include + #include #include @@ -60,6 +62,7 @@ public: Q_INVOKABLE void deselectAll(); Q_INVOKABLE QString warningToString(DataTypeWarning::Warning warning) const; + void setJsonFilePath(const Utils::FilePath &filePath); void loadCollection(const ModelNode &sourceNode, const QString &collection); void removeCollection(const ModelNode &sourceNode, const QString &collection); void removeAllCollections(); @@ -93,6 +96,7 @@ private: void ensureSingleCell(); QJsonDocument readJsonFile(const QUrl &url); + Utils::FilePath m_jsonFilePath; QHash m_openedCollections; CollectionDetails m_currentCollection; bool m_isEmpty = true; diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectioneditorconstants.h b/src/plugins/qmldesigner/components/collectioneditor/collectioneditorconstants.h index 76524762ede..2228c58518c 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectioneditorconstants.h +++ b/src/plugins/qmldesigner/components/collectioneditor/collectioneditorconstants.h @@ -16,4 +16,9 @@ inline constexpr char JSONCOLLECTIONMODEL_TYPENAME[] = "QtQuick.Studio.Ut inline constexpr char JSONCOLLECTIONCHILDMODEL_TYPENAME[] = "QtQuick.Studio.Utils.ChildListModel"; inline constexpr char JSONBACKEND_TYPENAME[] = "JsonData"; +inline constexpr QStringView DEFAULT_DATA_JSON_FILENAME = u"data.json"; +inline constexpr QStringView DEFAULT_MODELS_JSON_FILENAME = u"models.json"; +inline constexpr QStringView DEFAULT_DATASTORE_QML_FILENAME = u"DataStore.qml"; +inline constexpr QStringView DEFAULT_JSONDATA_QML_FILENAME = u"JsonData.qml"; + } // namespace QmlDesigner::CollectionEditorConstants diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.cpp index 40350802d26..a991e2d729c 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.cpp @@ -4,9 +4,11 @@ #include "collectioneditorutils.h" #include "collectiondatatypemodel.h" +#include "collectioneditorconstants.h" #include "model.h" #include "nodemetainfo.h" #include "propertymetainfo.h" +#include "variantproperty.h" #include #include @@ -73,47 +75,6 @@ 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 {}; - - FilePath oldImportDirectory = currentProject->projectDirectory().pathAppended( - "imports/" + currentProject->displayName()); - if (oldImportDirectory.exists()) - return oldImportDirectory; - - return currentProject->projectDirectory().pathAppended(currentProject->displayName()); -} - -inline Utils::FilePath collectionPath(const QString &filePath) -{ - return dataStoreDir().pathAppended(filePath); -} - -inline Utils::FilePath qmlDirFilePath() -{ - return collectionPath("qmldir"); -} - } // namespace namespace QmlDesigner::CollectionEditorUtils { @@ -123,25 +84,6 @@ bool variantIslessThan(const QVariant &a, const QVariant &b, DataType type) return std::visit(LessThanVisitor{}, valueToVariant(a, type), valueToVariant(b, type)); } -QString getSourceCollectionType(const ModelNode &node) -{ - using namespace QmlDesigner; - if (node.type() == CollectionEditorConstants::JSONCOLLECTIONMODEL_TYPENAME) - return "json"; - - return {}; -} - -Utils::FilePath dataStoreJsonFilePath() -{ - return collectionPath("models.json"); -} - -Utils::FilePath dataStoreQmlFilePath() -{ - return collectionPath("DataStore.qml"); -} - bool canAcceptCollectionAsModel(const ModelNode &node) { const NodeMetaInfo nodeMetaInfo = node.metaInfo(); @@ -176,116 +118,25 @@ QString getSourceCollectionPath(const ModelNode &dataStoreNode) if (!dataStoreNode.isValid()) return {}; - const FilePath expectedFile = dataStoreJsonFilePath(); + const QUrl dataStoreUrl = dataStoreNode.model()->fileUrl(); + QUrl sourceValue = dataStoreNode.property("source").toVariantProperty().value().toUrl(); - if (expectedFile.exists()) + QUrl sourceUrl = sourceValue.isRelative() ? dataStoreUrl.resolved(sourceValue) : sourceValue; + + const FilePath expectedFile = FilePath::fromUrl(sourceUrl); + + if (expectedFile.isFile() && expectedFile.exists()) return expectedFile.toFSPathString(); + const FilePath defaultJsonFile = FilePath::fromUrl( + dataStoreUrl.resolved(CollectionEditorConstants::DEFAULT_MODELS_JSON_FILENAME.toString())); + + if (defaultJsonFile.exists()) + return defaultJsonFile.toFSPathString(); + return {}; } -bool isDataStoreNode(const ModelNode &dataStoreNode) -{ - using Utils::FilePath; - - if (!dataStoreNode.isValid()) - return false; - - const FilePath expectedFile = dataStoreQmlFilePath(); - - if (!expectedFile.exists()) - return false; - - FilePath modelPath = FilePath::fromUserInput(dataStoreNode.model()->fileUrl().toLocalFile()); - - return modelPath.isSameFile(expectedFile); -} - -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; - } - - if (!filePath.parentDir().ensureWritableDir()) { - qWarning() << Q_FUNC_INFO << __LINE__ << "Cannot create directory" - << filePath.parentDir(); - return false; - } - - if (templatePath.copyFile(filePath)) { - 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; -} - QJsonObject defaultCollection() { QJsonObject collectionObject; @@ -337,6 +188,21 @@ QJsonObject defaultColorCollection() return collection.toLocalJson(); } +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 {}; +} + bool writeToJsonDocument(const Utils::FilePath &path, const QJsonDocument &document, QString *errorString) { Core::FileChangeBlocker fileBlocker(path); diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.h b/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.h index 355addf59be..7afc6f233fe 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.h +++ b/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.h @@ -4,7 +4,6 @@ #pragma once #include "collectiondetails.h" -#include "collectioneditorconstants.h" QT_BEGIN_NAMESPACE class QJsonArray; @@ -19,22 +18,14 @@ namespace QmlDesigner::CollectionEditorUtils { bool variantIslessThan(const QVariant &a, const QVariant &b, CollectionDetails::DataType type); -QString getSourceCollectionType(const QmlDesigner::ModelNode &node); - QString getSourceCollectionPath(const QmlDesigner::ModelNode &dataStoreNode); -Utils::FilePath dataStoreJsonFilePath(); - -Utils::FilePath dataStoreQmlFilePath(); +Utils::FilePath findFile(const Utils::FilePath &path, const QString &fileName); bool writeToJsonDocument(const Utils::FilePath &path, const QJsonDocument &document, QString *errorString = nullptr); -bool isDataStoreNode(const ModelNode &dataStoreNode); - -bool ensureDataStoreExists(bool &justCreated); - bool canAcceptCollectionAsModel(const ModelNode &node); bool hasTextRoleProperty(const ModelNode &node); diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionlistmodel.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectionlistmodel.cpp index d27a077d2a7..320bc1bc043 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionlistmodel.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionlistmodel.cpp @@ -3,6 +3,7 @@ #include "collectionlistmodel.h" +#include "collectioneditorconstants.h" #include "collectioneditorutils.h" #include diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionview.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectionview.cpp index 9221919df45..f8382b19897 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionview.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionview.cpp @@ -17,6 +17,7 @@ #include "qmldesignerplugin.h" #include "variantproperty.h" +#include #include #include #include @@ -77,8 +78,7 @@ CollectionView::CollectionView(ExternalDependenciesInterface &externalDependenci : AbstractView(externalDependencies) , m_dataStore(std::make_unique()) -{ -} +{} CollectionView::~CollectionView() = default; @@ -330,7 +330,8 @@ void CollectionView::resetDataStoreNode() if (!m_widget) return; - m_dataStore->reloadModel(); + auto compUtils = QmlDesignerPlugin::instance()->documentManager().generatedComponentUtils(); + m_dataStore->reloadModel(compUtils.projectModulePath()); ModelNode dataStore = dataStoreNode(); m_widget->setDataStoreExists(dataStore.isValid()); @@ -354,6 +355,7 @@ void CollectionView::resetDataStoreNode() if (dataStoreSingletonFound) { m_widget->listModel()->setDataStoreNode(dataStore); + m_widget->collectionDetailsModel()->setJsonFilePath(m_dataStore->jsonFilePath()); m_dataStoreTypeFound = true; resetPuppet(); @@ -374,7 +376,7 @@ ModelNode CollectionView::dataStoreNode() const void CollectionView::ensureDataStoreExists() { bool filesJustCreated = false; - bool filesExist = CollectionEditorUtils::ensureDataStoreExists(filesJustCreated); + bool filesExist = createDataStore(filesJustCreated); if (filesExist && filesJustCreated) { // Force code model reset to notice changes to existing module if (auto modelManager = QmlJS::ModelManagerInterface::instance()) @@ -411,6 +413,103 @@ void CollectionView::unloadDataStore() } } +bool CollectionView::createDataStore(bool &justCreated) const +{ + using Utils::FilePath; + using Utils::FileReader; + using Utils::FileSaver; + using namespace Qt::StringLiterals; + + auto compUtils = QmlDesignerPlugin::instance()->documentManager().generatedComponentUtils(); + FilePath projectModulePath = compUtils.projectModulePath(true); + + FilePath qmlTargetPath = projectModulePath.resolvePath( + CollectionEditorConstants::DEFAULT_DATASTORE_QML_FILENAME.toString()); + justCreated = false; + + auto extractDependency = [&justCreated](const FilePath &filePath) -> bool { + if (filePath.exists()) + return true; + + const QString templateFileName = filePath.fileName() + u".tpl"; + const FilePath templatePath = CollectionEditorUtils::findFile(Core::ICore::resourcePath(), + templateFileName); + if (!templatePath.exists()) { + qWarning() << Q_FUNC_INFO << __LINE__ << templateFileName << "does not exist"; + return false; + } + + if (!filePath.parentDir().ensureWritableDir()) { + qWarning() << Q_FUNC_INFO << __LINE__ << "Cannot create directory" + << filePath.parentDir(); + return false; + } + + if (templatePath.copyFile(filePath)) { + justCreated = true; + return true; + } + + qWarning() << Q_FUNC_INFO << __LINE__ << "Cannot copy" << templateFileName << "to" << filePath; + return false; + }; + + if (!extractDependency(projectModulePath.resolvePath( + CollectionEditorConstants::DEFAULT_MODELS_JSON_FILENAME.toString()))) { + return false; + } + + if (!extractDependency(projectModulePath.resolvePath( + CollectionEditorConstants::DEFAULT_DATA_JSON_FILENAME.toString()))) { + return false; + } + + if (!extractDependency(projectModulePath.resolvePath( + CollectionEditorConstants::DEFAULT_JSONDATA_QML_FILENAME.toString()))) { + return false; + } + + if (!qmlTargetPath.exists()) { + if (qmlTargetPath.ensureExistingFile()) { + justCreated = true; + } else { + qWarning() << Q_FUNC_INFO << __LINE__ << "Can't create DataStore Qml File"; + return false; + } + } + + FilePath qmlDirPath = projectModulePath.resolvePath("qmldir"_L1); + 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; +} + void CollectionView::ensureStudioModelImport() { executeInTransaction(__FUNCTION__, [&] { diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionview.h b/src/plugins/qmldesigner/components/collectioneditor/collectionview.h index 20cb045374d..458ea6c60a5 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionview.h +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionview.h @@ -23,6 +23,7 @@ class CollectionListModel; class CollectionTask; class CollectionWidget; class DataStoreModelNode; +class GeneratedComponentUtils; class CollectionView : public AbstractView { @@ -69,6 +70,7 @@ private: NodeMetaInfo jsonCollectionMetaInfo() const; void unloadDataStore(); + bool createDataStore(bool &justCreated) const; void ensureStudioModelImport(); void onItemLibraryNodeCreated(const ModelNode &node); void addTask(QSharedPointer task); diff --git a/src/plugins/qmldesigner/components/collectioneditor/datastoremodelnode.cpp b/src/plugins/qmldesigner/components/collectioneditor/datastoremodelnode.cpp index d8b80061f32..5ffad6683c3 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/datastoremodelnode.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/datastoremodelnode.cpp @@ -21,9 +21,7 @@ #include #include -#include #include -#include #include #include @@ -114,7 +112,6 @@ void setQmlContextToModel(QmlDesigner::Model *model, const QString &qmlContext) std::unique_ptr rewriter = std::make_unique( externalDependencies, QmlDesigner::RewriterView::Validate); - rewriter->setParent(model); rewriter->setTextModifier(modifier.get()); rewriter->setCheckSemanticErrors(false); @@ -126,22 +123,21 @@ void setQmlContextToModel(QmlDesigner::Model *model, const QString &qmlContext) namespace QmlDesigner { -DataStoreModelNode::DataStoreModelNode() -{ - reloadModel(); -} +DataStoreModelNode::DataStoreModelNode() = default; -void DataStoreModelNode::reloadModel() +void DataStoreModelNode::reloadModel(const Utils::FilePath &projectModulePath) { using Utils::FilePath; - if (!ProjectExplorer::ProjectManager::startupProject()) { + if (!projectModulePath.exists()) { reset(); return; } bool forceUpdate = false; - const FilePath dataStoreQmlPath = CollectionEditorUtils::dataStoreQmlFilePath(); - const FilePath dataStoreJsonPath = CollectionEditorUtils::dataStoreJsonFilePath(); + const FilePath dataStoreQmlPath = projectModulePath.resolvePath( + CollectionEditorConstants::DEFAULT_DATASTORE_QML_FILENAME.toString()); + const FilePath dataStoreJsonPath = projectModulePath.resolvePath( + CollectionEditorConstants::DEFAULT_MODELS_JSON_FILENAME.toString()); QUrl dataStoreQmlUrl = dataStoreQmlPath.toUrl(); if (dataStoreQmlPath.exists() && dataStoreJsonPath.exists()) { @@ -196,6 +192,15 @@ ModelNode DataStoreModelNode::modelNode() const return m_model->rootModelNode(); } +Utils::FilePath DataStoreModelNode::jsonFilePath() const +{ + QUrl modelUrl = m_model->fileUrl(); + return Utils::FilePath::fromUserInput(modelUrl.isLocalFile() ? modelUrl.toLocalFile() + : modelUrl.toString()) + .parentDir() + .resolvePath(CollectionEditorConstants::DEFAULT_MODELS_JSON_FILENAME.toString()); +} + QString DataStoreModelNode::getModelQmlText() { ModelNode node = modelNode(); diff --git a/src/plugins/qmldesigner/components/collectioneditor/datastoremodelnode.h b/src/plugins/qmldesigner/components/collectioneditor/datastoremodelnode.h index 6cd969edbe6..9d438ef5f56 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/datastoremodelnode.h +++ b/src/plugins/qmldesigner/components/collectioneditor/datastoremodelnode.h @@ -24,11 +24,12 @@ public: DataStoreModelNode(); - void reloadModel(); + void reloadModel(const Utils::FilePath &projectModulePath); QStringList collectionNames() const; Model *model() const; ModelNode modelNode() const; + Utils::FilePath jsonFilePath() const; void setCollectionNames(const QStringList &newCollectionNames); void addCollection(const QString &collectionName); diff --git a/src/plugins/qmldesigner/designercore/generatedcomponentutils.cpp b/src/plugins/qmldesigner/designercore/generatedcomponentutils.cpp index 137fbd9b528..d9e4480ef53 100644 --- a/src/plugins/qmldesigner/designercore/generatedcomponentutils.cpp +++ b/src/plugins/qmldesigner/designercore/generatedcomponentutils.cpp @@ -2,11 +2,36 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "generatedcomponentutils.h" - #include namespace QmlDesigner { +bool couldBeProjectModule(const Utils::FilePath &path, const QString &projectName) +{ + if (!path.exists()) + return false; + + Utils::FilePath qmlDirPath = path.pathAppended("qmldir"); + if (qmlDirPath.exists()) { + Utils::expected_str qmldirContents = qmlDirPath.fileContents(); + if (!qmldirContents.has_value()) + return false; + + const QString expectedLine = QLatin1String("module %1").arg(projectName); + QByteArray fileContents = qmldirContents.value(); + QTextStream stream(fileContents); + while (!stream.atEnd()) { + QString lineData = stream.readLine().trimmed(); + if (lineData.startsWith(u"module ")) + return lineData == expectedLine; + } + } + if (path.endsWith(projectName)) + return true; + + return false; +} + GeneratedComponentUtils::GeneratedComponentUtils(ExternalDependenciesInterface &externalDependencies) : m_externalDependencies(externalDependencies) { @@ -106,6 +131,36 @@ Utils::FilePath GeneratedComponentUtils::effectBundlePath() const return basePath.resolvePath(QLatin1String(Constants::COMPONENT_BUNDLES_EFFECT_BUNDLE_TYPE)); } +Utils::FilePath GeneratedComponentUtils::projectModulePath(bool generateIfNotExists) const +{ + using Utils::FilePath; + FilePath projectPath = FilePath::fromString(m_externalDependencies.currentProjectDirPath()); + + if (projectPath.isEmpty()) + return {}; + + const QString projectName = m_externalDependencies.projectName(); + + FilePath newImportDirectory = projectPath.pathAppended(projectName); + if (couldBeProjectModule(newImportDirectory, projectName)) + return newImportDirectory; + + FilePath oldImportDirectory = projectPath.resolvePath(QLatin1String("imports/") + projectName); + if (couldBeProjectModule(oldImportDirectory, projectName)) + return oldImportDirectory; + + for (const QString &path : m_externalDependencies.projectModulePaths()) { + FilePath dir = FilePath::fromString(path); + if (couldBeProjectModule(dir, projectName)) + return dir; + } + + if (generateIfNotExists) + newImportDirectory.createDir(); + + return newImportDirectory; +} + bool GeneratedComponentUtils::isImport3dPath(const QString &path) const { return path.contains('/' + QLatin1String(Constants::OLD_QUICK_3D_ASSETS_FOLDER)) diff --git a/src/plugins/qmldesigner/designercore/generatedcomponentutils.h b/src/plugins/qmldesigner/designercore/generatedcomponentutils.h index 5fc51fd85f3..cc51b5f8cbc 100644 --- a/src/plugins/qmldesigner/designercore/generatedcomponentutils.h +++ b/src/plugins/qmldesigner/designercore/generatedcomponentutils.h @@ -23,6 +23,7 @@ public: Utils::FilePath import3dBasePath() const; Utils::FilePath materialBundlePath() const; Utils::FilePath effectBundlePath() const; + Utils::FilePath projectModulePath(bool generateIfNotExists = false) const; bool isImport3dPath(const QString &path) const; bool isComposedEffectPath(const QString &path) const; diff --git a/src/plugins/qmldesigner/designercore/include/externaldependenciesinterface.h b/src/plugins/qmldesigner/designercore/include/externaldependenciesinterface.h index 71ddeb7dc19..9055f51b6a1 100644 --- a/src/plugins/qmldesigner/designercore/include/externaldependenciesinterface.h +++ b/src/plugins/qmldesigner/designercore/include/externaldependenciesinterface.h @@ -28,6 +28,7 @@ public: virtual QString qmlPuppetFallbackDirectory() const = 0; virtual QString defaultPuppetToplevelBuildDirectory() const = 0; virtual QUrl projectUrl() const = 0; + virtual QString projectName() const = 0; virtual QString currentProjectDirPath() const = 0; virtual QUrl currentResourcePath() const = 0; virtual void parseItemLibraryDescriptions() = 0; diff --git a/src/plugins/qmldesigner/qmldesignerexternaldependencies.cpp b/src/plugins/qmldesigner/qmldesignerexternaldependencies.cpp index 321d95197fc..97b2b46e7d5 100644 --- a/src/plugins/qmldesigner/qmldesignerexternaldependencies.cpp +++ b/src/plugins/qmldesigner/qmldesignerexternaldependencies.cpp @@ -56,6 +56,11 @@ QUrl ExternalDependencies::projectUrl() const return {}; } +QString ExternalDependencies::projectName() const +{ + return QmlDesignerPlugin::instance()->documentManager().currentProjectName(); +} + QString ExternalDependencies::currentProjectDirPath() const { return QmlDesignerPlugin::instance()->documentManager().currentProjectDirPath().toString(); diff --git a/src/plugins/qmldesigner/qmldesignerexternaldependencies.h b/src/plugins/qmldesigner/qmldesignerexternaldependencies.h index b4908c23833..6a49e4b5516 100644 --- a/src/plugins/qmldesigner/qmldesignerexternaldependencies.h +++ b/src/plugins/qmldesigner/qmldesignerexternaldependencies.h @@ -21,6 +21,7 @@ public: QString qmlPuppetFallbackDirectory() const override; QString defaultPuppetToplevelBuildDirectory() const override; QUrl projectUrl() const override; + QString projectName() const override; QString currentProjectDirPath() const override; QUrl currentResourcePath() const override; void parseItemLibraryDescriptions() override; diff --git a/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp b/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp index 569d0ce3a4e..2e88690f322 100644 --- a/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp +++ b/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp @@ -149,6 +149,7 @@ public: QString defaultPuppetToplevelBuildDirectory() const override { return {}; } QString qmlPuppetFallbackDirectory() const override { return {}; } QUrl projectUrl() const override { return {}; } + QString projectName() const override { return {}; } void parseItemLibraryDescriptions() override {} const QmlDesigner::DesignerSettings &designerSettings() const override { return settings; } void undoOnCurrentDesignDocument() override {} diff --git a/tests/unit/tests/mocks/externaldependenciesmock.h b/tests/unit/tests/mocks/externaldependenciesmock.h index c4cfe6cd3b5..df70a7fcdb3 100644 --- a/tests/unit/tests/mocks/externaldependenciesmock.h +++ b/tests/unit/tests/mocks/externaldependenciesmock.h @@ -15,6 +15,7 @@ public: MOCK_METHOD(QString, qmlPuppetFallbackDirectory, (), (const, override)); MOCK_METHOD(QString, defaultPuppetToplevelBuildDirectory, (), (const, override)); MOCK_METHOD(QUrl, projectUrl, (), (const, override)); + MOCK_METHOD(QString, projectName, (), (const, override)); MOCK_METHOD(QString, currentProjectDirPath, (), (const, override)); MOCK_METHOD(QUrl, currentResourcePath, (), (const, override)); MOCK_METHOD(void, parseItemLibraryDescriptions, (), (override));