From 9f6221d3cd3ecc49664460ade2bacf6ccddf0edf Mon Sep 17 00:00:00 2001 From: Knud Dollereder Date: Wed, 11 Sep 2024 13:13:21 +0200 Subject: [PATCH] Introduce mockImports and allow resources in the root folder mockImports is a secial import path which is only considered by Design Studio and ignored by the cmake exporter. This prevents name clashes between qml mock modules and their c++/python counter parts. Fixes: QDS-13466 Fixes: QDS-13469 Change-Id: I64026ea9d8823f3d5e818a352ccb565fa29c1933 Reviewed-by: Thomas Hartmann --- .../buildsystem/projectitem/converters.cpp | 3 + .../projectitem/qmlprojectitem.cpp | 10 +++ .../buildsystem/projectitem/qmlprojectitem.h | 3 + .../buildsystem/qmlbuildsystem.cpp | 12 ++- .../buildsystem/qmlbuildsystem.h | 2 + .../qmlprojectexporter/cmakegenerator.cpp | 20 ++++- .../qmlprojectexporter/cmakegenerator.h | 1 + .../qmlprojectexporter/cmakewriter.cpp | 78 +++++++++++++++---- .../qmlprojectexporter/cmakewriter.h | 8 +- .../qmlprojectexporter/cmakewriterv0.cpp | 2 +- .../qmlprojectexporter/cmakewriterv1.cpp | 15 +++- .../qmlprojectexporter/filetypes.cpp | 2 +- 12 files changed, 131 insertions(+), 25 deletions(-) diff --git a/src/plugins/qmlprojectmanager/buildsystem/projectitem/converters.cpp b/src/plugins/qmlprojectmanager/buildsystem/projectitem/converters.cpp index 515c80de40e..51ee81c7d54 100644 --- a/src/plugins/qmlprojectmanager/buildsystem/projectitem/converters.cpp +++ b/src/plugins/qmlprojectmanager/buildsystem/projectitem/converters.cpp @@ -147,6 +147,7 @@ QString jsonToQmlProject(const QJsonObject &rootObject) appendBool("enablePythonGeneration", deploymentConfig["enablePythonGeneration"].toBool()); appendBool("widgetApp", runConfig["widgetApp"].toBool()); appendStringArray("importPaths", rootObject["importPaths"].toVariant().toStringList()); + appendStringArray("mockImports", rootObject["mockImports"].toVariant().toStringList()); appendBreak(); appendString("qdsVersion", versionConfig["designStudio"].toString()); appendString("quickVersion", versionConfig["qtQuick"].toString()); @@ -411,6 +412,8 @@ QJsonObject qmlProjectTojson(const Utils::FilePath &projectFile) } else if (propName.contains("importpaths", Qt::CaseInsensitive)) { objKey = "importPaths"; importPaths = value.toVariant().toStringList(); + } else if (propName.contains("mockImports", Qt::CaseInsensitive)) { + objKey = "mockImports"; } else { currentObj = &otherProperties; objKey = propName; // With prefix diff --git a/src/plugins/qmlprojectmanager/buildsystem/projectitem/qmlprojectitem.cpp b/src/plugins/qmlprojectmanager/buildsystem/projectitem/qmlprojectitem.cpp index 77221c3a5e0..65c310ce497 100644 --- a/src/plugins/qmlprojectmanager/buildsystem/projectitem/qmlprojectitem.cpp +++ b/src/plugins/qmlprojectmanager/buildsystem/projectitem/qmlprojectitem.cpp @@ -212,6 +212,16 @@ void QmlProjectItem::setImportPaths(const QStringList &importPaths) insertAndUpdateProjectFile("importPaths", QJsonArray::fromStringList(importPaths)); } +QStringList QmlProjectItem::mockImports() const +{ + return m_project["mockImports"].toVariant().toStringList(); +} + +void QmlProjectItem::setMockImports(const QStringList &paths) +{ + insertAndUpdateProjectFile("mockImports", QJsonArray::fromStringList(paths)); +} + void QmlProjectItem::addImportPath(const QString &importPath) { QJsonArray importPaths = m_project["importPaths"].toArray(); diff --git a/src/plugins/qmlprojectmanager/buildsystem/projectitem/qmlprojectitem.h b/src/plugins/qmlprojectmanager/buildsystem/projectitem/qmlprojectitem.h index 36ee8ef5316..fa6d700291a 100644 --- a/src/plugins/qmlprojectmanager/buildsystem/projectitem/qmlprojectitem.h +++ b/src/plugins/qmlprojectmanager/buildsystem/projectitem/qmlprojectitem.h @@ -46,6 +46,9 @@ public: void setImportPaths(const QStringList &paths); void addImportPath(const QString &importPath); + QStringList mockImports() const; + void setMockImports(const QStringList &paths); + QStringList qmlProjectModules() const; QStringList fileSelectors() const; diff --git a/src/plugins/qmlprojectmanager/buildsystem/qmlbuildsystem.cpp b/src/plugins/qmlprojectmanager/buildsystem/qmlbuildsystem.cpp index 5a64c8b7de0..79b20f3c82a 100644 --- a/src/plugins/qmlprojectmanager/buildsystem/qmlbuildsystem.cpp +++ b/src/plugins/qmlprojectmanager/buildsystem/qmlbuildsystem.cpp @@ -716,14 +716,24 @@ QStringList QmlBuildSystem::shaderToolFiles() const return m_projectItem->shaderToolFiles(); } +QStringList QmlBuildSystem::allImports() const +{ + return m_projectItem->importPaths() + m_projectItem->mockImports(); +} + QStringList QmlBuildSystem::importPaths() const { return m_projectItem->importPaths(); } +QStringList QmlBuildSystem::mockImports() const +{ + return m_projectItem->mockImports(); +} + QStringList QmlBuildSystem::absoluteImportPaths() const { - return Utils::transform(m_projectItem->importPaths(), [&](const QString &importPath) { + return Utils::transform(allImports(), [&](const QString &importPath) { Utils::FilePath filePath = Utils::FilePath::fromString(importPath); if (!filePath.isAbsolutePath()) return (projectDirectory() / importPath).toString(); diff --git a/src/plugins/qmlprojectmanager/buildsystem/qmlbuildsystem.h b/src/plugins/qmlprojectmanager/buildsystem/qmlbuildsystem.h index 22ea4e443e6..3907e8741ed 100644 --- a/src/plugins/qmlprojectmanager/buildsystem/qmlbuildsystem.h +++ b/src/plugins/qmlprojectmanager/buildsystem/qmlbuildsystem.h @@ -73,7 +73,9 @@ public: Utils::EnvironmentItems environment() const; + QStringList allImports() const; QStringList importPaths() const; + QStringList mockImports() const; QStringList absoluteImportPaths() const; QStringList fileSelectors() const; diff --git a/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakegenerator.cpp b/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakegenerator.cpp index 063811ea9d0..c529f012eef 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakegenerator.cpp +++ b/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakegenerator.cpp @@ -172,7 +172,7 @@ bool CMakeGenerator::checkUri(const QString& uri, const Utils::FilePath &path) c Utils::FilePath relative = path.relativeChildPath(m_root->dir); QList pathComponents = relative.pathView().split('/', Qt::SkipEmptyParts); - for (const auto& import : buildSystem()->importPaths()) { + for (const auto& import : buildSystem()->allImports()) { Utils::FilePath importPath = Utils::FilePath::fromUserInput(import); for (const auto& component : importPath.pathView().split('/', Qt::SkipEmptyParts)) { if (component == pathComponents.first()) @@ -219,9 +219,25 @@ void CMakeGenerator::createSourceFiles() const m_writer->writeSourceFiles(sourceNode, m_root); } +bool CMakeGenerator::isMockModule(const NodePtr &node) const +{ + QTC_ASSERT(buildSystem(), return false); + + Utils::FilePath dir = node->dir.parentDir(); + QString mockDir = dir.relativeChildPath(m_root->dir).path(); + for (const QString &import : buildSystem()->mockImports()) { + if (import == mockDir) + return true; + } + return false; +} + void CMakeGenerator::readQmlDir(const Utils::FilePath &filePath, NodePtr &node) const { - node->type = Node::Type::Module; + if (isMockModule(node)) + node->type = Node::Type::MockModule; + else + node->type = Node::Type::Module; QFile f(filePath.toString()); f.open(QIODevice::ReadOnly); diff --git a/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakegenerator.h b/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakegenerator.h index e3b8a8a1085..43257e17815 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakegenerator.h +++ b/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakegenerator.h @@ -42,6 +42,7 @@ public: private: bool ignore(const Utils::FilePath &path) const; bool checkUri(const QString& uri, const Utils::FilePath &path) const; + bool isMockModule(const NodePtr &node) const; void createCMakeFiles(const NodePtr &node) const; void createSourceFiles() const; diff --git a/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriter.cpp b/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriter.cpp index 966714981a0..857a30ce330 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriter.cpp +++ b/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriter.cpp @@ -17,6 +17,13 @@ namespace QmlProjectManager { namespace QmlProjectExporter { +const char TEMPLATE_RESOURCES[] = R"( +qt6_add_resources(%1 %2 + PREFIX "%3" + VERSION 1.0 + FILES %4 +))"; + const char TEMPLATE_BIG_RESOURCES[] = R"( qt6_add_resources(%1 %2 BIG_RESOURCES @@ -235,36 +242,64 @@ QString CMakeWriter::makeSetEnvironmentFn() const return out; } -std::tuple CMakeWriter::makeResourcesBlocks(const NodePtr &node) const +std::tuple CMakeWriter::makeResourcesBlocksRoot(const NodePtr &node) const { QString resourcesOut; QString bigResourcesOut; - QString resourceFiles; - std::vector bigResources; - for (const Utils::FilePath &path : assets(node)) { - if (path.fileSize() > 5000000) { - bigResources.push_back(makeRelative(node, path)); - continue; - } - resourceFiles.append(QString("\t\t%1\n").arg(makeRelative(node, path))); + QStringList res; + QStringList bigRes; + collectResources(node, res, bigRes); + + if (!res.isEmpty()) { + QString resourceContent; + for (const QString &r : res) + resourceContent.append(QString("\n\t\t%1").arg(r)); + + const QString resourceName = node->name + "Resource"; + resourcesOut = QString::fromUtf8(TEMPLATE_RESOURCES, -1) + .arg("${CMAKE_PROJECT_NAME}", resourceName, "/qt/qml", resourceContent); } - if (!resourceFiles.isEmpty()) - resourcesOut.append(QString("\tRESOURCES\n%1").arg(resourceFiles)); + if (!bigRes.isEmpty()) { + QString bigResourceContent; + for (const QString &r : bigRes) + bigResourceContent.append(QString("\n\t\t%1").arg(r)); - QString templatePostfix; - if (!bigResources.empty()) { + const QString resourceName = node->name + "BigResource"; + bigResourcesOut = QString::fromUtf8(TEMPLATE_BIG_RESOURCES, -1) + .arg("${CMAKE_PROJECT_NAME}", resourceName, "/qt/qml", bigResourceContent); + } + + return {resourcesOut, bigResourcesOut}; +} + +std::tuple CMakeWriter::makeResourcesBlocksModule(const NodePtr &node) const +{ + QString resourcesOut; + QString bigResourcesOut; + + QStringList res; + QStringList bigRes; + collectResources(node, res, bigRes); + + if (!res.isEmpty()) { + resourcesOut = "\tRESOURCES\n"; + for (const QString &r : res) + resourcesOut.append(QString("\t\t%1\n").arg(r)); + } + + if (!bigRes.isEmpty()) { QString resourceContent; - for (const QString &res : bigResources) - resourceContent.append(QString("\n %1").arg(res)); + for (const QString &res : bigRes) + resourceContent.append(QString("\n\t\t%1").arg(res)); const QString prefixPath = QString(node->uri).replace('.', '/'); const QString prefix = "/qt/qml/" + prefixPath; const QString resourceName = node->name + "BigResource"; bigResourcesOut = QString::fromUtf8(TEMPLATE_BIG_RESOURCES, -1) - .arg(node->name, resourceName, prefix, resourceContent); + .arg(node->name, resourceName, prefix, resourceContent); } return {resourcesOut, bigResourcesOut}; @@ -278,6 +313,17 @@ void CMakeWriter::collectPlugins(const NodePtr &node, std::vector &out) collectPlugins(child, out); } +void CMakeWriter::collectResources(const NodePtr &node, QStringList &res, QStringList &bigRes) const +{ + for (const Utils::FilePath &path : assets(node)) { + if (path.fileSize() > 5000000) { + bigRes.push_back(makeRelative(node, path)); + } else { + res.append(makeRelative(node, path)); + } + } +} + } // End namespace QmlProjectExporter. } // End namespace QmlProjectManager. diff --git a/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriter.h b/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriter.h index 0fbee120f79..e783a3ca4d9 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriter.h +++ b/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriter.h @@ -20,6 +20,7 @@ struct Node Module, Library, Folder, + MockModule }; std::shared_ptr parent = nullptr; @@ -63,6 +64,8 @@ public: static void writeFile(const Utils::FilePath &path, const QString &content); CMakeWriter(CMakeGenerator *parent); + virtual ~CMakeWriter() = default; + const CMakeGenerator *parent() const; virtual bool isPlugin(const NodePtr &node) const; @@ -89,11 +92,12 @@ protected: QString makeSingletonBlock(const NodePtr &node) const; QString makeSubdirectoriesBlock(const NodePtr &node) const; QString makeSetEnvironmentFn() const; - std::tuple makeResourcesBlocks(const NodePtr &node) const; - + std::tuple makeResourcesBlocksRoot(const NodePtr &node) const; + std::tuple makeResourcesBlocksModule(const NodePtr &node) const; private: void collectPlugins(const NodePtr &node, std::vector &out) const; + void collectResources(const NodePtr &node, QStringList &res, QStringList &bigRes) const; const CMakeGenerator *m_parent = nullptr; }; diff --git a/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriterv0.cpp b/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriterv0.cpp index 257a549b264..35f7fc9b82e 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriterv0.cpp +++ b/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriterv0.cpp @@ -106,7 +106,7 @@ void CMakeWriterV0::writeModuleCMakeFile(const NodePtr &node, const NodePtr &roo QString qmlModulesContent; qmlModulesContent.append(makeQmlFilesBlock(node)); - auto [resources, bigResources] = makeResourcesBlocks(node); + auto [resources, bigResources] = makeResourcesBlocksModule(node); qmlModulesContent.append(resources); if (!qmlModulesContent.isEmpty()) { diff --git a/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriterv1.cpp b/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriterv1.cpp index 8c3178beb53..0e76546c6f3 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriterv1.cpp +++ b/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriterv1.cpp @@ -88,7 +88,17 @@ void CMakeWriterV1::writeModuleCMakeFile(const NodePtr &node, const NodePtr &) c const Utils::FilePath userFile = node->dir.pathAppended("qds.cmake"); QString userFileContent(DO_NOT_EDIT_FILE); userFileContent.append(makeSubdirectoriesBlock(node)); - userFileContent.append("\n"); + + auto [resources, bigResources] = makeResourcesBlocksRoot(node); + if (!resources.isEmpty()) { + userFileContent.append(resources); + userFileContent.append("\n"); + } + + if (!bigResources.isEmpty()) { + userFileContent.append(bigResources); + userFileContent.append("\n"); + } QString pluginNames; std::vector plugs = plugins(node); @@ -102,6 +112,7 @@ void CMakeWriterV1::writeModuleCMakeFile(const NodePtr &node, const NodePtr &) c "target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE\n" "%1)"); + userFileContent.append("\n"); userFileContent.append(linkLibrariesTemplate.arg(pluginNames)); writeFile(userFile, userFileContent); return; @@ -119,7 +130,7 @@ void CMakeWriterV1::writeModuleCMakeFile(const NodePtr &node, const NodePtr &) c prefix.append(makeSubdirectoriesBlock(node)); prefix.append(makeSingletonBlock(node)); - auto [resources, bigResources] = makeResourcesBlocks(node); + auto [resources, bigResources] = makeResourcesBlocksModule(node); QString moduleContent; moduleContent.append(makeQmlFilesBlock(node)); moduleContent.append(resources); diff --git a/src/plugins/qmlprojectmanager/qmlprojectexporter/filetypes.cpp b/src/plugins/qmlprojectmanager/qmlprojectexporter/filetypes.cpp index a6ee4cd15f6..c69afd9a70c 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectexporter/filetypes.cpp +++ b/src/plugins/qmlprojectmanager/qmlprojectexporter/filetypes.cpp @@ -33,7 +33,7 @@ bool isAssetFile(const Utils::FilePath &path) { static const QStringList suffixes = { "js", "ts", "json", "hints", "mesh", "qad", "qsb", "frag", - "frag.qsb", "vert", "vert.qsb", "mng" + "frag.qsb", "vert", "vert.qsb", "mng", "wav" }; return suffixes.contains(path.suffix(), Qt::CaseInsensitive) ||