aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/qmlprojectmanager
diff options
context:
space:
mode:
authorTim Jenssen <tim.jenssen@qt.io>2023-11-16 17:17:46 +0100
committerTim Jenssen <tim.jenssen@qt.io>2023-11-16 17:17:46 +0100
commit9f1d23df00443d600abec93f4ce5e82b679ac6e0 (patch)
tree7e977f277baee0c441d60c4b78d90534985c9900 /src/plugins/qmlprojectmanager
parent3a5e0299c07184fa416295ca576806d12e581ab4 (diff)
parent245bd90a6e53421eafae6c8dfe4d71949f387eab (diff)
Merge remote-tracking branch 'origin/qds/dev'
Diffstat (limited to 'src/plugins/qmlprojectmanager')
-rw-r--r--src/plugins/qmlprojectmanager/buildsystem/projectitem/converters.cpp403
-rw-r--r--src/plugins/qmlprojectmanager/buildsystem/projectitem/qmlprojectitem.cpp51
-rw-r--r--src/plugins/qmlprojectmanager/cmakegen/qmlprojectmaincmakelists.tpl9
3 files changed, 278 insertions, 185 deletions
diff --git a/src/plugins/qmlprojectmanager/buildsystem/projectitem/converters.cpp b/src/plugins/qmlprojectmanager/buildsystem/projectitem/converters.cpp
index c77189a8b6c..5cafae5660f 100644
--- a/src/plugins/qmlprojectmanager/buildsystem/projectitem/converters.cpp
+++ b/src/plugins/qmlprojectmanager/buildsystem/projectitem/converters.cpp
@@ -3,28 +3,20 @@
#include "converters.h"
-#include <QJsonArray>
+#include <QJsonDocument>
namespace QmlProjectManager::Converters {
-using PropsPair = QPair<QString, QStringList>;
-struct FileProps
-{
- const PropsPair image{"image",
- QStringList{"*.jpeg", "*.jpg", "*.png", "*.svg", "*.hdr", ".ktx"}};
- const PropsPair qml{"qml", QStringList{"*.qml"}};
- const PropsPair qmlDir{"qmldir", QStringList{"qmldir"}};
- const PropsPair javaScr{"javaScript", QStringList{"*.js", "*.ts"}};
- const PropsPair video{"video", QStringList{"*.mp4"}};
- const PropsPair sound{"sound", QStringList{"*.mp3", "*.wav"}};
- const PropsPair font{"font", QStringList{"*.ttf", "*.otf"}};
- const PropsPair config{"config", QStringList{"*.conf"}};
- const PropsPair styling{"styling", QStringList{"*.css"}};
- const PropsPair mesh{"meshes", QStringList{"*.mesh"}};
- const PropsPair
- shader{"shader",
- QStringList{"*.glsl", "*.glslv", "*.glslf", "*.vsh", "*.fsh", "*.vert", "*.frag"}};
-};
+const static QStringList qmlFilesFilter{QStringLiteral("*.qml")};
+const static QStringList javaScriptFilesFilter{QStringLiteral("*.js"), QStringLiteral("*.ts")};
+const static QStringList imageFilesFilter{QStringLiteral("*.jpeg"),
+ QStringLiteral("*.jpg"),
+ QStringLiteral("*.png"),
+ QStringLiteral("*.svg"),
+ QStringLiteral("*.hdr"),
+ QStringLiteral("*.ktx")};
+
+QString jsonValueToString(const QJsonValue &val, int indentationLevel, bool indented);
QString jsonToQmlProject(const QJsonObject &rootObject)
{
@@ -37,7 +29,12 @@ QString jsonToQmlProject(const QJsonObject &rootObject)
QJsonObject versionConfig = rootObject["versions"].toObject();
QJsonObject environmentConfig = rootObject["environment"].toObject();
QJsonObject deploymentConfig = rootObject["deployment"].toObject();
- QJsonObject filesConfig = rootObject["fileGroups"].toObject();
+ QJsonArray filesConfig = rootObject["fileGroups"].toArray();
+ QJsonObject otherProperties = rootObject["otherProperties"].toObject();
+
+ QJsonObject mcuObject = rootObject["mcu"].toObject();
+ QJsonObject mcuConfig = mcuObject["config"].toObject();
+ QJsonObject mcuModule = mcuObject["module"].toObject();
int indentationLevel = 0;
@@ -54,6 +51,8 @@ QString jsonToQmlProject(const QJsonObject &rootObject)
};
auto appendString = [&appendItem](const QString &key, const QString &val) {
+ if (val.isEmpty())
+ return;
appendItem(key, val, true);
};
@@ -61,15 +60,39 @@ QString jsonToQmlProject(const QJsonObject &rootObject)
appendItem(key, QString::fromStdString(val ? "true" : "false"), false);
};
- auto appendArray = [&appendItem](const QString &key, const QStringList &vals) {
+ auto appendStringArray = [&appendItem](const QString &key, const QStringList &vals) {
+ if (vals.isEmpty())
+ return;
QString finalString;
for (const QString &value : vals)
finalString.append("\"").append(value).append("\"").append(",");
+
finalString.remove(finalString.length() - 1, 1);
finalString.prepend("[ ").append(" ]");
appendItem(key, finalString, false);
};
+ auto appendJsonArray = [&appendItem, &indentationLevel](const QString &key,
+ const QJsonArray &vals) {
+ if (vals.isEmpty())
+ return;
+ appendItem(key, jsonValueToString(vals, indentationLevel, /*indented*/ true), false);
+ };
+
+ auto appendProperties = [&appendItem, &indentationLevel](const QJsonObject &props,
+ const QString &prefix) {
+ for (const auto &key : props.keys()) {
+ QJsonValue val = props[key];
+ QString keyWithPrefix = key;
+ if (!prefix.isEmpty()) {
+ keyWithPrefix.prepend(prefix + ".");
+ }
+ appendItem(keyWithPrefix,
+ jsonValueToString(val, indentationLevel, /*indented*/ false),
+ false);
+ }
+ };
+
auto startObject = [&ts, &indentationLevel](const QString &objectName) {
ts << Qt::endl
<< QString(" ").repeated(indentationLevel * 4) << objectName << " {" << Qt::endl;
@@ -81,42 +104,31 @@ QString jsonToQmlProject(const QJsonObject &rootObject)
ts << QString(" ").repeated(indentationLevel * 4) << "}" << Qt::endl;
};
- auto appendDirectories =
- [&startObject, &endObject, &appendString, &filesConfig](const QString &jsonKey,
- const QString &qmlKey) {
- QJsonValue dirsObj = filesConfig[jsonKey].toObject()["directories"];
- const QStringList dirs = dirsObj.toVariant().toStringList();
- for (const QString &directory : dirs) {
- startObject(qmlKey);
- appendString("directory", directory);
- endObject();
- }
- };
-
- auto appendFiles = [&startObject,
- &endObject,
- &appendString,
- &appendArray,
- &filesConfig](const QString &jsonKey, const QString &qmlKey) {
- QJsonValue dirsObj = filesConfig[jsonKey].toObject()["directories"];
- QJsonValue filesObj = filesConfig[jsonKey].toObject()["files"];
- QJsonValue filtersObj = filesConfig[jsonKey].toObject()["filters"];
-
- const QStringList directories = dirsObj.toVariant().toStringList();
- for (const QString &directory : directories) {
- startObject(qmlKey);
- appendString("directory", directory);
- appendString("filters", filtersObj.toVariant().toStringList().join(";"));
-
- if (!filesObj.toArray().isEmpty()) {
- QStringList fileList;
- const QJsonArray files = filesObj.toArray();
- for (const QJsonValue &file : files)
- fileList.append(file.toObject()["name"].toString());
- appendArray("files", fileList);
- }
- endObject();
+ auto appendFileGroup = [&startObject,
+ &endObject,
+ &appendString,
+ &appendProperties,
+ &appendJsonArray](const QJsonObject &fileGroup,
+ const QString &nodeName) {
+ startObject(nodeName);
+ appendString("directory", fileGroup["directory"].toString());
+ QStringList filters = fileGroup["filters"].toVariant().toStringList();
+ QStringList filter = {};
+ if (nodeName.toLower() == "qmlfiles") {
+ filter = qmlFilesFilter;
+ } else if (nodeName.toLower() == "imagefiles") {
+ filter = imageFilesFilter;
+ } else if (nodeName.toLower() == "javascriptfiles") {
+ filter = javaScriptFilesFilter;
}
+ for (const QString &entry : filter) {
+ filters.removeOne(entry);
+ }
+ appendString("filter", filters.join(";"));
+ appendJsonArray("files", fileGroup["files"].toArray());
+ appendProperties(fileGroup["mcuProperties"].toObject(), "MCU");
+ appendProperties(fileGroup["otherProperties"].toObject(), "");
+ endObject();
};
// start creating the file content
@@ -127,54 +139,78 @@ QString jsonToQmlProject(const QJsonObject &rootObject)
{
startObject("Project");
- { // append non-object props
- appendString("mainFile", runConfig["mainFile"].toString());
- appendString("mainUiFile", runConfig["mainUiFile"].toString());
- appendString("targetDirectory", deploymentConfig["targetDirectory"].toString());
- appendBool("widgetApp", runConfig["widgetApp"].toBool());
- appendArray("importPaths", rootObject["importPaths"].toVariant().toStringList());
- appendBreak();
- appendString("qdsVersion", versionConfig["designStudio"].toString());
- appendString("quickVersion", versionConfig["qtQuick"].toString());
- appendBool("qt6Project", versionConfig["qt"].toString() == "6");
- appendBool("qtForMCUs", !(rootObject["mcuConfig"].toObject().isEmpty()));
+ // append non-object props
+ appendString("mainFile", runConfig["mainFile"].toString());
+ appendString("mainUiFile", runConfig["mainUiFile"].toString());
+ appendString("targetDirectory", deploymentConfig["targetDirectory"].toString());
+ appendBool("widgetApp", runConfig["widgetApp"].toBool());
+ appendStringArray("importPaths", rootObject["importPaths"].toVariant().toStringList());
+ appendBreak();
+ appendString("qdsVersion", versionConfig["designStudio"].toString());
+ appendString("quickVersion", versionConfig["qtQuick"].toString());
+ appendBool("qt6Project", versionConfig["qt"].toString() == "6");
+ appendBool("qtForMCUs",
+ mcuObject["enabled"].toBool() || !mcuConfig.isEmpty() || !mcuModule.isEmpty());
+ if (!languageConfig.isEmpty()) {
appendBreak();
appendBool("multilanguageSupport", languageConfig["multiLanguageSupport"].toBool());
appendString("primaryLanguage", languageConfig["primaryLanguage"].toString());
- appendArray("supportedLanguages",
- languageConfig["supportedLanguages"].toVariant().toStringList());
+ appendStringArray("supportedLanguages",
+ languageConfig["supportedLanguages"].toVariant().toStringList());
}
- { // append Environment object
+ // Since different versions of Qt for MCUs may introduce new properties, we collect all
+ // unknown properties in a separate object.
+ // We need to avoid losing content regardless of which QDS/QUL version combo is used.
+ if (!otherProperties.isEmpty()) {
+ appendBreak();
+ appendProperties(otherProperties, "");
+ }
+
+ // append Environment object
+ if (!environmentConfig.isEmpty()) {
startObject("Environment");
- const QStringList keys = environmentConfig.keys();
- for (const QString &key : keys)
+ for (const QString &key : environmentConfig.keys()) {
appendItem(key, environmentConfig[key].toString(), true);
+ }
endObject();
}
- { // append ShaderTool object
- if (!shaderConfig["args"].toVariant().toStringList().isEmpty()) {
- startObject("ShaderTool");
- appendString("args",
- shaderConfig["args"].toVariant().toStringList().join(" ").replace(
- "\"", "\\\""));
- appendArray("files", shaderConfig["files"].toVariant().toStringList());
- endObject();
- }
+ // append ShaderTool object
+ if (!shaderConfig["args"].toVariant().toStringList().isEmpty()) {
+ startObject("ShaderTool");
+ appendString("args",
+ shaderConfig["args"].toVariant().toStringList().join(" ").replace("\"",
+ "\\\""));
+ appendStringArray("files", shaderConfig["files"].toVariant().toStringList());
+ endObject();
}
- { // append files objects
- appendDirectories("qml", "QmlFiles");
- appendDirectories("javaScript", "JavaScriptFiles");
- appendDirectories("image", "ImageFiles");
- appendFiles("config", "Files");
- appendFiles("font", "Files");
- appendFiles("meshes", "Files");
- appendFiles("qmldir", "Files");
- appendFiles("shader", "Files");
- appendFiles("sound", "Files");
- appendFiles("video", "Files");
+ // append the MCU.Config object
+ if (!mcuConfig.isEmpty()) {
+ // Append MCU.Config
+ startObject("MCU.Config");
+ appendProperties(mcuConfig, "");
+ endObject();
+ }
+
+ // Append the MCU.Module object
+ if (!mcuModule.isEmpty()) {
+ // Append MCU.Module
+ startObject("MCU.Module");
+ appendProperties(mcuModule, "");
+ endObject();
+ }
+
+ // append files objects
+ for (const QJsonValue &fileGroup : filesConfig) {
+ QString nodeType = QString("%1Files").arg(fileGroup["type"].toString());
+ if (fileGroup["type"].toString().isEmpty()
+ && fileGroup["filters"].toArray().contains("*.qml")) {
+ // TODO: IS this important? It turns Files node with *.qml in the filters into QmlFiles nodes
+ nodeType = "QmlFiles";
+ }
+ appendFileGroup(fileGroup.toObject(), nodeType);
}
endObject(); // Closing 'Project'
@@ -201,22 +237,27 @@ QJsonObject qmlProjectTojson(const Utils::FilePath &projectFile)
auto nodeToJsonObject = [](const QmlJS::SimpleReaderNode::Ptr &node) {
QJsonObject tObj;
- const QStringList childPropNames = node->propertyNames();
- for (const QString &childPropName : childPropNames)
+ for (const QString &childPropName : node->propertyNames())
tObj.insert(childPropName, node->property(childPropName).value.toJsonValue());
+
return tObj;
};
auto toCamelCase = [](const QString &s) { return QString(s).replace(0, 1, s[0].toLower()); };
QJsonObject rootObject; // root object
- QJsonObject fileGroupsObject;
+ QJsonArray fileGroupsObject;
QJsonObject languageObject;
QJsonObject versionObject;
QJsonObject runConfigObject;
QJsonObject deploymentObject;
QJsonObject mcuObject;
+ QJsonObject mcuConfigObject;
+ QJsonObject mcuModuleObject;
QJsonObject shaderToolObject;
+ QJsonObject otherProperties;
+
+ bool qtForMCUs = false;
// convert the non-object props
for (const QString &propName : rootNode->propertyNames()) {
@@ -224,10 +265,7 @@ QJsonObject qmlProjectTojson(const Utils::FilePath &projectFile)
QString objKey = QString(propName).remove("QDS.", Qt::CaseInsensitive);
QJsonValue value = rootNode->property(propName).value.toJsonValue();
- if (propName.startsWith("mcu.", Qt::CaseInsensitive)) {
- currentObj = &mcuObject;
- objKey = QString(propName).remove("MCU.");
- } else if (propName.contains("language", Qt::CaseInsensitive)) {
+ if (propName.contains("language", Qt::CaseInsensitive)) {
currentObj = &languageObject;
if (propName.contains("multilanguagesupport", Qt::CaseInsensitive))
// fixing the camelcase
@@ -247,12 +285,17 @@ QJsonObject qmlProjectTojson(const Utils::FilePath &projectFile)
} else if (propName.contains("targetdirectory", Qt::CaseInsensitive)) {
currentObj = &deploymentObject;
} else if (propName.contains("qtformcus", Qt::CaseInsensitive)) {
- currentObj = &mcuObject;
- objKey = "mcuEnabled";
+ qtForMCUs = value.toBool();
+ continue;
} else if (propName.contains("qt6project", Qt::CaseInsensitive)) {
currentObj = &versionObject;
objKey = "qt";
value = rootNode->property(propName).value.toBool() ? "6" : "5";
+ } else if (propName.contains("importpaths", Qt::CaseInsensitive)) {
+ objKey = "importPaths";
+ } else {
+ currentObj = &otherProperties;
+ objKey = propName; // With prefix
}
currentObj->insert(objKey, value);
@@ -267,85 +310,77 @@ QJsonObject qmlProjectTojson(const Utils::FilePath &projectFile)
versionObject.insert("qt", "5");
}
+ rootObject.insert("otherProperties", otherProperties);
+
// convert the object props
for (const QmlJS::SimpleReaderNode::Ptr &childNode : rootNode->children()) {
if (childNode->name().contains("files", Qt::CaseInsensitive)) {
- PropsPair propsPair;
- FileProps fileProps;
- const QString childNodeName = childNode->name().toLower().remove("qds.");
- const QmlJS::SimpleReaderNode::Property childNodeFilter = childNode->property("filter");
- const QmlJS::SimpleReaderNode::Property childNodeDirectory = childNode->property(
- "directory");
- const QmlJS::SimpleReaderNode::Property childNodeFiles = childNode->property("files");
- const QString childNodeFilterValue = childNodeFilter.value.toString();
-
- if (childNodeName == "qmlfiles" || childNodeFilterValue.contains("*.qml")) {
- propsPair = fileProps.qml;
- } else if (childNodeName == "javascriptfiles") {
- propsPair = fileProps.javaScr;
- } else if (childNodeName == "imagefiles") {
- propsPair = fileProps.image;
- } else {
- if (childNodeFilter.isValid()) {
- if (childNodeFilterValue.contains(".conf"))
- propsPair = fileProps.config;
- else if (childNodeFilterValue.contains(".ttf"))
- propsPair = fileProps.font;
- else if (childNodeFilterValue.contains("qmldir"))
- propsPair = fileProps.qmlDir;
- else if (childNodeFilterValue.contains(".wav"))
- propsPair = fileProps.sound;
- else if (childNodeFilterValue.contains(".mp4"))
- propsPair = fileProps.video;
- else if (childNodeFilterValue.contains(".mesh"))
- propsPair = fileProps.mesh;
- else if (childNodeFilterValue.contains(".glsl"))
- propsPair = fileProps.shader;
- else if (childNodeFilterValue.contains(".css"))
- propsPair = fileProps.styling;
+ QString childNodeName = childNode->name().remove("qds.", Qt::CaseInsensitive);
+ qsizetype filesPos = childNodeName.indexOf("files", 0, Qt::CaseInsensitive);
+ const QString childNodeType = childNodeName.first(filesPos);
+ childNodeName = childNodeName.toLower();
+
+ QJsonArray childNodeFiles = childNode->property("files").value.toJsonArray();
+ QString childNodeDirectory = childNode->property("directory").value.toString();
+ QStringList filters
+ = childNode->property("filter").value.toString().split(";", Qt::SkipEmptyParts);
+ QJsonArray childNodeFilters = QJsonArray::fromStringList(filters);
+
+ // files have priority over filters
+ // if explicit files are given, then filters will be ignored
+ // and all files are prefixed such as "directory/<filename>".
+ // if directory is empty, then the files are prefixed with the project directory
+ if (childNodeFiles.empty()) {
+ auto inserter = [&childNodeFilters](const QStringList &filterSource) {
+ std::for_each(filterSource.begin(),
+ filterSource.end(),
+ [&childNodeFilters](const auto &value) {
+ if (!childNodeFilters.contains(value)) {
+ childNodeFilters << value;
+ }
+ });
+ };
+
+ // Those 3 file groups are the special ones
+ // that have a default set of filters.
+ // The default filters are written to the
+ // qmlproject file after conversion
+ if (childNodeName == "qmlfiles") {
+ inserter(qmlFilesFilter);
+ } else if (childNodeName == "javascriptfiles") {
+ inserter(javaScriptFilesFilter);
+ } else if (childNodeName == "imagefiles") {
+ inserter(imageFilesFilter);
}
}
- // get all objects we'll work on
- QJsonObject targetObject = fileGroupsObject[propsPair.first].toObject();
- QJsonArray directories = targetObject["directories"].toArray();
- QJsonArray filters = targetObject["filters"].toArray();
- QJsonArray files = targetObject["files"].toArray();
+ // create the file group object
+ QJsonObject targetObject;
+ targetObject.insert("directory", childNodeDirectory);
+ targetObject.insert("filters", childNodeFilters);
+ targetObject.insert("files", childNodeFiles);
+ targetObject.insert("type", childNodeType);
+
+ QJsonObject mcuPropertiesObject;
+ QJsonObject otherPropertiesObject;
+ for (const auto &propName : childNode->propertyNames()) {
+ if (propName == "directory" || propName == "filter" || propName == "files") {
+ continue;
+ }
- // populate & update filters
- if (filters.isEmpty()) {
- filters = QJsonArray::fromStringList(
- propsPair.second); // populate the filters with the predefined ones
- }
+ auto val = QJsonValue::fromVariant(childNode->property(propName).value);
- if (childNodeFilter.isValid()) { // append filters from qmlproject (merge)
- const QStringList filtersFromProjectFile = childNodeFilterValue.split(";");
- for (const QString &filter : filtersFromProjectFile) {
- if (!filters.contains(QJsonValue(filter))) {
- filters.append(QJsonValue(filter));
- }
+ if (propName.startsWith("MCU.", Qt::CaseInsensitive)) {
+ mcuPropertiesObject.insert(propName.mid(4), val);
+ } else {
+ otherPropertiesObject.insert(propName, val);
}
}
- // populate & update directories
- if (childNodeDirectory.isValid()) {
- directories.append(childNodeDirectory.value.toJsonValue());
- }
- if (directories.isEmpty())
- directories.append(".");
-
- // populate & update files
- if (childNodeFiles.isValid()) {
- const QJsonArray fileList = childNodeFiles.value.toJsonArray();
- for (const QJsonValue &file : fileList)
- files.append(QJsonObject{{"name", file.toString()}});
- }
+ targetObject.insert("mcuProperties", mcuPropertiesObject);
+ targetObject.insert("otherProperties", otherPropertiesObject);
- // put everything back into the root object
- targetObject.insert("directories", directories);
- targetObject.insert("filters", filters);
- targetObject.insert("files", files);
- fileGroupsObject.insert(propsPair.first, targetObject);
+ fileGroupsObject.append(targetObject);
} else if (childNode->name().contains("shadertool", Qt::CaseInsensitive)) {
QStringList quotedArgs
= childNode->property("args").value.toString().split('\"', Qt::SkipEmptyParts);
@@ -361,21 +396,51 @@ QJsonObject qmlProjectTojson(const Utils::FilePath &projectFile)
shaderToolObject.insert("args", QJsonArray::fromStringList(args));
shaderToolObject.insert("files", childNode->property("files").value.toJsonValue());
+ } else if (childNode->name().contains("config", Qt::CaseInsensitive)) {
+ mcuConfigObject = nodeToJsonObject(childNode);
+ } else if (childNode->name().contains("module", Qt::CaseInsensitive)) {
+ mcuModuleObject = nodeToJsonObject(childNode);
} else {
rootObject.insert(toCamelCase(childNode->name().remove("qds.", Qt::CaseInsensitive)),
nodeToJsonObject(childNode));
}
}
+ mcuObject.insert("config", mcuConfigObject);
+ mcuObject.insert("module", mcuModuleObject);
+ qtForMCUs |= !(mcuModuleObject.isEmpty() && mcuConfigObject.isEmpty());
+ mcuObject.insert("enabled", qtForMCUs);
+
rootObject.insert("fileGroups", fileGroupsObject);
rootObject.insert("language", languageObject);
rootObject.insert("versions", versionObject);
rootObject.insert("runConfig", runConfigObject);
rootObject.insert("deployment", deploymentObject);
- rootObject.insert("mcuConfig", mcuObject);
+ rootObject.insert("mcu", mcuObject);
if (!shaderToolObject.isEmpty())
rootObject.insert("shaderTool", shaderToolObject);
rootObject.insert("fileVersion", 1);
return rootObject;
}
+
+QString jsonValueToString(const QJsonValue &val, int indentationLevel, bool indented)
+{
+ if (val.isArray()) {
+ auto jsonFormat = indented ? QJsonDocument::JsonFormat::Indented
+ : QJsonDocument::JsonFormat::Compact;
+ QString str = QString::fromUtf8((QJsonDocument(val.toArray()).toJson(jsonFormat)));
+ if (indented) {
+ // Strip trailing newline
+ str.chop(1);
+ }
+ return str.replace("\n", QString(" ").repeated(indentationLevel * 4).prepend("\n"));
+ } else if (val.isBool()) {
+ return val.toBool() ? QString("true") : QString("false");
+ } else if (val.isDouble()) {
+ return QString("%1").arg(val.toDouble());
+ } else {
+ return val.toString().prepend("\"").append("\"");
+ }
+}
+
} // namespace QmlProjectManager::Converters
diff --git a/src/plugins/qmlprojectmanager/buildsystem/projectitem/qmlprojectitem.cpp b/src/plugins/qmlprojectmanager/buildsystem/projectitem/qmlprojectitem.cpp
index 2761caff089..38f27fbc101 100644
--- a/src/plugins/qmlprojectmanager/buildsystem/projectitem/qmlprojectitem.cpp
+++ b/src/plugins/qmlprojectmanager/buildsystem/projectitem/qmlprojectitem.cpp
@@ -65,19 +65,15 @@ bool QmlProjectItem::initProjectObject()
void QmlProjectItem::setupFileFilters()
{
auto setupFileFilterItem = [this](const QJsonObject &fileGroup) {
- for (const QString &directory : fileGroup["directories"].toVariant().toStringList()) {
+ // first we need to add all directories as a 'resource' path for the project and set them as
+ // recursive.
+ // if there're any files with the explicit absolute paths, we need to add them afterwards.
+ for (const QString &directory : fileGroup["directory"].toVariant().toStringList()) {
std::unique_ptr<FileFilterItem> fileFilterItem{new FileFilterItem};
-
- QStringList filesArr;
- for (const QJsonValue &file : fileGroup["files"].toArray()) {
- filesArr.append(file["name"].toString());
- }
-
fileFilterItem->setDirectory(directory);
fileFilterItem->setFilters(fileGroup["filters"].toVariant().toStringList());
- fileFilterItem->setRecursive(fileGroup["recursive"].toBool(true));
- fileFilterItem->setPathsProperty(fileGroup["directories"].toVariant().toStringList());
- fileFilterItem->setPathsProperty(filesArr);
+ fileFilterItem->setRecursive(true);
+
fileFilterItem->setDefaultDirectory(m_projectFile.parentDir().toFSPathString());
#ifndef TESTS_ENABLED_QMLPROJECTITEM
connect(fileFilterItem.get(),
@@ -87,11 +83,38 @@ void QmlProjectItem::setupFileFilters()
#endif
m_content.push_back(std::move(fileFilterItem));
};
+
+ // here we begin to add files with the explicit absolute paths
+ QJsonArray files = fileGroup["files"].toArray();
+ if (files.isEmpty())
+ return;
+
+ QStringList filesArr;
+ std::transform(files.begin(),
+ files.end(),
+ std::back_inserter(filesArr),
+ [](const QJsonValue &value) { return value.toString(); });
+
+ const QString directory = fileGroup["directory"].toString() == ""
+ ? m_projectFile.parentDir().toString()
+ : fileGroup["directory"].toString();
+ Utils::FilePath groupDir = Utils::FilePath::fromString(directory);
+ std::unique_ptr<FileFilterItem> fileFilterItem{new FileFilterItem};
+ fileFilterItem->setRecursive(false);
+ fileFilterItem->setPathsProperty(filesArr);
+ fileFilterItem->setDefaultDirectory(m_projectFile.parentDir().toString());
+ fileFilterItem->setDirectory(groupDir.toString());
+#ifndef TESTS_ENABLED_QMLPROJECTITEM
+ connect(fileFilterItem.get(),
+ &FileFilterItem::filesChanged,
+ this,
+ &QmlProjectItem::qmlFilesChanged);
+#endif
+ m_content.push_back(std::move(fileFilterItem));
};
- QJsonObject fileGroups = m_project["fileGroups"].toObject();
- for (const QString &groupName : fileGroups.keys()) {
- setupFileFilterItem(fileGroups[groupName].toObject());
+ for (const QJsonValue &fileGroup : m_project["fileGroups"].toArray()) {
+ setupFileFilterItem(fileGroup.toObject());
}
}
@@ -107,7 +130,7 @@ QString QmlProjectItem::targetDirectory() const
bool QmlProjectItem::isQt4McuProject() const
{
- return m_project["mcuConfig"].toObject()["mcuEnabled"].toBool();
+ return m_project["mcu"].toObject()["enabled"].toBool();
}
Utils::EnvironmentItems QmlProjectItem::environment() const
diff --git a/src/plugins/qmlprojectmanager/cmakegen/qmlprojectmaincmakelists.tpl b/src/plugins/qmlprojectmanager/cmakegen/qmlprojectmaincmakelists.tpl
index 4cd900a31ff..9ca0ace63ba 100644
--- a/src/plugins/qmlprojectmanager/cmakegen/qmlprojectmaincmakelists.tpl
+++ b/src/plugins/qmlprojectmanager/cmakegen/qmlprojectmaincmakelists.tpl
@@ -5,8 +5,13 @@ option(BUILD_QDS_COMPONENTS "Build design studio components" ON)
project(%1 LANGUAGES CXX)
-set(CMAKE_INCLUDE_CURRENT_DIR ON)
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)
@@ -39,7 +44,7 @@ if (LINK_INSIGHT)
endif ()
include(GNUInstallDirs)
-install(TARGETS CppExampleApp
+install(TARGETS %1
BUNDLE DESTINATION .
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}