aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKnud Dollereder <knud.dollereder@qt.io>2024-02-01 15:17:58 +0100
committerKnud Dollereder <knud.dollereder@qt.io>2024-02-05 16:21:24 +0000
commit8b97598011b79152c5addc367f938556cefc7fb2 (patch)
tree71f7493ba0be6158553a3a56a9d3698d7f65e309
parentc58efc4310d25bdbd62766f0efa087cbdafcd1f1 (diff)
QmlProjectManager: Add new cmake generator
Automatic cmake generation can now be enabled by setting the qmlproject property enableCMakeGeneration to true Change-Id: I98523a9479d0cd812e43a9bd0b700120358260f6 Reviewed-by: <github-actions-qt-creator@cristianadam.eu> Reviewed-by: Qt CI Patch Build Bot <ci_patchbuild_bot@qt.io> Reviewed-by: Tim Jenssen <tim.jenssen@qt.io> Reviewed-by: Burak Hancerli <burak.hancerli@qt.io>
-rw-r--r--src/plugins/qmlprojectmanager/CMakeLists.txt3
-rw-r--r--src/plugins/qmlprojectmanager/buildsystem/projectitem/converters.cpp4
-rw-r--r--src/plugins/qmlprojectmanager/buildsystem/projectitem/qmlprojectitem.cpp12
-rw-r--r--src/plugins/qmlprojectmanager/buildsystem/projectitem/qmlprojectitem.h3
-rw-r--r--src/plugins/qmlprojectmanager/buildsystem/qmlbuildsystem.cpp10
-rw-r--r--src/plugins/qmlprojectmanager/buildsystem/qmlbuildsystem.h4
-rw-r--r--src/plugins/qmlprojectmanager/cmakegen/boilerplate.qrc3
-rw-r--r--src/plugins/qmlprojectmanager/cmakegen/cmakegenerator.cpp550
-rw-r--r--src/plugins/qmlprojectmanager/cmakegen/cmakegenerator.h101
-rw-r--r--src/plugins/qmlprojectmanager/cmakegen/gencmakeheadercomponents.tpl19
-rw-r--r--src/plugins/qmlprojectmanager/cmakegen/gencmakemodule.tpl14
-rw-r--r--src/plugins/qmlprojectmanager/cmakegen/gencmakeroot.tpl52
-rw-r--r--tests/unit/tests/unittests/qmlprojectmanager/data/converter/test-set-1/testfile.jsontoqml1
-rw-r--r--tests/unit/tests/unittests/qmlprojectmanager/data/converter/test-set-1/testfile.qmlproject2
-rw-r--r--tests/unit/tests/unittests/qmlprojectmanager/data/converter/test-set-1/testfile.qmltojson1
-rw-r--r--tests/unit/tests/unittests/qmlprojectmanager/data/converter/test-set-2/testfile.jsontoqml1
-rw-r--r--tests/unit/tests/unittests/qmlprojectmanager/data/converter/test-set-2/testfile.qmlproject2
-rw-r--r--tests/unit/tests/unittests/qmlprojectmanager/data/converter/test-set-2/testfile.qmltojson1
-rw-r--r--tests/unit/tests/unittests/qmlprojectmanager/data/converter/test-set-3/testfile.jsontoqml1
-rw-r--r--tests/unit/tests/unittests/qmlprojectmanager/data/converter/test-set-3/testfile.qmlproject2
-rw-r--r--tests/unit/tests/unittests/qmlprojectmanager/data/converter/test-set-3/testfile.qmltojson1
-rw-r--r--tests/unit/tests/unittests/qmlprojectmanager/data/converter/test-set-mcu-1/testfile.jsontoqml1
-rw-r--r--tests/unit/tests/unittests/qmlprojectmanager/data/converter/test-set-mcu-2/testfile.jsontoqml1
-rw-r--r--tests/unit/tests/unittests/qmlprojectmanager/data/getter-setter/empty.qmlproject1
-rw-r--r--tests/unit/tests/unittests/qmlprojectmanager/data/getter-setter/with_qds_prefix.qmlproject1
-rw-r--r--tests/unit/tests/unittests/qmlprojectmanager/data/getter-setter/without_qds_prefix.qmlproject1
-rw-r--r--tests/unit/tests/unittests/qmlprojectmanager/projectitem-test.cpp28
27 files changed, 818 insertions, 2 deletions
diff --git a/src/plugins/qmlprojectmanager/CMakeLists.txt b/src/plugins/qmlprojectmanager/CMakeLists.txt
index a1212e8bc1..b6fa746996 100644
--- a/src/plugins/qmlprojectmanager/CMakeLists.txt
+++ b/src/plugins/qmlprojectmanager/CMakeLists.txt
@@ -50,6 +50,7 @@ extend_qtc_plugin(QmlProjectManager
cmakeprojectconverterdialog.cpp cmakeprojectconverterdialog.h
generatecmakelists.cpp generatecmakelists.h
generatecmakelistsconstants.h
+ cmakegenerator.cpp cmakegenerator.h
boilerplate.qrc
)
@@ -57,7 +58,7 @@ add_qtc_library(QmlProjectManagerLib OBJECT
CONDITION Qt6_VERSION VERSION_GREATER_EQUAL 6.4.3
EXCLUDE_FROM_INSTALL
DEPENDS
- QmlJS Utils
+ QmlJS Utils ProjectExplorer
INCLUDES
${CMAKE_CURRENT_LIST_DIR}
SOURCES_PREFIX ${CMAKE_CURRENT_LIST_DIR}/buildsystem
diff --git a/src/plugins/qmlprojectmanager/buildsystem/projectitem/converters.cpp b/src/plugins/qmlprojectmanager/buildsystem/projectitem/converters.cpp
index b35679ed34..08fba2c098 100644
--- a/src/plugins/qmlprojectmanager/buildsystem/projectitem/converters.cpp
+++ b/src/plugins/qmlprojectmanager/buildsystem/projectitem/converters.cpp
@@ -143,6 +143,7 @@ QString jsonToQmlProject(const QJsonObject &rootObject)
appendString("mainFile", runConfig["mainFile"].toString());
appendString("mainUiFile", runConfig["mainUiFile"].toString());
appendString("targetDirectory", deploymentConfig["targetDirectory"].toString());
+ appendBool("enableCMakeGeneration", deploymentConfig["enableCMakeGeneration"].toBool());
appendBool("widgetApp", runConfig["widgetApp"].toBool());
appendStringArray("importPaths", rootObject["importPaths"].toVariant().toStringList());
appendBreak();
@@ -282,7 +283,8 @@ QJsonObject qmlProjectTojson(const Utils::FilePath &projectFile)
|| propName.contains("mainuifile", Qt::CaseInsensitive)
|| propName.contains("forcefreetype", Qt::CaseInsensitive)) {
currentObj = &runConfigObject;
- } else if (propName.contains("targetdirectory", Qt::CaseInsensitive)) {
+ } else if (propName.contains("targetdirectory", Qt::CaseInsensitive)
+ || propName.contains("enableCMakeGeneration", Qt::CaseInsensitive)) {
currentObj = &deploymentObject;
} else if (propName.contains("qtformcus", Qt::CaseInsensitive)) {
qtForMCUs = value.toBool();
diff --git a/src/plugins/qmlprojectmanager/buildsystem/projectitem/qmlprojectitem.cpp b/src/plugins/qmlprojectmanager/buildsystem/projectitem/qmlprojectitem.cpp
index 77d0eea82d..5524e927e5 100644
--- a/src/plugins/qmlprojectmanager/buildsystem/projectitem/qmlprojectitem.cpp
+++ b/src/plugins/qmlprojectmanager/buildsystem/projectitem/qmlprojectitem.cpp
@@ -422,4 +422,16 @@ void QmlProjectItem::insertAndUpdateProjectFile(const QString &key, const QJsonV
m_projectFile.writeFileContents(Converters::jsonToQmlProject(m_project).toUtf8());
}
+bool QmlProjectItem::enableCMakeGeneration() const
+{
+ return m_project["deployment"].toObject()["enableCMakeGeneration"].toBool();
+}
+
+void QmlProjectItem::setEnableCMakeGeneration(bool enable)
+{
+ QJsonObject obj = m_project["deployment"].toObject();
+ obj["enableCMakeGeneration"] = enable;
+ insertAndUpdateProjectFile("deployment", obj);
+}
+
} // namespace QmlProjectManager
diff --git a/src/plugins/qmlprojectmanager/buildsystem/projectitem/qmlprojectitem.h b/src/plugins/qmlprojectmanager/buildsystem/projectitem/qmlprojectitem.h
index 214614f536..7d57ad2e60 100644
--- a/src/plugins/qmlprojectmanager/buildsystem/projectitem/qmlprojectitem.h
+++ b/src/plugins/qmlprojectmanager/buildsystem/projectitem/qmlprojectitem.h
@@ -88,6 +88,9 @@ public:
QJsonObject project() const;
+ bool enableCMakeGeneration() const;
+ void setEnableCMakeGeneration(bool enable);
+
signals:
void qmlFilesChanged(const QSet<QString> &, const QSet<QString> &);
diff --git a/src/plugins/qmlprojectmanager/buildsystem/qmlbuildsystem.cpp b/src/plugins/qmlprojectmanager/buildsystem/qmlbuildsystem.cpp
index 5131d9c57c..e91fd72baa 100644
--- a/src/plugins/qmlprojectmanager/buildsystem/qmlbuildsystem.cpp
+++ b/src/plugins/qmlprojectmanager/buildsystem/qmlbuildsystem.cpp
@@ -77,6 +77,7 @@ void updateMcuBuildStep(Target *target, bool mcuEnabled)
QmlBuildSystem::QmlBuildSystem(Target *target)
: BuildSystem(target)
+ , m_cmakeGen(new GenerateCmake::CMakeGenerator(this, this))
{
// refresh first - project information is used e.g. to decide the default RC's
refresh(RefreshOptions::Project);
@@ -86,10 +87,12 @@ QmlBuildSystem::QmlBuildSystem(Target *target)
connect(target->project(), &Project::activeTargetChanged, this, [this](Target *target) {
refresh(RefreshOptions::NoFileRefresh);
+ m_cmakeGen->initialize(qmlProject());
updateMcuBuildStep(target, qtForMCUs());
});
connect(target->project(), &Project::projectFileIsDirty, this, [this]() {
refresh(RefreshOptions::Project);
+ m_cmakeGen->initialize(qmlProject());
updateMcuBuildStep(project()->activeTarget(), qtForMCUs());
});
@@ -220,6 +223,13 @@ void QmlBuildSystem::initProjectItem()
&QmlProjectItem::qmlFilesChanged,
this,
&QmlBuildSystem::refreshFiles);
+
+ connect(m_projectItem.get(),
+ &QmlProjectItem::qmlFilesChanged,
+ m_cmakeGen,
+ &GenerateCmake::CMakeGenerator::update);
+
+ m_cmakeGen->setEnabled(m_projectItem->enableCMakeGeneration());
}
void QmlBuildSystem::parseProjectFiles()
diff --git a/src/plugins/qmlprojectmanager/buildsystem/qmlbuildsystem.h b/src/plugins/qmlprojectmanager/buildsystem/qmlbuildsystem.h
index 3615979e2d..524af5cd1b 100644
--- a/src/plugins/qmlprojectmanager/buildsystem/qmlbuildsystem.h
+++ b/src/plugins/qmlprojectmanager/buildsystem/qmlbuildsystem.h
@@ -8,6 +8,8 @@
#include "../qmlprojectmanager_global.h"
#include <projectexplorer/buildsystem.h>
+#include "qmlprojectmanager/cmakegen/cmakegenerator.h"
+
namespace QmlProjectManager {
class QmlProject;
@@ -122,6 +124,8 @@ private:
void registerMenuButtons();
void updateDeploymentData();
friend class FilesUpdateBlocker;
+
+ GenerateCmake::CMakeGenerator* m_cmakeGen;
};
} // namespace QmlProjectManager
diff --git a/src/plugins/qmlprojectmanager/cmakegen/boilerplate.qrc b/src/plugins/qmlprojectmanager/cmakegen/boilerplate.qrc
index a89643d6ff..10fab59838 100644
--- a/src/plugins/qmlprojectmanager/cmakegen/boilerplate.qrc
+++ b/src/plugins/qmlprojectmanager/cmakegen/boilerplate.qrc
@@ -1,5 +1,8 @@
<RCC>
<qresource prefix="/boilerplatetemplates">
+ <file>gencmakeroot.tpl</file>
+ <file>gencmakemodule.tpl</file>
+ <file>gencmakeheadercomponents.tpl</file>
<file>qmlprojectmaincpp.tpl</file>
<file>qmlprojectmaincppheader.tpl</file>
<file>qmlprojectenvheader.tpl</file>
diff --git a/src/plugins/qmlprojectmanager/cmakegen/cmakegenerator.cpp b/src/plugins/qmlprojectmanager/cmakegen/cmakegenerator.cpp
new file mode 100644
index 0000000000..55bcea6a87
--- /dev/null
+++ b/src/plugins/qmlprojectmanager/cmakegen/cmakegenerator.cpp
@@ -0,0 +1,550 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "cmakegenerator.h"
+#include "generatecmakelistsconstants.h"
+
+#include "projectexplorer/projectmanager.h"
+#include "projectexplorer/projectnodes.h"
+#include "qmlprojectmanager/qmlproject.h"
+
+#include <QRegularExpression>
+
+#include <set>
+
+namespace QmlProjectManager {
+
+namespace GenerateCmake {
+
+const char TEMPLATE_CMAKELISTS_ROOT[] = ":/boilerplatetemplates/gencmakeroot.tpl";
+const char TEMPLATE_CMAKELISTS_MODULE[] = ":/boilerplatetemplates/gencmakemodule.tpl";
+
+const char TEMPLATE_QMLMODULES[] = ":/boilerplatetemplates/qmlprojectmodules.tpl";
+const char TEMPLATE_SOURCE_MAIN[] = ":/boilerplatetemplates/qmlprojectmaincpp.tpl";
+const char TEMPLATE_HEADER_IMPORT_COMPS[] = ":/boilerplatetemplates/gencmakeheadercomponents.tpl";
+const char TEMPLATE_HEADER_IMPORT_PLUGINS[] = ":/boilerplatetemplates/qmlprojectmaincppheader.tpl";
+const char TEMPLATE_HEADER_ENVIRONMENT[] = ":/boilerplatetemplates/qmlprojectenvheader.tpl";
+
+const char DO_NOT_EDIT_FILE_COMMENT[] =
+"### This file is automatically generated by Qt Design Studio.\n"
+"### Do not change\n\n";
+
+const char ADD_SUBDIR[] = "add_subdirectory(%1)\n";
+
+const char BIG_RESOURCE_TEMPLATE[] = R"(
+qt6_add_resources(%1 %2
+ BIG_RESOURCES
+ PREFIX "%3"
+ VERSION 1.0
+ FILES %4
+))";
+
+CMakeGenerator::CMakeGenerator(QmlBuildSystem *bs, QObject *parent)
+ : QObject(parent)
+ , m_root(std::make_shared<Node>())
+ , m_buildSystem(bs)
+{}
+
+void CMakeGenerator::setEnabled(bool enabled)
+{
+ m_enabled = enabled;
+}
+
+void CMakeGenerator::initialize(QmlProject *project)
+{
+ if (!m_enabled)
+ return;
+
+ m_srcs.clear();
+ m_moduleNames.clear();
+
+ m_root = std::make_shared<Node>();
+ m_root->name = QString("Root");
+ m_root->dir = project->rootProjectDirectory();
+
+ m_projectName = project->displayName();
+
+ ProjectExplorer::ProjectNode *rootProjectNode = project->rootProjectNode();
+ parseNodeTree(m_root, rootProjectNode);
+ parseSourceTree();
+
+ createCMakeFiles(m_root);
+ createEntryPoints(m_root);
+}
+
+void CMakeGenerator::update(const QSet<QString> &added, const QSet<QString> &removed)
+{
+ if (!m_enabled)
+ return;
+
+ std::set<NodePtr> dirtyModules;
+ for (const QString &add : added) {
+ const Utils::FilePath path = Utils::FilePath::fromString(add);
+ if (auto node = findOrCreateNode(m_root, path)) {
+ insertFile(node, path);
+ if (auto module = findModuleFor(node))
+ dirtyModules.insert(module);
+ } else {
+ qDebug() << "CmakeGen: Failed to find Folder node " << path;
+ }
+ }
+
+ for (const QString &remove : removed) {
+ const Utils::FilePath path = Utils::FilePath::fromString(remove);
+ if (auto node = findNode(m_root, path)) {
+ removeFile(node, path);
+ if (auto module = findModuleFor(node))
+ dirtyModules.insert(module);
+ }
+ }
+
+ for (auto module : dirtyModules)
+ createModuleCMakeFile(module);
+}
+
+std::vector<Utils::FilePath> CMakeGenerator::qmlFiles(const NodePtr &node) const
+{
+ std::vector<Utils::FilePath> out = node->files;
+ for (const NodePtr &child : node->subdirs) {
+ if (child->module)
+ continue;
+
+ auto childFiles = qmlFiles(child);
+ out.insert(out.end(), childFiles.begin(), childFiles.end());
+ }
+ return out;
+}
+
+std::vector<Utils::FilePath> CMakeGenerator::singletons(const NodePtr &node) const
+{
+ std::vector<Utils::FilePath> out = node->singletons;
+ for (const NodePtr &child : node->subdirs) {
+ if (child->module)
+ continue;
+
+ auto childFiles = singletons(child);
+ out.insert(out.end(), childFiles.begin(), childFiles.end());
+ }
+ return out;
+}
+
+std::vector<Utils::FilePath> CMakeGenerator::resources(const NodePtr &node) const
+{
+ std::vector<Utils::FilePath> out = node->resources;
+ for (const NodePtr &child : node->subdirs) {
+ if (child->module)
+ continue;
+
+ auto childFiles = resources(child);
+ out.insert(out.end(), childFiles.begin(), childFiles.end());
+ }
+ return out;
+}
+
+std::vector<Utils::FilePath> CMakeGenerator::sources(const NodePtr &node) const
+{
+ std::vector<Utils::FilePath> out = node->sources;
+ for (const NodePtr &child : node->subdirs) {
+ if (child->module)
+ continue;
+
+ auto childFiles = sources(child);
+ out.insert(out.end(), childFiles.begin(), childFiles.end());
+ }
+ return out;
+}
+
+void CMakeGenerator::createCMakeFiles(const NodePtr &node) const
+{
+ if (node->name == "Root") {
+ createMainCMakeFile(node);
+ createQmlModuleFile(node);
+ } else if (node->module || hasChildModule(node)) {
+ createModuleCMakeFile(node);
+ }
+ for (const NodePtr &n : node->subdirs)
+ createCMakeFiles(n);
+}
+
+void CMakeGenerator::createMainCMakeFile(const NodePtr &node) const
+{
+ const QString appName = m_projectName + "App";
+
+ const QString qtcontrolsConfFile = makeEnvironmentVariable(Constants::ENV_VARIABLE_CONTROLCONF);
+
+ QString fileSection = "";
+ if (!qtcontrolsConfFile.isEmpty())
+ fileSection = QString(" FILES\n %1").arg(qtcontrolsConfFile);
+
+ const QString fileTemplate = readTemplate(TEMPLATE_CMAKELISTS_ROOT);
+ const QString fileContent = fileTemplate.arg(appName, m_srcs.join(" "), fileSection);
+
+ const Utils::FilePath file = node->dir.pathAppended("CMakeLists.txt");
+ writeFile(file, fileContent);
+}
+
+void CMakeGenerator::createQmlModuleFile(const NodePtr &node) const
+{
+ const QString appName = m_projectName + "App";
+
+ QString subdirIncludes;
+ for (const NodePtr &n : node->subdirs)
+ subdirIncludes.append(QString(ADD_SUBDIR).arg(n->name));
+
+ QString modulesAsPlugins;
+ for (const QString &moduleName : m_moduleNames)
+ modulesAsPlugins.append(" " + moduleName + "plugin\n");
+
+ const QString fileTemplate = readTemplate(TEMPLATE_QMLMODULES);
+ const QString fileContent = fileTemplate.arg(appName, subdirIncludes, modulesAsPlugins);
+
+ const Utils::FilePath file = node->dir.pathAppended("qmlModules");
+ writeFile(file, fileContent);
+}
+
+void CMakeGenerator::createModuleCMakeFile(const NodePtr &node) const
+{
+ QString subDirContent;
+ for (const NodePtr &n : node->subdirs) {
+ if (n->module || hasChildModule(n))
+ subDirContent.append(QString(ADD_SUBDIR).arg(n->dir.fileName()));
+ }
+
+ QString content;
+ if (!node->module && hasChildModule(node)) {
+ content.append(DO_NOT_EDIT_FILE_COMMENT);
+ content.append(subDirContent);
+ Utils::FilePath file = node->dir.pathAppended("CMakeLists.txt");
+ writeFile(file, content);
+ return;
+ }
+
+ auto makeRelative = [](const Utils::FilePath &base,
+ const Utils::FilePath &converted) -> QString {
+ return "\"" + Utils::FilePath::calcRelativePath(converted.toString(), base.toString()) + "\"";
+ };
+
+ QString uri = node->uri;
+ if (uri.isEmpty())
+ uri = node->dir.baseName();
+
+ const QString setProperties(
+ "set_source_files_properties(%1\n PROPERTIES\n %2 %3\n)\n\n");
+
+ for (const Utils::FilePath &path : node->singletons) {
+ content.append(setProperties.arg(path.fileName()).arg("QT_QML_SINGLETON_TYPE").arg("true"));
+ }
+
+ if (!subDirContent.isEmpty())
+ content.append(subDirContent);
+
+ QString qmlFileContent;
+ for (const Utils::FilePath &path : qmlFiles(node)) {
+ qmlFileContent.append(QString(" %1\n").arg(makeRelative(node->dir, path)));
+ }
+
+ QString moduleContent;
+ if (!qmlFileContent.isEmpty())
+ moduleContent.append(QString(" QML_FILES\n%1").arg(qmlFileContent));
+
+ std::vector<QString> bigResources;
+ QString resourceFiles;
+ for (const Utils::FilePath &path : resources(node)) {
+ if (path.fileSize() > 5000000) {
+ bigResources.push_back(makeRelative(node->dir, path));
+ continue;
+ }
+ resourceFiles.append(QString(" %1\n").arg(makeRelative(node->dir, path)));
+ }
+
+ if (!resourceFiles.isEmpty())
+ moduleContent.append(QString(" RESOURCES\n%1").arg(resourceFiles));
+
+ QString bigResourceContent;
+ if (!bigResources.empty()) {
+ QString resourceContent;
+ for (const QString &res : bigResources)
+ resourceContent.append(QString("\n %1").arg(res));
+
+ const QString prefixPath = QString(uri).replace('.', '/');
+ const QString prefix = "/qt/qml/" + prefixPath;
+ const QString resourceName = node->name + "BigResource";
+
+ bigResourceContent = QString::fromUtf8(BIG_RESOURCE_TEMPLATE, -1)
+ .arg(node->name, resourceName, prefix, resourceContent);
+ }
+
+ const QString fileTemplate = readTemplate(TEMPLATE_CMAKELISTS_MODULE);
+ const QString fileContent =
+ fileTemplate.arg(content, node->name, uri, moduleContent, bigResourceContent);
+
+ const Utils::FilePath file = node->dir.pathAppended("CMakeLists.txt");
+ writeFile(file, fileContent);
+}
+
+void CMakeGenerator::createEntryPoints(const NodePtr &node) const
+{
+ createMainCppFile(node);
+}
+
+void CMakeGenerator::createMainCppFile(const NodePtr &node) const
+{
+ const Utils::FilePath srcDir = node->dir.pathAppended(Constants::DIRNAME_CPP);
+ if (!srcDir.exists()) {
+ srcDir.createDir();
+
+ const Utils::FilePath componentsHeaderPath = srcDir.pathAppended(
+ "import_qml_components_plugins.h");
+ const QString componentsHeaderContent = readTemplate(TEMPLATE_HEADER_IMPORT_COMPS);
+ writeFile(componentsHeaderPath, componentsHeaderContent);
+
+ const Utils::FilePath cppFilePath = srcDir.pathAppended("main.cpp");
+ const QString cppContent = readTemplate(TEMPLATE_SOURCE_MAIN);
+ writeFile(cppFilePath, cppContent);
+
+ const Utils::FilePath envHeaderPath = srcDir.pathAppended("app_environment.h");
+ if (m_buildSystem) {
+ QString environment;
+ const QString qtcontrolsConfFile = makeEnvironmentVariable(
+ Constants::ENV_VARIABLE_CONTROLCONF);
+ for (Utils::EnvironmentItem &envItem : m_buildSystem->environment()) {
+ QString key = envItem.name;
+ QString value = envItem.value;
+ if (value == qtcontrolsConfFile)
+ value.prepend(":/");
+ environment.append(QString(" qputenv(\"%1\", \"%2\");\n").arg(key).arg(value));
+ }
+ const QString envHeaderContent = readTemplate(TEMPLATE_HEADER_ENVIRONMENT).arg(environment);
+ writeFile(envHeaderPath, envHeaderContent);
+ }
+ }
+
+ QString moduleContent;
+ for (const QString &module : m_moduleNames)
+ moduleContent.append(QString("Q_IMPORT_QML_PLUGIN(%1)\n").arg(module + "Plugin"));
+
+ const QString headerContent = readTemplate(TEMPLATE_HEADER_IMPORT_PLUGINS).arg(moduleContent);
+ const Utils::FilePath headerFilePath = srcDir.pathAppended("import_qml_plugins.h");
+ writeFile(headerFilePath, headerContent);
+}
+
+void CMakeGenerator::writeFile(const Utils::FilePath &path, const QString &content) const
+{
+ QFile fileHandle(path.toString());
+ fileHandle.open(QIODevice::WriteOnly);
+ QTextStream stream(&fileHandle);
+ stream << content;
+ fileHandle.close();
+}
+
+QString CMakeGenerator::makeEnvironmentVariable(const QString &key) const
+{
+ QString value = {};
+
+ if (m_buildSystem) {
+ auto envItems = m_buildSystem->environment();
+ auto confEnv = std::find_if(envItems.begin(),
+ envItems.end(),
+ [key](Utils::NameValueItem &item) { return item.name == key; });
+ if (confEnv != envItems.end())
+ value = confEnv->value;
+ }
+ return value;
+}
+
+QString CMakeGenerator::readTemplate(const QString &templatePath) const
+{
+ QFile templatefile(templatePath);
+ templatefile.open(QIODevice::ReadOnly);
+ QTextStream stream(&templatefile);
+ QString content = stream.readAll();
+ templatefile.close();
+ return content;
+}
+
+void CMakeGenerator::readQmlDir(const Utils::FilePath &filePath, NodePtr &node) const
+{
+ node->module = true;
+
+ QFile f(filePath.toString());
+ f.open(QIODevice::ReadOnly);
+ QTextStream stream(&f);
+
+ Utils::FilePath dir = filePath.parentDir();
+ while (!stream.atEnd()) {
+ const QString line = stream.readLine();
+ const QStringList tokenizedLine = line.split(QRegularExpression("\\s+"));
+ const QString maybeFileName = tokenizedLine.last();
+ if (tokenizedLine.first().compare("module", Qt::CaseInsensitive) == 0) {
+ node->uri = tokenizedLine.last();
+ node->name = QString(node->uri).replace('.', '_');
+ } else if (maybeFileName.endsWith(".qml", Qt::CaseInsensitive)) {
+ Utils::FilePath tmp = dir.pathAppended(maybeFileName);
+ if (tokenizedLine.first() == "singleton")
+ node->singletons.push_back(tmp);
+ }
+ }
+
+ f.close();
+}
+
+CMakeGenerator::NodePtr CMakeGenerator::findModuleFor(const NodePtr &node) const
+{
+ NodePtr current = node;
+ while (current->parent) {
+ if (current->module)
+ return current;
+
+ current = current->parent;
+ }
+ return nullptr;
+}
+
+CMakeGenerator::NodePtr CMakeGenerator::findNode(NodePtr &node, const Utils::FilePath &path) const
+{
+ const Utils::FilePath parentDir = path.parentDir();
+ for (NodePtr &child : node->subdirs) {
+ if (child->dir == parentDir)
+ return child;
+ if (path.isChildOf(child->dir))
+ return findNode(child, path);
+ }
+ return nullptr;
+}
+
+CMakeGenerator::NodePtr CMakeGenerator::findOrCreateNode(NodePtr &node,
+ const Utils::FilePath &path) const
+{
+ if (auto found = findNode(node, path))
+ return found;
+
+ if (!path.isChildOf(node->dir))
+ return nullptr;
+
+ const Utils::FilePath parentDir = path.parentDir();
+ const Utils::FilePath relative = parentDir.relativeChildPath(node->dir);
+ const QChar separator = relative.pathComponentSeparator();
+ const QList<QStringView> components = relative.pathView().split(separator);
+
+ NodePtr last = node;
+ for (const auto &comp : components) {
+ NodePtr newNode = std::make_shared<Node>();
+ newNode->parent = last;
+ newNode->name = comp.toString();
+ newNode->dir = last->dir.pathAppended(comp.toString());
+ last->subdirs.push_back(newNode);
+ last = newNode;
+ }
+ return last;
+}
+
+void CMakeGenerator::insertFile(NodePtr &node, const Utils::FilePath &path) const
+{
+ if (path.fileName() == "qmldir") {
+ readQmlDir(path, node);
+ } else if (path.suffix() == "qml" || path.suffix() == "ui.qml") {
+ node->files.push_back(path);
+ } else if (path.suffix() == "cpp") {
+ node->sources.push_back(path);
+ } else if (isResource(path)) {
+ node->resources.push_back(path);
+ }
+}
+
+void CMakeGenerator::removeFile(NodePtr &node, const Utils::FilePath &path) const
+{
+ if (path.fileName() == "qmldir") {
+ node->module = false;
+ node->singletons.clear();
+ node->uri = "";
+ node->name = path.parentDir().fileName();
+
+ } else if (path.suffix() == "qml") {
+ auto iter = std::find(node->files.begin(), node->files.end(), path);
+ if (iter != node->files.end())
+ node->files.erase(iter);
+ } else if (isResource(path)) {
+ auto iter = std::find(node->resources.begin(), node->resources.end(), path);
+ if (iter != node->resources.end())
+ node->resources.erase(iter);
+ }
+}
+
+bool CMakeGenerator::hasChildModule(const NodePtr &node) const
+{
+ for (const NodePtr &child : node->subdirs) {
+ if (child->module)
+ return true;
+ if (hasChildModule(child))
+ return true;
+ }
+ return false;
+}
+
+bool CMakeGenerator::isResource(const Utils::FilePath &path) const
+{
+ static const QStringList suffixes = {
+ "json", "mesh", "dae", "qad", "hints", "png", "hdr", "ttf", "jpg",
+ "JPG", "js", "qsb", "frag", "frag.qsb", "vert", "vert.qsb", "svg", "ktx"};
+ return suffixes.contains(path.suffix());
+}
+
+void CMakeGenerator::printNodeTree(const NodePtr &generatorNode, size_t indent) const
+{
+ auto addIndent = [](size_t level) -> QString {
+ QString str;
+ for (size_t i = 0; i < level; ++i)
+ str += " ";
+ return str;
+ };
+
+ qDebug() << addIndent(indent) << "GeneratorNode: " << generatorNode->name;
+ qDebug() << addIndent(indent) << "directory: " << generatorNode->dir;
+ qDebug() << addIndent(indent) << "files: " << generatorNode->files;
+ qDebug() << addIndent(indent) << "singletons: " << generatorNode->singletons;
+ qDebug() << addIndent(indent) << "resources: " << generatorNode->resources;
+ qDebug() << addIndent(indent) << "sources: " << generatorNode->sources;
+
+ for (const auto &child : generatorNode->subdirs)
+ printNodeTree(child, indent + 1);
+}
+
+void CMakeGenerator::parseNodeTree(NodePtr &generatorNode,
+ const ProjectExplorer::FolderNode *folderNode)
+{
+ for (const auto *childNode : folderNode->nodes()) {
+ if (const auto *subFolderNode = childNode->asFolderNode()) {
+ CMakeGenerator::NodePtr childGeneratorNode = std::make_shared<Node>();
+ childGeneratorNode->parent = generatorNode;
+ childGeneratorNode->name = subFolderNode->displayName();
+ childGeneratorNode->dir = subFolderNode->filePath();
+ parseNodeTree(childGeneratorNode, subFolderNode);
+ generatorNode->subdirs.push_back(childGeneratorNode);
+ } else if (auto *fileNode = childNode->asFileNode()) {
+ insertFile(generatorNode, fileNode->filePath());
+ }
+ }
+
+ if (generatorNode->name == "content")
+ generatorNode->module = true;
+
+ if (generatorNode->module)
+ m_moduleNames.push_back(generatorNode->name);
+}
+
+void CMakeGenerator::parseSourceTree()
+{
+ m_srcs.clear();
+ const QString srcDir = m_root->dir.pathAppended(Constants::DIRNAME_CPP).path();
+ QDirIterator it(srcDir, QStringList({"*.cpp"}), QDir::Files, QDirIterator::Subdirectories);
+ while (it.hasNext()) {
+ QString relative = Utils::FilePath::calcRelativePath(it.next(), m_root->dir.path());
+ m_srcs.push_back(relative);
+ }
+
+ if (m_srcs.empty())
+ m_srcs.push_back("src/main.cpp");
+}
+
+} // namespace GenerateCmake
+} // namespace QmlProjectManager
diff --git a/src/plugins/qmlprojectmanager/cmakegen/cmakegenerator.h b/src/plugins/qmlprojectmanager/cmakegen/cmakegenerator.h
new file mode 100644
index 0000000000..54445d3561
--- /dev/null
+++ b/src/plugins/qmlprojectmanager/cmakegen/cmakegenerator.h
@@ -0,0 +1,101 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+#pragma once
+
+#include "utils/filepath.h"
+
+#include <QObject>
+
+namespace ProjectExplorer {
+class FolderNode;
+}
+
+namespace QmlProjectManager {
+
+class QmlProject;
+class QmlBuildSystem;
+
+namespace GenerateCmake {
+
+// TODO:
+// - Create "module" for src dir
+// - Replace AppName in templates with ${CMAKE_PROJECT_NAME}
+// - Introduce Blacklist (designer)
+
+class CMakeGenerator : public QObject
+{
+ Q_OBJECT
+
+public:
+ CMakeGenerator(QmlBuildSystem *bs, QObject *parent = nullptr);
+
+ void setEnabled(bool enabled);
+
+ void initialize(QmlProject *project);
+
+ void update(const QSet<QString> &added, const QSet<QString> &removed);
+
+private:
+ struct Node
+ {
+ std::shared_ptr<Node> parent = nullptr;
+ bool module = false;
+
+ QString uri;
+ QString name;
+ Utils::FilePath dir;
+
+ std::vector<std::shared_ptr<Node>> subdirs;
+ std::vector<Utils::FilePath> files;
+ std::vector<Utils::FilePath> singletons;
+ std::vector<Utils::FilePath> resources;
+ std::vector<Utils::FilePath> sources;
+ };
+
+ using NodePtr = std::shared_ptr<Node>;
+
+ std::vector<Utils::FilePath> qmlFiles(const NodePtr &node) const;
+ std::vector<Utils::FilePath> singletons(const NodePtr &node) const;
+ std::vector<Utils::FilePath> resources(const NodePtr &node) const;
+ std::vector<Utils::FilePath> sources(const NodePtr &node) const;
+
+ void createCMakeFiles(const NodePtr &node) const;
+
+ void createQmlModuleFile(const NodePtr &node) const;
+ void createMainCMakeFile(const NodePtr &node) const;
+ void createModuleCMakeFile(const NodePtr &node) const;
+
+ void createEntryPoints(const NodePtr &node) const;
+ void createMainCppFile(const NodePtr &node) const;
+ void writeFile(const Utils::FilePath &path, const QString &content) const;
+
+ QString makeEnvironmentVariable(const QString &key) const;
+
+ QString readTemplate(const QString &templatePath) const;
+ void readQmlDir(const Utils::FilePath &filePath, NodePtr &node) const;
+
+ NodePtr findModuleFor(const NodePtr &node) const;
+ NodePtr findNode(NodePtr &node, const Utils::FilePath &path) const;
+ NodePtr findOrCreateNode(NodePtr &node, const Utils::FilePath &path) const;
+
+ void insertFile(NodePtr &node, const Utils::FilePath &path) const;
+ void removeFile(NodePtr &node, const Utils::FilePath &path) const;
+
+ bool hasChildModule(const NodePtr &node) const;
+ bool isResource(const Utils::FilePath &path) const;
+
+ void printNodeTree(const NodePtr &generatorNode, size_t indent = 0) const;
+
+ void parseNodeTree(NodePtr &generatorNode, const ProjectExplorer::FolderNode *folderNode);
+ void parseSourceTree();
+
+ bool m_enabled = false;
+ QString m_projectName = {};
+ NodePtr m_root = {};
+ QStringList m_srcs = {};
+ std::vector<QString> m_moduleNames = {};
+ QmlBuildSystem *m_buildSystem = nullptr;
+};
+
+} // namespace GenerateCmake
+} // namespace QmlProjectManager
diff --git a/src/plugins/qmlprojectmanager/cmakegen/gencmakeheadercomponents.tpl b/src/plugins/qmlprojectmanager/cmakegen/gencmakeheadercomponents.tpl
new file mode 100644
index 0000000000..167481d7c7
--- /dev/null
+++ b/src/plugins/qmlprojectmanager/cmakegen/gencmakeheadercomponents.tpl
@@ -0,0 +1,19 @@
+/*
+ * This file is automatically generated by Qt Design Studio.
+ * Do not change.
+*/
+
+#include "qqmlextensionplugin.h"
+
+#ifdef BUILD_QDS_COMPONENTS
+
+Q_IMPORT_QML_PLUGIN(QtQuick_Studio_ComponentsPlugin)
+Q_IMPORT_QML_PLUGIN(QtQuick_Studio_EffectsPlugin)
+Q_IMPORT_QML_PLUGIN(QtQuick_Studio_ApplicationPlugin)
+Q_IMPORT_QML_PLUGIN(FlowViewPlugin)
+Q_IMPORT_QML_PLUGIN(QtQuick_Studio_LogicHelperPlugin)
+Q_IMPORT_QML_PLUGIN(QtQuick_Studio_MultiTextPlugin)
+Q_IMPORT_QML_PLUGIN(QtQuick_Studio_EventSimulatorPlugin)
+Q_IMPORT_QML_PLUGIN(QtQuick_Studio_EventSystemPlugin)
+
+#endif
diff --git a/src/plugins/qmlprojectmanager/cmakegen/gencmakemodule.tpl b/src/plugins/qmlprojectmanager/cmakegen/gencmakemodule.tpl
new file mode 100644
index 0000000000..7c4b38b043
--- /dev/null
+++ b/src/plugins/qmlprojectmanager/cmakegen/gencmakemodule.tpl
@@ -0,0 +1,14 @@
+### This file is automatically generated by Qt Design Studio.
+### Do not change
+
+%1
+
+qt_add_library(%2 STATIC)
+qt6_add_qml_module(%2
+ URI "%3"
+ VERSION 1.0
+ RESOURCE_PREFIX "/qt/qml"
+%4
+)
+
+%5
diff --git a/src/plugins/qmlprojectmanager/cmakegen/gencmakeroot.tpl b/src/plugins/qmlprojectmanager/cmakegen/gencmakeroot.tpl
new file mode 100644
index 0000000000..0b8553d195
--- /dev/null
+++ b/src/plugins/qmlprojectmanager/cmakegen/gencmakeroot.tpl
@@ -0,0 +1,52 @@
+cmake_minimum_required(VERSION 3.21.1)
+
+option(LINK_INSIGHT "Link Qt Insight Tracker library" ON)
+option(BUILD_QDS_COMPONENTS "Build design studio components" ON)
+
+project(%1 LANGUAGES CXX)
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+set(QT_QML_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/qml)
+set(QML_IMPORT_PATH ${QT_QML_OUTPUT_DIRECTORY}
+ CACHE STRING "Import paths for Qt Creator's code model"
+ FORCE
+)
+
+find_package(Qt6 6.2 REQUIRED COMPONENTS Core Gui Qml Quick)
+
+if (Qt6_VERSION VERSION_GREATER_EQUAL 6.3)
+ qt_standard_project_setup()
+endif()
+
+qt_add_executable(%1 %2)
+
+qt_add_resources(%1 "configuration"
+ PREFIX "/"
+%3
+)
+
+target_link_libraries(%1 PRIVATE
+ Qt${QT_VERSION_MAJOR}::Core
+ Qt${QT_VERSION_MAJOR}::Gui
+ Qt${QT_VERSION_MAJOR}::Quick
+ Qt${QT_VERSION_MAJOR}::Qml
+)
+
+if (BUILD_QDS_COMPONENTS)
+ include(${CMAKE_CURRENT_SOURCE_DIR}/qmlcomponents OPTIONAL)
+endif()
+
+include(${CMAKE_CURRENT_SOURCE_DIR}/qmlmodules)
+
+if (LINK_INSIGHT)
+ include(${CMAKE_CURRENT_SOURCE_DIR}/insight OPTIONAL)
+endif ()
+
+include(GNUInstallDirs)
+install(TARGETS %1
+ BUNDLE DESTINATION .
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+)
+
diff --git a/tests/unit/tests/unittests/qmlprojectmanager/data/converter/test-set-1/testfile.jsontoqml b/tests/unit/tests/unittests/qmlprojectmanager/data/converter/test-set-1/testfile.jsontoqml
index 2a67b12d50..90c980cda1 100644
--- a/tests/unit/tests/unittests/qmlprojectmanager/data/converter/test-set-1/testfile.jsontoqml
+++ b/tests/unit/tests/unittests/qmlprojectmanager/data/converter/test-set-1/testfile.jsontoqml
@@ -7,6 +7,7 @@ Project {
mainFile: "content/App.qml"
mainUiFile: "content/Screen01.ui.qml"
targetDirectory: "/opt/UntitledProject13"
+ enableCMakeGeneration: false
widgetApp: true
importPaths: [ "imports","asset_imports" ]
diff --git a/tests/unit/tests/unittests/qmlprojectmanager/data/converter/test-set-1/testfile.qmlproject b/tests/unit/tests/unittests/qmlprojectmanager/data/converter/test-set-1/testfile.qmlproject
index 260938164a..cb0ca5f9e1 100644
--- a/tests/unit/tests/unittests/qmlprojectmanager/data/converter/test-set-1/testfile.qmlproject
+++ b/tests/unit/tests/unittests/qmlprojectmanager/data/converter/test-set-1/testfile.qmlproject
@@ -90,6 +90,8 @@ Project {
/* Required for deployment */
targetDirectory: "/opt/UntitledProject13"
+ enableCMakeGeneration: false
+
qdsVersion: "4.0"
quickVersion: "6.2"
diff --git a/tests/unit/tests/unittests/qmlprojectmanager/data/converter/test-set-1/testfile.qmltojson b/tests/unit/tests/unittests/qmlprojectmanager/data/converter/test-set-1/testfile.qmltojson
index c4475af39c..815e9a0cc5 100644
--- a/tests/unit/tests/unittests/qmlprojectmanager/data/converter/test-set-1/testfile.qmltojson
+++ b/tests/unit/tests/unittests/qmlprojectmanager/data/converter/test-set-1/testfile.qmltojson
@@ -1,5 +1,6 @@
{
"deployment": {
+ "enableCMakeGeneration": false,
"targetDirectory": "/opt/UntitledProject13"
},
"environment": {
diff --git a/tests/unit/tests/unittests/qmlprojectmanager/data/converter/test-set-2/testfile.jsontoqml b/tests/unit/tests/unittests/qmlprojectmanager/data/converter/test-set-2/testfile.jsontoqml
index 5878bdafc7..16617e015d 100644
--- a/tests/unit/tests/unittests/qmlprojectmanager/data/converter/test-set-2/testfile.jsontoqml
+++ b/tests/unit/tests/unittests/qmlprojectmanager/data/converter/test-set-2/testfile.jsontoqml
@@ -6,6 +6,7 @@ import QmlProject
Project {
mainFile: "fileSelectors.qml"
targetDirectory: "/opt/fileSelectors"
+ enableCMakeGeneration: false
widgetApp: false
importPaths: [ "imports" ]
diff --git a/tests/unit/tests/unittests/qmlprojectmanager/data/converter/test-set-2/testfile.qmlproject b/tests/unit/tests/unittests/qmlprojectmanager/data/converter/test-set-2/testfile.qmlproject
index 3ceeda651a..29bc108e68 100644
--- a/tests/unit/tests/unittests/qmlprojectmanager/data/converter/test-set-2/testfile.qmlproject
+++ b/tests/unit/tests/unittests/qmlprojectmanager/data/converter/test-set-2/testfile.qmlproject
@@ -44,4 +44,6 @@ Project {
/* Required for deployment */
targetDirectory: "/opt/fileSelectors"
+
+ enableCMakeGeneration: false
}
diff --git a/tests/unit/tests/unittests/qmlprojectmanager/data/converter/test-set-2/testfile.qmltojson b/tests/unit/tests/unittests/qmlprojectmanager/data/converter/test-set-2/testfile.qmltojson
index a26e0fc160..2231f36ff2 100644
--- a/tests/unit/tests/unittests/qmlprojectmanager/data/converter/test-set-2/testfile.qmltojson
+++ b/tests/unit/tests/unittests/qmlprojectmanager/data/converter/test-set-2/testfile.qmltojson
@@ -1,5 +1,6 @@
{
"deployment": {
+ "enableCMakeGeneration": false,
"targetDirectory": "/opt/fileSelectors"
},
"environment": {
diff --git a/tests/unit/tests/unittests/qmlprojectmanager/data/converter/test-set-3/testfile.jsontoqml b/tests/unit/tests/unittests/qmlprojectmanager/data/converter/test-set-3/testfile.jsontoqml
index 2a67b12d50..90c980cda1 100644
--- a/tests/unit/tests/unittests/qmlprojectmanager/data/converter/test-set-3/testfile.jsontoqml
+++ b/tests/unit/tests/unittests/qmlprojectmanager/data/converter/test-set-3/testfile.jsontoqml
@@ -7,6 +7,7 @@ Project {
mainFile: "content/App.qml"
mainUiFile: "content/Screen01.ui.qml"
targetDirectory: "/opt/UntitledProject13"
+ enableCMakeGeneration: false
widgetApp: true
importPaths: [ "imports","asset_imports" ]
diff --git a/tests/unit/tests/unittests/qmlprojectmanager/data/converter/test-set-3/testfile.qmlproject b/tests/unit/tests/unittests/qmlprojectmanager/data/converter/test-set-3/testfile.qmlproject
index 1ec43b95d5..faf115d609 100644
--- a/tests/unit/tests/unittests/qmlprojectmanager/data/converter/test-set-3/testfile.qmlproject
+++ b/tests/unit/tests/unittests/qmlprojectmanager/data/converter/test-set-3/testfile.qmlproject
@@ -90,6 +90,8 @@ Project {
/* Required for deployment */
QDS.targetDirectory: "/opt/UntitledProject13"
+ QDS.enableCMakeGeneration: false
+
QDS.qdsVersion: "4.0"
QDS.quickVersion: "6.2"
diff --git a/tests/unit/tests/unittests/qmlprojectmanager/data/converter/test-set-3/testfile.qmltojson b/tests/unit/tests/unittests/qmlprojectmanager/data/converter/test-set-3/testfile.qmltojson
index c4475af39c..815e9a0cc5 100644
--- a/tests/unit/tests/unittests/qmlprojectmanager/data/converter/test-set-3/testfile.qmltojson
+++ b/tests/unit/tests/unittests/qmlprojectmanager/data/converter/test-set-3/testfile.qmltojson
@@ -1,5 +1,6 @@
{
"deployment": {
+ "enableCMakeGeneration": false,
"targetDirectory": "/opt/UntitledProject13"
},
"environment": {
diff --git a/tests/unit/tests/unittests/qmlprojectmanager/data/converter/test-set-mcu-1/testfile.jsontoqml b/tests/unit/tests/unittests/qmlprojectmanager/data/converter/test-set-mcu-1/testfile.jsontoqml
index 99e4f60bb3..04911c40f8 100644
--- a/tests/unit/tests/unittests/qmlprojectmanager/data/converter/test-set-mcu-1/testfile.jsontoqml
+++ b/tests/unit/tests/unittests/qmlprojectmanager/data/converter/test-set-mcu-1/testfile.jsontoqml
@@ -6,6 +6,7 @@ import QmlProject
Project {
mainFile: "Main.qml"
targetDirectory: "/opt/UntitledProject13"
+ enableCMakeGeneration: false
widgetApp: true
importPaths: [ "imports","asset_imports" ]
diff --git a/tests/unit/tests/unittests/qmlprojectmanager/data/converter/test-set-mcu-2/testfile.jsontoqml b/tests/unit/tests/unittests/qmlprojectmanager/data/converter/test-set-mcu-2/testfile.jsontoqml
index 2e73146cda..ad0102201f 100644
--- a/tests/unit/tests/unittests/qmlprojectmanager/data/converter/test-set-mcu-2/testfile.jsontoqml
+++ b/tests/unit/tests/unittests/qmlprojectmanager/data/converter/test-set-mcu-2/testfile.jsontoqml
@@ -4,6 +4,7 @@
import QmlProject
Project {
+ enableCMakeGeneration: false
widgetApp: false
qt6Project: false
diff --git a/tests/unit/tests/unittests/qmlprojectmanager/data/getter-setter/empty.qmlproject b/tests/unit/tests/unittests/qmlprojectmanager/data/getter-setter/empty.qmlproject
index 66adaaa7d9..bcf8995b7a 100644
--- a/tests/unit/tests/unittests/qmlprojectmanager/data/getter-setter/empty.qmlproject
+++ b/tests/unit/tests/unittests/qmlprojectmanager/data/getter-setter/empty.qmlproject
@@ -11,6 +11,7 @@ Project {
importPaths: [ ]
targetDirectory: ""
+ enableCMakeGeneration: false
fileSelectors: [ ]
qdsVersion: ""
diff --git a/tests/unit/tests/unittests/qmlprojectmanager/data/getter-setter/with_qds_prefix.qmlproject b/tests/unit/tests/unittests/qmlprojectmanager/data/getter-setter/with_qds_prefix.qmlproject
index a8b5b459d6..6422179e66 100644
--- a/tests/unit/tests/unittests/qmlprojectmanager/data/getter-setter/with_qds_prefix.qmlproject
+++ b/tests/unit/tests/unittests/qmlprojectmanager/data/getter-setter/with_qds_prefix.qmlproject
@@ -11,6 +11,7 @@ Project {
QDS.importPaths: [ "imports", "asset_imports" ]
QDS.targetDirectory: "/opt/targetDirectory"
+ QDS.enableCMakeGeneration: true
QDS.fileSelectors: [ "WXGA", "darkTheme", "ShowIndicator"]
QDS.qdsVersion: "3.9"
diff --git a/tests/unit/tests/unittests/qmlprojectmanager/data/getter-setter/without_qds_prefix.qmlproject b/tests/unit/tests/unittests/qmlprojectmanager/data/getter-setter/without_qds_prefix.qmlproject
index 6bee599955..77b5556893 100644
--- a/tests/unit/tests/unittests/qmlprojectmanager/data/getter-setter/without_qds_prefix.qmlproject
+++ b/tests/unit/tests/unittests/qmlprojectmanager/data/getter-setter/without_qds_prefix.qmlproject
@@ -11,6 +11,7 @@ Project {
importPaths: [ "imports", "asset_imports" ]
targetDirectory: "/opt/targetDirectory"
+ enableCMakeGeneration: true
fileSelectors: [ "WXGA", "darkTheme", "ShowIndicator"]
qdsVersion: "3.9"
diff --git a/tests/unit/tests/unittests/qmlprojectmanager/projectitem-test.cpp b/tests/unit/tests/unittests/qmlprojectmanager/projectitem-test.cpp
index 49caf96074..1e1d7d1189 100644
--- a/tests/unit/tests/unittests/qmlprojectmanager/projectitem-test.cpp
+++ b/tests/unit/tests/unittests/qmlprojectmanager/projectitem-test.cpp
@@ -121,6 +121,13 @@ TEST_F(QmlProjectItem, get_with_qds_prefix_tar_get_with_qds_prefix_directory)
ASSERT_THAT(targetDirectory, Eq("/opt/targetDirectory"));
}
+TEST_F(QmlProjectItem, get_with_qds_prefix_enable_cmake_generation)
+{
+ auto enable = projectItemWithQdsPrefix->enableCMakeGeneration();
+
+ ASSERT_TRUE(enable);
+}
+
TEST_F(QmlProjectItem, get_with_qds_prefix_import_paths)
{
auto importPaths = projectItemWithQdsPrefix->importPaths();
@@ -266,6 +273,13 @@ TEST_F(QmlProjectItem, get_without_qds_prefix_tar_get_without_qds_prefix_directo
ASSERT_THAT(targetDirectory, Eq("/opt/targetDirectory"));
}
+TEST_F(QmlProjectItem, get_without_qds_prefix_enable_cmake_generation)
+{
+ auto enable = projectItemWithoutQdsPrefix->enableCMakeGeneration();
+
+ ASSERT_TRUE(enable);
+}
+
TEST_F(QmlProjectItem, get_without_qds_prefix_import_paths)
{
auto importPaths = projectItemWithoutQdsPrefix->importPaths();
@@ -413,6 +427,13 @@ TEST_F(QmlProjectItem, get_empty_tar_get_empty_directory)
ASSERT_THAT(targetDirectory, IsEmpty());
}
+TEST_F(QmlProjectItem, get_empty_enable_cmake_generation)
+{
+ auto enable = projectItemEmpty->enableCMakeGeneration();
+
+ ASSERT_FALSE(enable);
+}
+
TEST_F(QmlProjectItem, get_empty_import_paths)
{
auto importPaths = projectItemEmpty->importPaths();
@@ -677,6 +698,13 @@ TEST_F(QmlProjectItem, set_design_studio_version)
ASSERT_EQ(projectItemSetters->versionDesignStudio(), "6");
}
+TEST_F(QmlProjectItem, set_enable_cmake_generation)
+{
+ projectItemSetters->setEnableCMakeGeneration(true);
+
+ ASSERT_EQ(projectItemSetters->enableCMakeGeneration(), true);
+}
+
// TODO: We should move these 2 tests into the integration tests
TEST_F(QmlProjectItem, test_file_filters)
{