Handle nodes and properties required by MCUs in JSON conversion

Qt for MCUs uses several features in the qmlproject files which
are unknown to QDS. It is important that this information does
not get lost when converting to and from the internal JSON
project format, to avoid breaking MCU projects.

The following changes were made:
- Files nodes keep the type (ImageFiles, QmlFiles...)
- Added support for more Files node types used by MCU projects
  (ModuleFiles, InterfaceFiles, FontFiles...)
- Files nodes can have child properties
- Added a JSON object to store properties unknown to QDS.
  They may be used by Qt for MCUs, and new properties may
  be added between versions
- Added support for the MCU.Config and MCU.Module nodes
- Added a test project for MCU. This project is also tested
  with Qt for MCUs. Both the original and the converted
  project build correctly
- Added instructions for notifying the MCU team before
  modifying the MCU test cases to avoid breaking changes.

Fixes: QDS-10774
Task-number: QDS-10969
Change-Id: I0dfd7f3b150a8661fc0398a8a3d575c7e8777ef3
Reviewed-by: Burak Hancerli <burak.hancerli@qt.io>
Reviewed-by: Yasser Grimes <yasser.grimes@qt.io>
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
Reviewed-by: Qt CI Patch Build Bot <ci_patchbuild_bot@qt.io>
This commit is contained in:
Sivert Krøvel
2023-11-08 14:16:23 +01:00
parent 820b1ce2d0
commit b080a3772c
16 changed files with 1119 additions and 178 deletions

View File

