QmlDesigner: Add button to component specifics

* Add a button to component specifics for simpler access to the
  component. Currently it is only possible to access a component via
  the context menu "Go into Component" or shortcut F2.
* Add image template
* Fix other templates
* Cleanup component specifics and introduce nested sections

Task-number: QDS-3062
Task-number: QDS-2358
Change-Id: I6b245b013fbf4b960509b0a357ae62d20e0383cc
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Henning Gruendl
2020-11-05 16:11:13 +01:00
committed by Henning Gründl
parent 50405d7153
commit 6a1f51b195
12 changed files with 514 additions and 132 deletions

View File

@@ -1,8 +1,11 @@
// Dummy comment to consume the first argument and suppress warnings %1
Section { Section {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
caption: "%1" caption: qsTr("Color")
expanded: false
level: 2
ColorEditor { ColorEditor {
backendValue: backendValues.%2 backendValue: backendValues.%2

View File

@@ -1,7 +1,10 @@
// Dummy comment to consume the first argument and suppress warnings %1
FontSection { FontSection {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
caption: "%1" caption: qsTr("Font")
fontName: "%2" fontName: "%2"
expanded: false
level: 2
} }

View File

@@ -0,0 +1,215 @@
// Dummy comment to consume the first argument and suppress warnings %1
Section {
anchors.left: parent.left
anchors.right: parent.right
caption: qsTr("Image")
expanded: false
level: 2
SectionLayout {
Label {
text: qsTr("Source")
}
SecondColumnLayout {
UrlChooser {
Layout.fillWidth: true
backendValue: backendValues.%2_source
}
ExpandingSpacer {
}
}
Label {
text: qsTr("Fill mode")
}
SecondColumnLayout {
ComboBox {
scope: "Image"
model: ["Stretch", "PreserveAspectFit", "PreserveAspectCrop", "Tile", "TileVertically", "TileHorizontally", "Pad"]
backendValue: backendValues.%2_fillMode
implicitWidth: 180
Layout.fillWidth: true
}
ExpandingSpacer {
}
}
Label {
text: qsTr("Source size")
disabledState: !backendValues.%2_sourceSize.isAvailable
}
SecondColumnLayout {
Label {
text: "W"
width: 12
disabledStateSoft: !backendValues.%2_sourceSize_width.isAvailable
}
SpinBox {
backendValue: backendValues.%2_sourceSize_width
minimumValue: 0
maximumValue: 8192
decimals: 0
enabled: backendValue.isAvailable
}
Item {
width: 4
height: 4
}
Label {
text: "H"
width: 12
disabledStateSoft: !backendValues.%2_sourceSize_height.isAvailable
}
SpinBox {
backendValue: backendValues.%2_sourceSize_height
minimumValue: 0
maximumValue: 8192
decimals: 0
enabled: backendValue.isAvailable
}
ExpandingSpacer {
}
}
Label {
text: qsTr("Horizontal alignment")
}
SecondColumnLayout {
ComboBox {
scope: "Image"
model: ["AlignLeft", "AlignRight", "AlignHCenter"]
backendValue: backendValues.%2_horizontalAlignment
implicitWidth: 180
Layout.fillWidth: true
}
ExpandingSpacer {
}
}
Label {
text: qsTr("Vertical alignment")
}
SecondColumnLayout {
ComboBox {
scope: "Image"
model: ["AlignTop", "AlignBottom", "AlignVCenter"]
backendValue: backendValues.%2_verticalAlignment
implicitWidth: 180
Layout.fillWidth: true
}
ExpandingSpacer {
}
}
Label {
text: qsTr("Asynchronous")
tooltip: qsTr("Loads images on the local filesystem asynchronously in a separate thread.")
disabledState: !backendValues.%2_asynchronous.isAvailable
}
SecondColumnLayout {
CheckBox {
enabled: backendValues.%2_asynchronous.isAvailable
text: backendValues.%2_asynchronous.valueToString
backendValue: backendValues.%2_asynchronous
implicitWidth: 180
}
ExpandingSpacer {}
}
Label {
text: qsTr("Auto transform")
tooltip: qsTr("Automatically applies image transformation metadata such as EXIF orientation.")
disabledState: !backendValues.%2_autoTransform.isAvailable
}
SecondColumnLayout {
CheckBox {
enabled: backendValues.%2_autoTransform.isAvailable
text: backendValues.%2_autoTransform.valueToString
backendValue: backendValues.%2_autoTransform
implicitWidth: 180
}
ExpandingSpacer {}
}
Label {
text: qsTr("Cache")
tooltip: qsTr("Caches the image.")
disabledState: !backendValues.%2_cache.isAvailable
}
SecondColumnLayout {
CheckBox {
enabled: backendValues.%2_cache.isAvailable
text: backendValues.%2_cache.valueToString
backendValue: backendValues.%2_cache
implicitWidth: 180
}
ExpandingSpacer {}
}
Label {
text: qsTr("Mipmap")
tooltip: qsTr("Uses mipmap filtering when the image is scaled or transformed.")
disabledState: !backendValues.%2_mipmap.isAvailable
}
SecondColumnLayout {
CheckBox {
enabled: backendValues.%2_mipmap.isAvailable
text: backendValues.%2_mipmap.valueToString
backendValue: backendValues.%2_mipmap
implicitWidth: 180
}
ExpandingSpacer {}
}
Label {
text: qsTr("Mirror")
tooltip: qsTr("Inverts the image horizontally.")
disabledState: !backendValues.%2_mirror.isAvailable
}
SecondColumnLayout {
CheckBox {
enabled: backendValues.%2_mirror.isAvailable
text: backendValues.%2_mirror.valueToString
backendValue: backendValues.%2_mirror
implicitWidth: 180
}
ExpandingSpacer {}
}
Label {
text: qsTr("Smooth")
tooltip: qsTr("Smoothly filters the image when it is scaled or transformed.")
disabledState: !backendValues.%2_smooth.isAvailable
}
SecondColumnLayout {
CheckBox {
enabled: backendValues.%2_smooth.isAvailable
text: backendValues.%2_smooth.valueToString
backendValue: backendValues.%2_smooth
implicitWidth: 180
}
ExpandingSpacer {}
}
}
}

View File

@@ -1,21 +1,25 @@
// Dummy comment to consume the first argument and suppress warnings %1
Section { Section {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
caption: qsTr("%2 Color") caption: qsTr("Color")
expanded: false
level: 2
ColorEditor { ColorEditor {
caption: qsTr("Color") caption: qsTr("Color")
backendValue: backendValues.%2_color backendValue: backendValues.%2_color
supportGradient: true supportGradient: true
} }
} }
Section { Section {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
caption: qsTr("%2 Border Color") caption: qsTr("Border Color")
expanded: false
level: 2
ColorEditor { ColorEditor {
caption: qsTr("Border Color") caption: qsTr("Border Color")
@@ -24,11 +28,12 @@ Section {
} }
} }
Section { Section {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
caption: "%2 Rectangle" caption: qsTr("Rectangle")
expanded: false
level: 2
SectionLayout { SectionLayout {
rows: 2 rows: 2

View File

@@ -24,7 +24,7 @@
****************************************************************************/ ****************************************************************************/
AutoTypes { AutoTypes {
imports: [ "import HelperWidgets 2.0", "import QtQuick 2.1", "import QtQuick.Layouts 1.1" ] imports: [ "import HelperWidgets 2.0", "import QtQuick 2.15", "import QtQuick.Layouts 1.15" ]
Type { Type {
typeNames: ["int"] typeNames: ["int"]
@@ -71,4 +71,9 @@ AutoTypes {
separateSection: true separateSection: true
} }
Type {
typeNames: ["Image"]
sourceFile: "ImageEditorTemplate.template"
separateSection: true
}
} }

View File

@@ -1,7 +1,9 @@
Section { Section {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
caption: "%1" caption: qsTr("Text")
expanded: false
level: 2
SectionLayout { SectionLayout {
columns: 2 columns: 2

View File

@@ -0,0 +1,52 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
import QtQuick 2.15
import StudioControls 1.0 as StudioControls
import StudioTheme 1.0 as StudioTheme
Column {
id: column
width: parent.width
spacing: 10
padding: 10
Label {
text: qsTr("This item is an instance of a Component")
anchors.horizontalCenter: parent.horizontalCenter
width: 220
}
StudioControls.AbstractButton {
id: testtest
anchors.horizontalCenter: parent.horizontalCenter
width: 180
buttonIcon: qsTr("Edit Master Component")
iconFont: StudioTheme.Constants.font
onClicked: goIntoComponent()
}
}

View File

@@ -23,9 +23,9 @@
** **
****************************************************************************/ ****************************************************************************/
import QtQuick 2.1 import QtQuick 2.15
import QtQuick.Controls 2.12 as Controls import QtQuick.Controls 2.12 as Controls
import QtQuick.Layouts 1.0 import QtQuick.Layouts 1.15
import QtQuickDesignerTheme 1.0 import QtQuickDesignerTheme 1.0
import StudioTheme 1.0 as StudioTheme import StudioTheme 1.0 as StudioTheme
@@ -35,28 +35,22 @@ Item {
property int leftPadding: 8 property int leftPadding: 8
property int topPadding: 4 property int topPadding: 4
property int rightPadding: 0 property int rightPadding: 0
property int bottomPadding: 4
property int animationDuration: 0 property int animationDuration: 0
property bool expanded: true property bool expanded: true
property int level: 0
property int levelShift: 10
clip: true clip: true
Rectangle { Rectangle {
id: header id: header
height: 20 height: 20
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
color: Qt.lighter(StudioTheme.Values.themeSectionHeadBackground, 1.0 + (0.2 * level))
Controls.Label {
id: label
anchors.verticalCenter: parent.verticalCenter
color: StudioTheme.Values.themeTextColor
x: 22
font.bold: true
font.pixelSize: StudioTheme.Values.myFontSize
}
Image { Image {
id: arrow id: arrow
@@ -64,35 +58,27 @@ Item {
height: 4 height: 4
source: "image://icons/down-arrow" source: "image://icons/down-arrow"
anchors.left: parent.left anchors.left: parent.left
anchors.leftMargin: 4 anchors.leftMargin: 4 + (level * levelShift)
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
Behavior on rotation { Behavior on rotation {
NumberAnimation { NumberAnimation {
easing.type: Easing.OutCubic easing.type: Easing.OutCubic
duration: animationDuration duration: section.animationDuration
}
} }
} }
} Controls.Label {
id: label
color: StudioTheme.Values.themeSectionHeadBackground anchors.verticalCenter: parent.verticalCenter
color: StudioTheme.Values.themeTextColor
Rectangle { x: 22 + (level * levelShift)
visible: false font.bold: true
color:"#333" font.pixelSize: StudioTheme.Values.myFontSize
width: parent.width
height: 1
}
Rectangle {
visible: false
color: "#333"
anchors.bottom: parent.bottom
width: parent.width
height: 1
} }
MouseArea { MouseArea {
id: mouseArea
anchors.fill: parent anchors.fill: parent
onClicked: { onClicked: {
section.animationDuration = 120 section.animationDuration = 120
@@ -105,22 +91,23 @@ Item {
readonly property alias contentItem: row readonly property alias contentItem: row
implicitHeight: Math.round(row.height + header.height + 8) implicitHeight: Math.round(row.height + header.height
+ section.topPadding + section.bottomPadding)
Row { Row {
anchors.left: parent.left
anchors.leftMargin: leftPadding
anchors.right: parent.right
anchors.rightMargin: rightPadding
anchors.top: header.bottom
anchors.topMargin: topPadding
id: row id: row
anchors.left: parent.left
anchors.leftMargin: section.leftPadding
anchors.right: parent.right
anchors.rightMargin: section.rightPadding
anchors.top: header.bottom
anchors.topMargin: section.topPadding
} }
Behavior on implicitHeight { Behavior on implicitHeight {
NumberAnimation { NumberAnimation {
easing.type: Easing.OutCubic easing.type: Easing.OutCubic
duration: animationDuration duration: section.animationDuration
} }
} }

View File

@@ -14,6 +14,7 @@ ColorEditor 2.0 ColorEditor.qml
ColorLine 2.0 ColorLine.qml ColorLine 2.0 ColorLine.qml
ColorLogic 2.0 ColorLogic.qml ColorLogic 2.0 ColorLogic.qml
ComboBox 2.0 ComboBox.qml ComboBox 2.0 ComboBox.qml
ComponentButton 2.0 ComponentButton.qml
EditableListView 2.0 EditableListView.qml EditableListView 2.0 EditableListView.qml
ExpandingSpacer 2.0 ExpandingSpacer.qml ExpandingSpacer 2.0 ExpandingSpacer.qml
ExtendedFunctionLogic 2.0 ExtendedFunctionLogic.qml ExtendedFunctionLogic 2.0 ExtendedFunctionLogic.qml

View File

@@ -180,6 +180,21 @@ void PropertyEditorContextObject::toogleExportAlias()
} }
} }
void PropertyEditorContextObject::goIntoComponent()
{
QTC_ASSERT(m_model && m_model->rewriterView(), return);
/* Ideally we should not missuse the rewriterView
* If we add more code here we have to forward the property editor view */
RewriterView *rewriterView = m_model->rewriterView();
QTC_ASSERT(!rewriterView->selectedModelNodes().isEmpty(), return);
const ModelNode selectedNode = rewriterView->selectedModelNodes().constFirst();
DocumentManager::goIntoComponent(selectedNode);
}
void PropertyEditorContextObject::changeTypeName(const QString &typeName) void PropertyEditorContextObject::changeTypeName(const QString &typeName)
{ {
QTC_ASSERT(m_model && m_model->rewriterView(), return); QTC_ASSERT(m_model && m_model->rewriterView(), return);

View File

@@ -86,6 +86,8 @@ public:
Q_INVOKABLE void toogleExportAlias(); Q_INVOKABLE void toogleExportAlias();
Q_INVOKABLE void goIntoComponent();
Q_INVOKABLE void changeTypeName(const QString &typeName); Q_INVOKABLE void changeTypeName(const QString &typeName);
Q_INVOKABLE void insertKeyframe(const QString &propertyName); Q_INVOKABLE void insertKeyframe(const QString &propertyName);

View File

@@ -551,17 +551,13 @@ inline bool dotPropertyHeuristic(const QmlObjectNode &node, const NodeMetaInfo &
NodeMetaInfo itemInfo = node.view()->model()->metaInfo("QtQuick.Item"); NodeMetaInfo itemInfo = node.view()->model()->metaInfo("QtQuick.Item");
NodeMetaInfo textInfo = node.view()->model()->metaInfo("QtQuick.Text"); NodeMetaInfo textInfo = node.view()->model()->metaInfo("QtQuick.Text");
NodeMetaInfo rectangleInfo = node.view()->model()->metaInfo("QtQuick.Rectangle"); NodeMetaInfo rectangleInfo = node.view()->model()->metaInfo("QtQuick.Rectangle");
NodeMetaInfo imageInfo = node.view()->model()->metaInfo("QtQuick.Image");
if (itemInfo.hasProperty(itemProperty)) if (typeName == "font"
return false; || itemInfo.hasProperty(itemProperty)
|| textInfo.isSubclassOf(typeName)
if (typeName == "font") || rectangleInfo.isSubclassOf(typeName)
return false; || imageInfo.isSubclassOf(typeName))
if (textInfo.isSubclassOf(typeName))
return false;
if (rectangleInfo.isSubclassOf(typeName))
return false; return false;
return true; return true;
@@ -576,92 +572,188 @@ QString PropertyEditorQmlBackend::templateGeneration(const NodeMetaInfo &type,
const auto nodes = templateConfiguration()->children(); const auto nodes = templateConfiguration()->children();
QStringList sectorTypes; QStringList allTypes; // all template types
QStringList separateSectionTypes; // separate section types only
for (const QmlJS::SimpleReaderNode::Ptr &node : nodes) { for (const QmlJS::SimpleReaderNode::Ptr &node : nodes) {
if (node->propertyNames().contains("separateSection")) if (node->propertyNames().contains("separateSection"))
sectorTypes.append(variantToStringList(node->property("typeNames"))); separateSectionTypes.append(variantToStringList(node->property("typeNames")));
allTypes.append(variantToStringList(node->property("typeNames")));
} }
QStringList imports = variantToStringList(templateConfiguration()->property(QStringLiteral("imports"))); const QList<PropertyName> allProperties = type.propertyNames();
QString qmlTemplate = imports.join(QLatin1Char('\n')) + QLatin1Char('\n'); QMap<PropertyName, QList<PropertyName>> propertyMap;
QList<PropertyName> separateSectionProperties;
qmlTemplate += "Column {\n"; // Iterate over all properties and isolate the properties which have their own template
qmlTemplate += "anchors.left: parent.left\n"; for (const PropertyName &propertyName : allProperties) {
qmlTemplate += "anchors.right: parent.right\n"; if (propertyName.startsWith("__"))
QList<PropertyName> orderedList = type.propertyNames();
Utils::sort(orderedList, [type, &sectorTypes](const PropertyName &left, const PropertyName &right){
const QString typeNameLeft = QString::fromLatin1(type.propertyTypeName(left));
const QString typeNameRight = QString::fromLatin1(type.propertyTypeName(right));
if (typeNameLeft == typeNameRight)
return left > right;
if (sectorTypes.contains(typeNameLeft)) {
if (sectorTypes.contains(typeNameRight))
return left > right;
return true;
} else if (sectorTypes.contains(typeNameRight)) {
return false;
}
return left > right;
});
bool emptyTemplate = true;
bool sectionStarted = false;
foreach (const PropertyName &name, orderedList) {
if (name.startsWith("__"))
continue; // private API continue; // private API
PropertyName properName = name;
properName.replace('.', '_'); if (!superType.hasProperty(propertyName)
&& type.propertyIsWritable(propertyName)
&& dotPropertyHeuristic(node, type, propertyName)) {
const QString typeName = QString::fromLatin1(type.propertyTypeName(propertyName));
TypeName typeName = type.propertyTypeName(name); // Check if a template for the type exists
if (allTypes.contains(typeName)) {
if (separateSectionTypes.contains(typeName)) { // template enforces separate section
separateSectionProperties.append(propertyName);
} else {
if (propertyName.contains('.')) {
const PropertyName parentProperty = propertyName.split('.').first();
if (propertyMap.contains(parentProperty))
propertyMap[parentProperty].append(propertyName);
else
propertyMap[parentProperty] = { propertyName };
} else {
if (!propertyMap.contains(propertyName))
propertyMap[propertyName] = {};
}
}
}
}
}
// Filter out the properties which have a basic type e.g. int, string, bool
QList<PropertyName> basicProperties;
for (auto k : propertyMap.keys()) {
if (propertyMap.value(k).empty()) {
basicProperties.append(k);
propertyMap.remove(k);
}
}
Utils::sort(basicProperties);
auto findAndFillTemplate = [&nodes, &node, &type](const PropertyName &label,
const PropertyName &property) {
PropertyName underscoreProperty = property;
underscoreProperty.replace('.', '_');
TypeName typeName = type.propertyTypeName(property);
// alias resolution only possible with instance // alias resolution only possible with instance
if (typeName == "alias" && node.isValid()) if (typeName == "alias" && node.isValid())
typeName = node.instanceType(name); typeName = node.instanceType(property);
auto nodes = templateConfiguration()->children(); QString filledTemplate;
for (const QmlJS::SimpleReaderNode::Ptr &n : nodes) {
if (!superType.hasProperty(name) && type.propertyIsWritable(name) && dotPropertyHeuristic(node, type, name)) { // Check if we have a template for the type
if (variantToStringList(n->property(QStringLiteral("typeNames"))).contains(QString::fromLatin1(typeName))) {
for (const QmlJS::SimpleReaderNode::Ptr &node : nodes) { const QString fileName = propertyTemplatesPath() + n->property(QStringLiteral("sourceFile")).toString();
if (variantToStringList(node->property(QStringLiteral("typeNames"))).contains(QString::fromLatin1(typeName))) {
const QString fileName = propertyTemplatesPath() + node->property(QStringLiteral("sourceFile")).toString();
QFile file(fileName); QFile file(fileName);
if (file.open(QIODevice::ReadOnly)) { if (file.open(QIODevice::ReadOnly)) {
QString source = QString::fromUtf8(file.readAll()); QString source = QString::fromUtf8(file.readAll());
file.close(); file.close();
const bool section = node->propertyNames().contains("separateSection"); filledTemplate = source.arg(QString::fromUtf8(label)).arg(QString::fromUtf8(underscoreProperty));
if (section) {
} else if (!sectionStarted) {
qmlTemplate += QStringLiteral("Section {\n");
qmlTemplate += QStringLiteral("caption: \"%1\"\n").arg(QString::fromUtf8(type.simplifiedTypeName()));
qmlTemplate += "anchors.left: parent.left\n";
qmlTemplate += "anchors.right: parent.right\n";
qmlTemplate += QStringLiteral("SectionLayout {\n");
sectionStarted = true;
}
qmlTemplate += source.arg(QString::fromUtf8(name)).arg(QString::fromUtf8(properName));
emptyTemplate = false;
} else { } else {
qWarning().nospace() << "template definition source file not found:" << fileName; qWarning().nospace() << "template definition source file not found:" << fileName;
} }
} }
} }
} return filledTemplate;
} };
if (sectionStarted) {
qmlTemplate += QStringLiteral("}\n"); //Section // QML specfics preparation
qmlTemplate += QStringLiteral("}\n"); //SectionLayout QStringList imports = variantToStringList(templateConfiguration()->property(QStringLiteral("imports")));
QString qmlTemplate = imports.join(QLatin1Char('\n')) + QLatin1Char('\n');
bool emptyTemplate = true;
const QString anchorLeftRight = "anchors.left: parent.left\nanchors.right: parent.right\n";
const QString paddingLeftTopBottom = "leftPadding: 0\ntopPadding: 0\nbottomPadding: 0\n";
qmlTemplate += "Column {\n";
qmlTemplate += anchorLeftRight;
if (node.modelNode().isComponent())
qmlTemplate += "ComponentButton {}\n";
qmlTemplate += "Section {\n";
qmlTemplate += "caption: \"User added properties\"\n";
qmlTemplate += anchorLeftRight;
qmlTemplate += paddingLeftTopBottom;
qmlTemplate += "Column {\n";
qmlTemplate += "width: parent.width\n";
// First the section containing properties of basic type e.g. int, string, bool
if (!basicProperties.empty()) {
emptyTemplate = false;
qmlTemplate += "Column {\n";
qmlTemplate += "width: parent.width\n";
qmlTemplate += "leftPadding: 8\n";
qmlTemplate += "rightPadding: 0\n";
qmlTemplate += "topPadding: 4\n";
qmlTemplate += "bottomPadding: 4\n";
qmlTemplate += "SectionLayout {\n";
for (const auto &p : qAsConst(basicProperties))
qmlTemplate += findAndFillTemplate(p, p);
qmlTemplate += "}\n"; // SectionLayout
qmlTemplate += "}\n"; // Column
} }
qmlTemplate += "}\n"; // Second the section containing properties of complex type for which no specific template exists e.g. Button
if (!propertyMap.empty()) {
emptyTemplate = false;
for (const auto &k : propertyMap.keys()) {
TypeName parentTypeName = type.propertyTypeName(k);
// alias resolution only possible with instance
if (parentTypeName == "alias" && node.isValid())
parentTypeName = node.instanceType(k);
qmlTemplate += "Section {\n";
qmlTemplate += QStringLiteral("caption: \"%1 - %2\"\n").arg(QString::fromUtf8(k)).arg(QString::fromUtf8(parentTypeName));
qmlTemplate += anchorLeftRight;
qmlTemplate += "expanded: false\n";
qmlTemplate += "level: 1\n";
qmlTemplate += "SectionLayout {\n";
auto properties = propertyMap.value(k);
Utils::sort(properties);
for (const auto &p : qAsConst(properties)) {
const PropertyName shortName = p.contains('.') ? p.split('.').last() : p;
qmlTemplate += findAndFillTemplate(shortName, p);
}
qmlTemplate += "}\n"; // SectionLayout
qmlTemplate += "}\n"; // Section
}
}
// Third the section containing properties of complex type for which a specific template exists e.g. Rectangle, Image
if (!separateSectionProperties.empty()) {
emptyTemplate = false;
Utils::sort(separateSectionProperties);
for (const auto &p : qAsConst(separateSectionProperties)) {
TypeName parentTypeName = type.propertyTypeName(p);
// alias resolution only possible with instance
if (parentTypeName == "alias" && node.isValid())
parentTypeName = node.instanceType(p);
qmlTemplate += "Section {\n";
qmlTemplate += QStringLiteral("caption: \"%1 - %2\"\n").arg(QString::fromUtf8(p)).arg(QString::fromUtf8(parentTypeName));
qmlTemplate += anchorLeftRight;
qmlTemplate += paddingLeftTopBottom;
qmlTemplate += "level: 1\n";
qmlTemplate += "Column {\n";
qmlTemplate += "width: parent.width\n";
qmlTemplate += findAndFillTemplate(p, p);
qmlTemplate += "}\n"; // Column
qmlTemplate += "}\n"; // Section
}
}
qmlTemplate += "}\n"; // Column
qmlTemplate += "}\n"; // Section
qmlTemplate += "}\n"; // Column
if (emptyTemplate) if (emptyTemplate)
return QString(); return QString();