@@ -3,10 +3,21 @@
#include "converters.h"
#include <QJsonArray>
#include <QJsonDocument>
namespace QmlProjectManager::Converters {
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)
{
QString qmlProjectString;
@@ -19,6 +30,11 @@ QString jsonToQmlProject(const QJsonObject &rootObject)
QJsonObject environmentConfig = rootObject["environment"].toObject();
QJsonObject deploymentConfig = rootObject["deployment"].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;
@@ -35,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);
};
@@ -42,7 +60,9 @@ 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(",");
@@ -52,6 +72,27 @@ QString jsonToQmlProject(const QJsonObject &rootObject)
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;
@@ -63,20 +104,30 @@ QString jsonToQmlProject(const QJsonObject &rootObject)
ts << QString(" ").repeated(indentationLevel * 4) << "}" << Qt::endl;
};
auto appendFileGroup =
[&startObject, &endObject, &appendString, &appendArray](const QJsonObject &fileGroup,
const QString &qmlKey) {
startObject(qmlKey);
appendString("directory", fileGroup["directory"].toString());
appendString("filter", fileGroup["filters"].toVariant().toStringList().join(";"));
appendArray("files", fileGroup["files"].toVariant().toStringList());
endObject();
};
auto appendQmlFileGroup =
[&startObject, &endObject, &appendString](const QJsonObject &fileGroup) {
startObject("QmlFiles");
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();
};
@@ -93,24 +144,37 @@ QString jsonToQmlProject(const QJsonObject &rootObject)
appendString("mainUiFile", runConfig["mainUiFile"].toString());
appendString("targetDirectory", deploymentConfig["targetDirectory"].toString());
appendBool("widgetApp", runConfig["widgetApp"].toBool());
appendArray("importPaths", rootObject["importPaths"].toVariant().toStringList());
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", !(rootObject["mcuConfig"].toObject().isEmpty()));
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",
appendStringArray("supportedLanguages",
languageConfig["supportedLanguages"].toVariant().toStringList());
}
// 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");
for (const QString &key : environmentConfig.keys())
for (const QString &key : environmentConfig.keys()) {
appendItem(key, environmentConfig[key].toString(), true);
}
endObject();
}
// append ShaderTool object
if (!shaderConfig["args"].toVariant().toStringList().isEmpty()) {
@@ -118,16 +182,35 @@ QString jsonToQmlProject(const QJsonObject &rootObject)
appendString("args",
shaderConfig["args"].toVariant().toStringList().join(" ").replace("\"",
"\\\""));
appendArray("files", shaderConfig["files"].toVariant().toStringList());
appendStringArray("files", shaderConfig["files"].toVariant().toStringList());
endObject();
}
// 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) {
if (fileGroup["filters"].toArray().contains("*.qml"))
appendQmlFileGroup(fileGroup.toObject());
else
appendFileGroup(fileGroup.toObject(), "Files");
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'
@@ -169,7 +252,12 @@ QJsonObject qmlProjectTojson(const Utils::FilePath &projectFile)
QJsonObject runConfigObject;
QJsonObject deploymentObject;
QJsonObject mcuObject;
QJsonObject mcuConfigObject;
QJsonObject mcuModuleObject;
QJsonObject shaderToolObject;
QJsonObject otherProperties;
bool qtForMCUs = false;
// convert the the non-object props
for (const QString &propName : rootNode->propertyNames()) {
@@ -177,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
@@ -200,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);
@@ -220,14 +310,20 @@ QJsonObject qmlProjectTojson(const Utils::FilePath &projectFile)
versionObject.insert("qt", "5");
}
rootObject.insert("otherProperties", otherProperties);
// convert the the object props
for (const QmlJS::SimpleReaderNode::Ptr &childNode : rootNode->children()) {
if (childNode->name().contains("files", Qt::CaseInsensitive)) {
const QString childNodeName = childNode->name().toLower().remove("qds.");
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(";");
filters.removeAll("");
QStringList filters
= childNode->property("filter").value.toString().split(";", Qt::SkipEmptyParts);
QJsonArray childNodeFilters = QJsonArray::fromStringList(filters);
// files have priority over filters
@@ -239,25 +335,22 @@ QJsonObject qmlProjectTojson(const Utils::FilePath &projectFile)
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. After the first
// conversion (QmlProject -> JSON) they are converted to
// the generic file group format ('Files' or 'QDS.Files')
// that have a default set of filters.
// The default filters are written to the
// qmlproject file after conversion
if (childNodeName == "qmlfiles") {
inserter({QStringLiteral("*.qml")});
inserter(qmlFilesFilter);
} else if (childNodeName == "javascriptfiles") {
inserter({QStringLiteral("*.js"), QStringLiteral("*.ts")});
inserter(javaScriptFilesFilter);
} else if (childNodeName == "imagefiles") {
inserter({QStringLiteral("*.jpeg"),
QStringLiteral("*.jpg"),
QStringLiteral("*.png"),
QStringLiteral("*.svg"),
QStringLiteral("*.hdr"),
QStringLiteral(".ktx")});
inserter(imageFilesFilter);
}
}
@@ -266,6 +359,26 @@ QJsonObject qmlProjectTojson(const Utils::FilePath &projectFile)
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;
}
auto val = QJsonValue::fromVariant(childNode->property(propName).value);
if (propName.startsWith("MCU.", Qt::CaseInsensitive)) {
mcuPropertiesObject.insert(propName.mid(4), val);
} else {
otherPropertiesObject.insert(propName, val);
}
}
targetObject.insert("mcuProperties", mcuPropertiesObject);
targetObject.insert("otherProperties", otherPropertiesObject);
fileGroupsObject.append(targetObject);
} else if (childNode->name().contains("shadertool", Qt::CaseInsensitive)) {
@@ -283,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

View File

@@ -130,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

View File

@@ -67,7 +67,9 @@ INSTANTIATE_TEST_SUITE_P(QmlProjectItem,
QmlProjectConverter,
::testing::Values(QString("test-set-1"),
QString("test-set-2"),
QString("test-set-3")));
QString("test-set-3"),
QString("test-set-mcu-1"),
QString("test-set-mcu-2")));
TEST_P(QmlProjectConverter, qml_project_to_json)
{

View File

@@ -30,6 +30,37 @@ Test functions iterate over the "test-set-*" folders and run the tests by using
* **purpose**: testing `QDS.` prefixes
* **origin**: copy of test-set-1
### Qt for MCUs test sets
These tests define the requirements for Qt for MCUs (QUL) projects. They are maintained by the Qt for MCUs
team. Please do not make changes to these test sets before consulting them. These tests help make sure
that QDS and QUL are aligned on the qmlproject format and that new features in QDS does not break
qmlproject files for MCU projects. The test set will be tested in the Qt for MCUs repositories
to make sure both the original and the converted qmlprojects build correctly.
The qmlproject files in the test set aim to cover all the possible contents of a Qt for MCUs qmlproject,
but since new features are added with every release, it is not guaranteed to be exhaustive.
Some main points for qmlproject files for MCU projects:
* Unknown content in the qmlproject file will cause errors in the QUL tooling
* Any node or property with the `QDS`-prefix is ignored by QUL. When adding new properties,
these must either be prefixed or communicated with the MCU team to whitelist them in the tooling.
* Plain `Files` nodes are ignored by QUL, it needs to know the node type. The node contents will be processed
by different tools depending on which type of files it includes. The node types used by QUL are:
+ `QmlFiles`
+ `ImageFiles`
+ `FontFiles`
+ `ModuleFiles`
+ `InterfaceFiles`
+ `TranslationFiles`
* In addition to adding files to the project, any of the `*Files` nodes listed can also contain properties to
apply to the file group added by the node.
* MCU projects may have MCU-specific configuration nodes: `MCU.Config` and `MCU.Module`.
* A new version of Qt for MCUs may add new properties to any node, including `Project`. For this reason
it is not possible to define an exact set of properties to support which is valid across all versions.
* Qt for MCUs developers must still edit and maintain qmlproject files manually. The converted format
of the qmlproject file should be easy to read and edit by hand
## File Filters test data

View File

@@ -40,76 +40,56 @@ Project {
directory: "imports"
}
Files {
JavaScriptFiles {
directory: "content"
filter: "*.js;*.ts"
files: [ ]
}
Files {
JavaScriptFiles {
directory: "imports"
filter: "*.js;*.ts"
files: [ ]
}
Files {
ImageFiles {
directory: "content"
filter: "*.jpeg;*.jpg;*.png;*.svg;*.hdr;.ktx"
files: [ ]
}
Files {
ImageFiles {
directory: "asset_imports"
filter: "*.jpeg;*.jpg;*.png;*.svg;*.hdr;.ktx"
files: [ ]
}
Files {
directory: ""
filter: ""
files: [ "qtquickcontrols2.conf" ]
files: [
"qtquickcontrols2.conf"
]
}
Files {
directory: ""
filter: "*.conf"
files: [ ]
}
Files {
directory: "."
filter: "qmldir"
files: [ ]
}
Files {
directory: ""
filter: "*.ttf;*.otf;*.ctf"
files: [ ]
}
Files {
directory: ""
filter: "*.wav;*.mp3"
files: [ ]
}
Files {
directory: ""
filter: "*.mp4"
files: [ ]
}
Files {
directory: ""
filter: "*.glsl;*.glslv;*.glslf;*.vsh;*.fsh;*.vert;*.frag;*.trag"
files: [ ]
}
Files {
directory: "asset_imports"
filter: "*.mesh"
files: [ ]
}
QmlFiles {

View File

@@ -16,7 +16,12 @@
],
"filters": [
"*.qml"
]
],
"mcuProperties": {
},
"otherProperties": {
},
"type": "Qml"
},
{
"directory": "imports",
@@ -24,7 +29,12 @@
],
"filters": [
"*.qml"
]
],
"mcuProperties": {
},
"otherProperties": {
},
"type": "Qml"
},
{
"directory": "content",
@@ -33,7 +43,12 @@
"filters": [
"*.js",
"*.ts"
]
],
"mcuProperties": {
},
"otherProperties": {
},
"type": "JavaScript"
},
{
"directory": "imports",
@@ -42,7 +57,12 @@
"filters": [
"*.js",
"*.ts"
]
],
"mcuProperties": {
},
"otherProperties": {
},
"type": "JavaScript"
},
{
"directory": "content",
@@ -54,8 +74,13 @@
"*.png",
"*.svg",
"*.hdr",
".ktx"
]
"*.ktx"
],
"mcuProperties": {
},
"otherProperties": {
},
"type": "Image"
},
{
"directory": "asset_imports",
@@ -67,8 +92,13 @@
"*.png",
"*.svg",
"*.hdr",
".ktx"
]
"*.ktx"
],
"mcuProperties": {
},
"otherProperties": {
},
"type": "Image"
},
{
"directory": "",
@@ -76,7 +106,12 @@
"qtquickcontrols2.conf"
],
"filters": [
]
],
"mcuProperties": {
},
"otherProperties": {
},
"type": ""
},
{
"directory": "",
@@ -84,7 +119,12 @@
],
"filters": [
"*.conf"
]
],
"mcuProperties": {
},
"otherProperties": {
},
"type": ""
},
{
"directory": ".",
@@ -92,7 +132,12 @@
],
"filters": [
"qmldir"
]
],
"mcuProperties": {
},
"otherProperties": {
},
"type": ""
},
{
"directory": "",
@@ -102,7 +147,12 @@
"*.ttf",
"*.otf",
"*.ctf"
]
],
"mcuProperties": {
},
"otherProperties": {
},
"type": ""
},
{
"directory": "",
@@ -111,7 +161,12 @@
"filters": [
"*.wav",
"*.mp3"
]
],
"mcuProperties": {
},
"otherProperties": {
},
"type": ""
},
{
"directory": "",
@@ -119,7 +174,12 @@
],
"filters": [
"*.mp4"
]
],
"mcuProperties": {
},
"otherProperties": {
},
"type": ""
},
{
"directory": "",
@@ -134,7 +194,12 @@
"*.vert",
"*.frag",
"*.trag"
]
],
"mcuProperties": {
},
"otherProperties": {
},
"type": ""
},
{
"directory": "asset_imports",
@@ -142,7 +207,12 @@
],
"filters": [
"*.mesh"
]
],
"mcuProperties": {
},
"otherProperties": {
},
"type": ""
},
{
"directory": "asset_imports",
@@ -150,7 +220,12 @@
],
"filters": [
"*.qml"
]
],
"mcuProperties": {
},
"otherProperties": {
},
"type": ""
}
],
"fileVersion": 1,
@@ -165,8 +240,14 @@
"en"
]
},
"mcuConfig": {
"mcuEnabled": true
"mcu": {
"config": {
},
"enabled": true,
"module": {
}
},
"otherProperties": {
},
"runConfig": {
"fileSelectors": [

View File

@@ -5,20 +5,13 @@ import QmlProject
Project {
mainFile: "fileSelectors.qml"
mainUiFile: ""
targetDirectory: "/opt/fileSelectors"
widgetApp: false
importPaths: [ "imports" ]
qdsVersion: ""
quickVersion: ""
qt6Project: false
qtForMCUs: false
multilanguageSupport: false
primaryLanguage: ""
supportedLanguages: [ ]
Environment {
QT_AUTO_SCREEN_SCALE_FACTOR: "1"
QT_QUICK_CONTROLS_CONF: "qtquickcontrols2.conf"
@@ -28,33 +21,26 @@ Project {
directory: "."
}
Files {
JavaScriptFiles {
directory: "."
filter: "*.js;*.ts"
files: [ ]
}
Files {
ImageFiles {
directory: "."
filter: "*.jpeg;*.jpg;*.png;*.svg;*.hdr;.ktx"
files: [ ]
}
Files {
directory: ""
filter: ""
files: [ "qtquickcontrols2.conf" ]
files: [
"qtquickcontrols2.conf"
]
}
Files {
directory: ""
filter: "*.conf"
files: [ ]
}
Files {
directory: "."
filter: "qmldir"
files: [ ]
}
}

View File

@@ -13,7 +13,12 @@
],
"filters": [
"*.qml"
]
],
"mcuProperties": {
},
"otherProperties": {
},
"type": "Qml"
},
{
"directory": ".",
@@ -22,7 +27,12 @@
"filters": [
"*.js",
"*.ts"
]
],
"mcuProperties": {
},
"otherProperties": {
},
"type": "JavaScript"
},
{
"directory": ".",
@@ -34,8 +44,13 @@
"*.png",
"*.svg",
"*.hdr",
".ktx"
]
"*.ktx"
],
"mcuProperties": {
},
"otherProperties": {
},
"type": "Image"
},
{
"directory": "",
@@ -43,7 +58,12 @@
"qtquickcontrols2.conf"
],
"filters": [
]
],
"mcuProperties": {
},
"otherProperties": {
},
"type": ""
},
{
"directory": "",
@@ -51,7 +71,12 @@
],
"filters": [
"*.conf"
]
],
"mcuProperties": {
},
"otherProperties": {
},
"type": ""
},
{
"directory": ".",
@@ -59,7 +84,12 @@
],
"filters": [
"qmldir"
]
],
"mcuProperties": {
},
"otherProperties": {
},
"type": ""
}
],
"fileVersion": 1,
@@ -68,7 +98,14 @@
],
"language": {
},
"mcuConfig": {
"mcu": {
"config": {
},
"enabled": false,
"module": {
}
},
"otherProperties": {
},
"runConfig": {
"fileSelectors": [

View File

@@ -40,76 +40,56 @@ Project {
directory: "imports"
}
Files {
JavaScriptFiles {
directory: "content"
filter: "*.js;*.ts"
files: [ ]
}
Files {
JavaScriptFiles {
directory: "imports"
filter: "*.js;*.ts"
files: [ ]
}
Files {
ImageFiles {
directory: "content"
filter: "*.jpeg;*.jpg;*.png;*.svg;*.hdr;.ktx"
files: [ ]
}
Files {
ImageFiles {
directory: "asset_imports"
filter: "*.jpeg;*.jpg;*.png;*.svg;*.hdr;.ktx"
files: [ ]
}
Files {
directory: ""
filter: ""
files: [ "qtquickcontrols2.conf" ]
files: [
"qtquickcontrols2.conf"
]
}
Files {
directory: ""
filter: "*.conf"
files: [ ]
}
Files {
directory: "."
filter: "qmldir"
files: [ ]
}
Files {
directory: ""
filter: "*.ttf;*.otf;*.ctf"
files: [ ]
}
Files {
directory: ""
filter: "*.wav;*.mp3"
files: [ ]
}
Files {
directory: ""
filter: "*.mp4"
files: [ ]
}
Files {
directory: ""
filter: "*.glsl;*.glslv;*.glslf;*.vsh;*.fsh;*.vert;*.frag;*.trag"
files: [ ]
}
Files {
directory: "asset_imports"
filter: "*.mesh"
files: [ ]
}
QmlFiles {

View File

@@ -16,7 +16,12 @@
],
"filters": [
"*.qml"
]
],
"mcuProperties": {
},
"otherProperties": {
},
"type": "Qml"
},
{
"directory": "imports",
@@ -24,7 +29,12 @@
],
"filters": [
"*.qml"
]
],
"mcuProperties": {
},
"otherProperties": {
},
"type": "Qml"
},
{
"directory": "content",
@@ -33,7 +43,12 @@
"filters": [
"*.js",
"*.ts"
]
],
"mcuProperties": {
},
"otherProperties": {
},
"type": "JavaScript"
},
{
"directory": "imports",
@@ -42,7 +57,12 @@
"filters": [
"*.js",
"*.ts"
]
],
"mcuProperties": {
},
"otherProperties": {
},
"type": "JavaScript"
},
{
"directory": "content",
@@ -54,8 +74,13 @@
"*.png",
"*.svg",
"*.hdr",
".ktx"
]
"*.ktx"
],
"mcuProperties": {
},
"otherProperties": {
},
"type": "Image"
},
{
"directory": "asset_imports",
@@ -67,8 +92,13 @@
"*.png",
"*.svg",
"*.hdr",
".ktx"
]
"*.ktx"
],
"mcuProperties": {
},
"otherProperties": {
},
"type": "Image"
},
{
"directory": "",
@@ -76,7 +106,12 @@
"qtquickcontrols2.conf"
],
"filters": [
]
],
"mcuProperties": {
},
"otherProperties": {
},
"type": ""
},
{
"directory": "",
@@ -84,7 +119,12 @@
],
"filters": [
"*.conf"
]
],
"mcuProperties": {
},
"otherProperties": {
},
"type": ""
},
{
"directory": ".",
@@ -92,7 +132,12 @@
],
"filters": [
"qmldir"
]
],
"mcuProperties": {
},
"otherProperties": {
},
"type": ""
},
{
"directory": "",
@@ -102,7 +147,12 @@
"*.ttf",
"*.otf",
"*.ctf"
]
],
"mcuProperties": {
},
"otherProperties": {
},
"type": ""
},
{
"directory": "",
@@ -111,7 +161,12 @@
"filters": [
"*.wav",
"*.mp3"
]
],
"mcuProperties": {
},
"otherProperties": {
},
"type": ""
},
{
"directory": "",
@@ -119,7 +174,12 @@
],
"filters": [
"*.mp4"
]
],
"mcuProperties": {
},
"otherProperties": {
},
"type": ""
},
{
"directory": "",
@@ -134,7 +194,12 @@
"*.vert",
"*.frag",
"*.trag"
]
],
"mcuProperties": {
},
"otherProperties": {
},
"type": ""
},
{
"directory": "asset_imports",
@@ -142,7 +207,12 @@
],
"filters": [
"*.mesh"
]
],
"mcuProperties": {
},
"otherProperties": {
},
"type": ""
},
{
"directory": "asset_imports",
@@ -150,7 +220,12 @@
],
"filters": [
"*.qml"
]
],
"mcuProperties": {
},
"otherProperties": {
},
"type": ""
}
],
"fileVersion": 1,
@@ -165,8 +240,14 @@
"en"
]
},
"mcuConfig": {
"mcuEnabled": true
"mcu": {
"config": {
},
"enabled": true,
"module": {
}
},
"otherProperties": {
},
"runConfig": {
"fileSelectors": [

View File

@@ -0,0 +1,111 @@
// prop: json-converted
// prop: auto-generated
import QmlProject
Project {
mainFile: "Main.qml"
targetDirectory: "/opt/UntitledProject13"
widgetApp: true
importPaths: [ "imports","asset_imports" ]
qdsVersion: "4.0"
quickVersion: "6.2"
qt6Project: false
qtForMCUs: true
multilanguageSupport: true
primaryLanguage: "en"
supportedLanguages: [ "no" ]
idBasedTranslations: true
projectRootPath: ".."
Environment {
QML_COMPAT_RESOLVE_URLS_ON_ASSIGNMENT: "1"
QT_AUTO_SCREEN_SCALE_FACTOR: "1"
QT_ENABLE_HIGHDPI_SCALING: "0"
QT_LOGGING_RULES: "qt.qml.connections=false"
QT_QUICK_CONTROLS_CONF: "qtquickcontrols2.conf"
}
ShaderTool {
args: "-s --glsl \"100 es,120,150\" --hlsl 50 --msl 12"
files: [ "content/shaders/*" ]
}
MCU.Config {
defaultFontFamily: "Roboto"
fontEngine: "Spark"
maxResourceCacheSize: [[128,128],[16384,1]]
resourceCompression: true
}
QmlFiles {
directory: "content"
MCU.copyQmlFiles: true
}
QmlFiles {
files: [
"qml/Header.qml",
"qml/Footer.qml"
]
}
ImageFiles {
directory: "assets"
}
ImageFiles {
files: [
"images/clock.png"
]
MCU.resourceCompression: false
}
ImageFiles {
files: [
"images/weather.png",
"images/navigation.png"
]
MCU.base: "images"
MCU.prefix: "assets"
}
ModuleFiles {
files: [
"qmlproject/module/module.qmlproject"
]
MCU.qulModules: ["Controls","Timeline"]
}
FontFiles {
files: [
"fonts/RobotoFonts.fmp"
]
}
InterfaceFiles {
files: [
"src/BoardInterface.h"
]
}
TranslationFiles {
files: [
"additional_translations/qml_en.ts",
"i18n/qml_no.ts"
]
MCU.omitSourceLanguage: true
}
JavaScriptFiles {
directory: "scripts"
}
Files {
directory: "more_files"
filter: "*.mp3"
}
}

View File

@@ -0,0 +1,156 @@
import QmlProject 1.3
// This file works with Qt for MCUs 2.6, with the testfile of set-set-mcu-2 used as the module.
// Do not make any changes to this or the expected output before communicating with the MCU team
// The set of properties may not be exhaustive and may not match every supported Qt for MCUs version
Project {
// These properties are used by Qt for MCUs
// They should never have the QDS-prefix
mainFile: "Main.qml"
supportedLanguages: ["no"]
primaryLanguage: "en"
importPaths: [ "imports", "asset_imports" ]
idBasedTranslations: true
projectRootPath: ".."
// END of common properties
// The following properties are ignored by Qt for MCUs
// They can have the QDS-prefix, but do not need it
targetDirectory: "/opt/UntitledProject13"
qdsVersion: "4.0"
quickVersion: "6.2"
qtForMCUs: true
widgetApp: true
multilanguageSupport: true
// END of ignored properties
// The following properties must have the QDS prefix as of Qt for MCUs 2.6
// empty
// END of QDS prefixed properties
// These nodes are used by Qt for MCUs as well as Design Studio
// Their object type and content must never change based on conversion
// Any child properties prefixed with MCU must remain unchanged
// The nodes can have properties set on the file group.
// This test set does not contain an exhaustive set of the available properties
QmlFiles {
directory: "content"
MCU.copyQmlFiles: true
}
QmlFiles {
files: [
"qml/Header.qml",
"qml/Footer.qml"
]
}
ImageFiles {
directory: "assets"
}
ImageFiles {
files: [
"images/clock.png"
]
MCU.resourceCompression: false
}
ImageFiles {
files: [
"images/weather.png",
"images/navigation.png"
]
MCU.prefix: "assets"
MCU.base: "images"
}
// END common nodes
// These nodes are used by Qt for MCUs but not Design Studio
// Their object type and content must never change based on conversion
// Any child properties prefixed with MCU must remain unchanged
ModuleFiles {
files: [
"qmlproject/module/module.qmlproject"
]
MCU.qulModules: [
"Controls",
"Timeline"
]
}
FontFiles {
files: [
"fonts/RobotoFonts.fmp"
]
}
InterfaceFiles {
files: [
"src/BoardInterface.h"
]
}
TranslationFiles {
files: [
"additional_translations/qml_en.ts",
"i18n/qml_no.ts"
]
MCU.omitSourceLanguage: true
}
// END MCU nodes
// This node is prefixed with MCU. Its props are not prefixed
// It must remain unchanged after conversion. Modules may have MCU.Module
MCU.Config {
resourceCompression: true
fontEngine: "Spark"
defaultFontFamily: "Roboto"
maxResourceCacheSize: [
[128, 128],
[16384, 1]
]
}
//END MCU-prefixed node
// The following nodes are ignored by Qt for MCUs
// They do not need the QDS-prefix, but may have it
Environment {
QT_QUICK_CONTROLS_CONF: "qtquickcontrols2.conf"
QT_AUTO_SCREEN_SCALE_FACTOR: "1"
QML_COMPAT_RESOLVE_URLS_ON_ASSIGNMENT: "1"
QT_LOGGING_RULES: "qt.qml.connections=false"
QT_ENABLE_HIGHDPI_SCALING: "0"
/* Useful for debugging
QSG_VISUALIZE=batches
QSG_VISUALIZE=clip
QSG_VISUALIZE=changes
QSG_VISUALIZE=overdraw
*/
}
JavaScriptFiles {
directory: "scripts"
}
Files {
directory: "more_files"
filter: "*.mp3"
}
// END of ignored nodes
// The following nodes are unknown to Qt for MCUs (2.6)
// Unknown nodes cause a warning in MCU tooling, but no error as of Qt for MCUs 2.6
ShaderTool {
args: "-s --glsl \"100 es,120,150\" --hlsl 50 --msl 12"
files: [ "content/shaders/*" ]
}
// END of unknown nodes
}

View File

@@ -0,0 +1,236 @@
{
"deployment": {
"targetDirectory": "/opt/UntitledProject13"
},
"environment": {
"QML_COMPAT_RESOLVE_URLS_ON_ASSIGNMENT": "1",
"QT_AUTO_SCREEN_SCALE_FACTOR": "1",
"QT_ENABLE_HIGHDPI_SCALING": "0",
"QT_LOGGING_RULES": "qt.qml.connections=false",
"QT_QUICK_CONTROLS_CONF": "qtquickcontrols2.conf"
},
"fileGroups": [
{
"directory": "content",
"files": [
],
"filters": [
"*.qml"
],
"mcuProperties": {
"copyQmlFiles": true
},
"otherProperties": {
},
"type": "Qml"
},
{
"directory": "",
"files": [
"qml/Header.qml",
"qml/Footer.qml"
],
"filters": [
],
"mcuProperties": {
},
"otherProperties": {
},
"type": "Qml"
},
{
"directory": "assets",
"files": [
],
"filters": [
"*.jpeg",
"*.jpg",
"*.png",
"*.svg",
"*.hdr",
"*.ktx"
],
"mcuProperties": {
},
"otherProperties": {
},
"type": "Image"
},
{
"directory": "",
"files": [
"images/clock.png"
],
"filters": [
],
"mcuProperties": {
"resourceCompression": false
},
"otherProperties": {
},
"type": "Image"
},
{
"directory": "",
"files": [
"images/weather.png",
"images/navigation.png"
],
"filters": [
],
"mcuProperties": {
"base": "images",
"prefix": "assets"
},
"otherProperties": {
},
"type": "Image"
},
{
"directory": "",
"files": [
"qmlproject/module/module.qmlproject"
],
"filters": [
],
"mcuProperties": {
"qulModules": [
"Controls",
"Timeline"
]
},
"otherProperties": {
},
"type": "Module"
},
{
"directory": "",
"files": [
"fonts/RobotoFonts.fmp"
],
"filters": [
],
"mcuProperties": {
},
"otherProperties": {
},
"type": "Font"
},
{
"directory": "",
"files": [
"src/BoardInterface.h"
],
"filters": [
],
"mcuProperties": {
},
"otherProperties": {
},
"type": "Interface"
},
{
"directory": "",
"files": [
"additional_translations/qml_en.ts",
"i18n/qml_no.ts"
],
"filters": [
],
"mcuProperties": {
"omitSourceLanguage": true
},
"otherProperties": {
},
"type": "Translation"
},
{
"directory": "scripts",
"files": [
],
"filters": [
"*.js",
"*.ts"
],
"mcuProperties": {
},
"otherProperties": {
},
"type": "JavaScript"
},
{
"directory": "more_files",
"files": [
],
"filters": [
"*.mp3"
],
"mcuProperties": {
},
"otherProperties": {
},
"type": ""
}
],
"fileVersion": 1,
"importPaths": [
"imports",
"asset_imports"
],
"language": {
"multiLanguageSupport": true,
"primaryLanguage": "en",
"supportedLanguages": [
"no"
]
},
"mcu": {
"config": {
"defaultFontFamily": "Roboto",
"fontEngine": "Spark",
"maxResourceCacheSize": [
[
128,
128
],
[
16384,
1
]
],
"resourceCompression": true
},
"enabled": true,
"module": {
}
},
"otherProperties": {
"idBasedTranslations": true,
"projectRootPath": ".."
},
"runConfig": {
"fileSelectors": [
],
"mainFile": "Main.qml",
"widgetApp": true
},
"shaderTool": {
"args": [
"-s",
"--glsl",
"\"100 es,120,150\"",
"--hlsl",
"50",
"--msl",
"12"
],
"files": [
"content/shaders/*"
]
},
"versions": {
"designStudio": "4.0",
"qt": "5",
"qtQuick": "6.2"
}
}

View File

@@ -0,0 +1,32 @@
// prop: json-converted
// prop: auto-generated
import QmlProject
Project {
widgetApp: false
qt6Project: false
qtForMCUs: true
projectRootPath: "../.."
MCU.Module {
generateQmltypes: true
uri: "MyModule"
}
QmlFiles {
files: [
"qml/TextIcon.qml"
]
}
ImageFiles {
files: [
"images/qt_logo.png"
]
MCU.base: "images"
MCU.prefix: "logo"
}
}

View File

@@ -0,0 +1,29 @@
import QmlProject 1.3
// This file represents the module contained in the testfile of test-set-mcu-1
// Do not modify without discussing with the MCU team
Project {
projectRootPath: "../.."
MCU.Module {
uri: "MyModule"
generateQmltypes: true
}
QmlFiles {
files: [
"qml/TextIcon.qml"
]
}
ImageFiles {
files: [
"images/qt_logo.png"
]
MCU.base: "images"
MCU.prefix: "logo"
}
}

View File

@@ -0,0 +1,56 @@
{
"deployment": {
},
"fileGroups": [
{
"directory": "",
"files": [
"qml/TextIcon.qml"
],
"filters": [
],
"mcuProperties": {
},
"otherProperties": {
},
"type": "Qml"
},
{
"directory": "",
"files": [
"images/qt_logo.png"
],
"filters": [
],
"mcuProperties": {
"base": "images",
"prefix": "logo"
},
"otherProperties": {
},
"type": "Image"
}
],
"fileVersion": 1,
"language": {
},
"mcu": {
"config": {
},
"enabled": true,
"module": {
"generateQmltypes": true,
"uri": "MyModule"
}
},
"otherProperties": {
"projectRootPath": "../.."
},
"runConfig": {
"fileSelectors": [
]
},
"versions": {
"qt": "5"
}
}