aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDominik Holland <dominik.holland@pelagicore.com>2017-08-29 16:11:15 +0200
committerDominik Holland <dominik.holland@pelagicore.com>2017-09-15 12:49:01 +0000
commitc99b4539534a09e0da836b5dd5057e8b770e9863 (patch)
tree1c97b0b6c3745b8a706310c1b0abd2ad272b4492
parentc453170eeba7f3e2685329928deea600c6fc4a35 (diff)
Refactor the control_panel interface class
The class now works more like the QtIvi public API and uses one object per zone accessible using the zoneAt property. This also intruces two new special controls for Enums and Flags, which makes the generate.py part a little bit easier and make the controls work in both directions (backend values and update of user values). Change-Id: Ib012265ef405d4a4e20ed43d611caa0163a40446 Reviewed-by: Mike Krus <mike.krus@kdab.com>
-rwxr-xr-xsrc/tools/ivigenerator/generate.py35
-rw-r--r--src/tools/ivigenerator/ivigenerator.pro2
-rw-r--r--src/tools/ivigenerator/templates_backend_simulator/backend.cpp.tpl1
-rw-r--r--src/tools/ivigenerator/templates_control_panel.yaml4
-rw-r--r--src/tools/ivigenerator/templates_control_panel/EnumControl.qml.tpl31
-rw-r--r--src/tools/ivigenerator/templates_control_panel/FlagControl.qml.tpl29
-rw-r--r--src/tools/ivigenerator/templates_control_panel/interface.cpp.tpl85
-rw-r--r--src/tools/ivigenerator/templates_control_panel/interface.h.tpl24
-rw-r--r--src/tools/ivigenerator/templates_control_panel/interface.qml.tpl33
-rw-r--r--src/tools/ivigenerator/templates_control_panel/main.cpp.tpl2
-rw-r--r--src/tools/ivigenerator/templates_control_panel/qml.qrc.tpl2
11 files changed, 143 insertions, 105 deletions
diff --git a/src/tools/ivigenerator/generate.py b/src/tools/ivigenerator/generate.py
index 39d47b1..157be8b 100755
--- a/src/tools/ivigenerator/generate.py
+++ b/src/tools/ivigenerator/generate.py
@@ -364,8 +364,9 @@ def qml_control_properties(symbol, backend_object):
return 'id: {0}; from:-100000; to: {1}; {2}'.format(prop_str, top, binding)
values = domain_values(symbol)
- if values is None and symbol.type.is_enum:
- values = symbol.type.reference.members
+ if values is None and (symbol.type.is_enum or symbol.type.is_flag):
+ values_string = ' '.join('ListElement {{ key: "{0}"; value: {1}.{0} }}'.format(e, qml_type(symbol.interface)) for e in symbol.type.reference.members)
+ return 'id: {0}; textRole: "key"; {2} model: ListModel {{ {1} }}'.format(prop_str, values_string, binding)
if values is not None:
values_string = ','.join('"'+str(e)+'"' for e in values)
return 'id: {0}; model: [ {1} ]; '.format(prop_str, values_string)
@@ -400,24 +401,6 @@ def qml_meta_control_name(symbol):
if values is not None:
return "ComboBox"
-
-def qml_flag_control(symbol):
- """
- Returns QML code for creation of group of check-boxes for
- the flag property
- """
- # First try to calculate control name based on the tags
- result = qml_meta_control_name(symbol)
- # If nothing is defined, calculate it based on its type
- if result is None and symbol.type.reference.members:
- # form a group of checkboxes
- values = symbol.type.reference.members
- result = ""
- for value in values:
- result+="Text{{ text:'{0}'}} CheckBox {{ id: flag{0}; }}\n".format(value)
- return result
-
-
def qml_type_control_name(symbol):
"""
Returns name of the QML control inferred based on the type of the symbol.
@@ -429,9 +412,11 @@ def qml_type_control_name(symbol):
return "CheckBox"
elif t.is_enum:
if t.reference.is_enum:
- return "ComboBox"
+ return "EnumControl"
elif t.reference.is_flag:
- return qml_flag_control(symbol)
+ return "FlagControl"
+ elif t.is_flag:
+ return "FlagControl"
return "TextField"
@@ -454,8 +439,6 @@ def qml_control(symbol, backend_object):
Returns QML code for the control (or group of controls) to represent the editing UI for the symbol.
"""
- if symbol.type.reference and symbol.type.reference.is_flag:
- return qml_flag_control(symbol)
if symbol.type.is_struct:
return qml_struct_control(symbol)
@@ -470,12 +453,12 @@ def qml_binding_property(symbol):
control_name = qml_control_name(symbol)
if control_name == "CheckBox":
return "checked"
- elif control_name == "Slider" or control_name == "SpinBox":
+ elif control_name == "Slider" or control_name == "SpinBox" or control_name == "FlagControl" or control_name == "EnumControl":
return "value"
elif control_name == "TextField":
return "text"
elif control_name == "ComboBox":
- return "currentText"
+ return "currentIndex"
def qml_struct_control(symbol):
if symbol.type.is_struct and symbol.type.reference.fields:
diff --git a/src/tools/ivigenerator/ivigenerator.pro b/src/tools/ivigenerator/ivigenerator.pro
index ce5fda0..15edf97 100644
--- a/src/tools/ivigenerator/ivigenerator.pro
+++ b/src/tools/ivigenerator/ivigenerator.pro
@@ -53,6 +53,8 @@ templates_generation_validator.files += \
templates_generation_validator.path = $$[QT_HOST_BINS]/ivigenerator/templates_generation_validator
templates_control_panel.files += \
+ templates_control_panel/EnumControl.qml.tpl \
+ templates_control_panel/FlagControl.qml.tpl \
templates_control_panel/generated_comment.cpp.tpl \
templates_control_panel/global.h.tpl \
templates_control_panel/interface.cpp.tpl \
diff --git a/src/tools/ivigenerator/templates_backend_simulator/backend.cpp.tpl b/src/tools/ivigenerator/templates_backend_simulator/backend.cpp.tpl
index 2e56f6a..8516302 100644
--- a/src/tools/ivigenerator/templates_backend_simulator/backend.cpp.tpl
+++ b/src/tools/ivigenerator/templates_backend_simulator/backend.cpp.tpl
@@ -67,6 +67,7 @@ QT_BEGIN_NAMESPACE
{% endfor %}
{
+ {{module.module_name}}Module::registerTypes();
{% set zones = interface.tags.config_simulator.zones if interface.tags.config_simulator else {} %}
{% for zone_name, zone_id in zones.items() %}
ZoneBackend {{zone_name}}Zone;
diff --git a/src/tools/ivigenerator/templates_control_panel.yaml b/src/tools/ivigenerator/templates_control_panel.yaml
index e8297d8..3a7f6e3 100644
--- a/src/tools/ivigenerator/templates_control_panel.yaml
+++ b/src/tools/ivigenerator/templates_control_panel.yaml
@@ -14,6 +14,10 @@ generate_rules:
template_file: "module.h.tpl"
- dest_file: "{{module.module_name|lower}}module.cpp"
template_file: "module.cpp.tpl"
+ - dest_file: "FlagControl.qml"
+ template_file: "FlagControl.qml.tpl"
+ - dest_file: "EnumControl.qml"
+ template_file: "EnumControl.qml.tpl"
interface_rules:
- dest_file: '{{interface}}.qml'
template_file: 'interface.qml.tpl'
diff --git a/src/tools/ivigenerator/templates_control_panel/EnumControl.qml.tpl b/src/tools/ivigenerator/templates_control_panel/EnumControl.qml.tpl
new file mode 100644
index 0000000..9f517e6
--- /dev/null
+++ b/src/tools/ivigenerator/templates_control_panel/EnumControl.qml.tpl
@@ -0,0 +1,31 @@
+import QtQuick 2.7
+import QtQuick.Controls 2.1
+
+ComboBox {
+ id: root
+
+ property var value: 0
+
+ FontMetrics {
+ font: root.font
+ id: _metrics
+ }
+
+ Binding {
+ target: root
+ property: "value"
+ value: model.get(currentIndex).value
+ }
+
+ onValueChanged: {
+ for(var i=0; i<model.count; i++) {
+ if (model.get(i).value == value) {
+ //Make the ComboBox as big as it's content
+ root.implicitWidth = _metrics.boundingRect(model.get(i).key).width + 100
+ currentIndex = i;
+ return;
+ }
+ }
+ console.warn("Couldn't find the value in the EnumControl model: " + value);
+ }
+}
diff --git a/src/tools/ivigenerator/templates_control_panel/FlagControl.qml.tpl b/src/tools/ivigenerator/templates_control_panel/FlagControl.qml.tpl
new file mode 100644
index 0000000..9e5abc6
--- /dev/null
+++ b/src/tools/ivigenerator/templates_control_panel/FlagControl.qml.tpl
@@ -0,0 +1,29 @@
+import QtQuick 2.0
+import QtQuick.Controls 2.1
+import QtQuick.Layouts 1.1
+
+RowLayout {
+ id: root
+ property alias model: repeater.model
+ property int value
+ property string textRole
+
+ spacing: 2
+
+ Repeater {
+ id: repeater
+ RowLayout {
+ Text { text: model[textRole] }
+ CheckBox {
+ id: checkBox
+ checked: root.value & model.value;
+ onClicked: {
+ if (checked)
+ root.value |= model.value
+ else
+ root.value &= ~model.value
+ }
+ }
+ }
+ }
+}
diff --git a/src/tools/ivigenerator/templates_control_panel/interface.cpp.tpl b/src/tools/ivigenerator/templates_control_panel/interface.cpp.tpl
index 7cf85d2..3d00e84 100644
--- a/src/tools/ivigenerator/templates_control_panel/interface.cpp.tpl
+++ b/src/tools/ivigenerator/templates_control_panel/interface.cpp.tpl
@@ -44,7 +44,7 @@
#include "{{class|lower}}.h"
#include <QQmlEngine>
-
+#include <QDebug>
namespace {
const QString INITIAL_MAIN_ZONE = "MainZone";
@@ -57,24 +57,27 @@ QT_BEGIN_NAMESPACE
\inmodule {{module}}
{{ utils.format_comments(interface.comment) }}
*/
-{{class}}::{{class}}(QObject *parent)
+{{class}}::{{class}}(const QString &zone, QObject *parent)
: QObject(parent)
- , m_currentZoneBackend(createZoneBackend())
- , m_currentZone(INITIAL_MAIN_ZONE)
+ , m_currentZone(zone)
{
- m_zones << INITIAL_MAIN_ZONE;
+ if (!zone.isEmpty()) {
+ return;
+ }
+
+ //Add ourself to the available zones to make it available to the UI and still keep the code clean
+ m_zoneHash.insert(INITIAL_MAIN_ZONE, this);
+ m_zoneMap.insert(INITIAL_MAIN_ZONE, QVariant::fromValue(this));
+
{% set zones = interface.tags.config_simulator.zones if interface.tags.config_simulator else {} %}
{% for zone_name, zone_id in zones.items() %}
- m_zones << "{{zone_id}}";
+ addZone("{{zone_id}}");
{% endfor %}
}
/*! \internal */
{{class}}::~{{class}}()
{
-{% if module.tags.config.disablePrivateIVI %}
- delete m_helper;
-{% endif %}
}
/*! \internal */
@@ -89,24 +92,24 @@ void {{class}}::registerQmlTypes(const QString& uri, int majorVersion, int minor
void {{class}}::addZone(const QString &newZone)
{
- bool exists = false;
- for (int i = 0; i < m_zones.count(); ++i) {
- if (m_zones.at(i).toString() == newZone) {
- exists = true;
- break;
- }
+ if (!m_currentZone.isEmpty()) {
+ qWarning("Adding a new zone is only possible from the root zone.");
+ return;
}
- if (!exists) {
- m_zones.append(newZone);
- emit zonesChanged();
- }
-}
+ if (m_zoneHash.contains(newZone))
+ return;
+ {{class}} *zoneObject = new {{class}}(newZone, this);
+ m_zoneHash.insert(newZone, zoneObject);
+ m_zoneMap.insert(newZone, QVariant::fromValue(zoneObject));
-QVariantList {{class}}::zones() const
+ emit zonesChanged();
+}
+
+QStringList {{class}}::zones() const
{
- return m_zones;
+ return m_zoneMap.keys();
}
@@ -115,27 +118,11 @@ QString {{class}}::currentZone() const
return m_currentZone;
}
-
-void {{class}}::setCurrentZone(const QString &zone)
+QVariantMap {{class}}::zoneAt() const
{
- if (zone != m_currentZone) {
-{% if interface_zoned %}
- m_zoneMap[m_currentZone]=m_currentZoneBackend;
- m_currentZone = zone;
- if(m_zoneMap.contains(m_currentZone)) {
- m_currentZoneBackend = m_zoneMap[m_currentZone];
- } else {
- m_currentZoneBackend = createZoneBackend();
- }
-{% endif %}
- emit currentZoneChanged();
-{% for property in interface.properties %}
- emit {{property}}Changed(m_currentZoneBackend.{{property}});
-{% endfor %}
- }
+ return m_zoneMap;
}
-
{% for property in interface.properties %}
/*!
@@ -147,13 +134,15 @@ void {{class}}::setCurrentZone(const QString &zone)
*/
{{property|return_type}} {{class}}::{{property|getter_name}}() const
{
- return m_currentZoneBackend.{{property}};
+ return m_{{property}};
}
void {{class}}::{{property|setter_name}}({{ property|parameter_type }})
{
- m_currentZoneBackend.{{property}} = {{property}};
- emit {{property}}Changed({{property}});
+ if (m_{{property}} == {{property}})
+ return;
+ m_{{property}} = {{property}};
+ emit {{property}}Changed({{property}});
}
{% endfor %}
@@ -170,14 +159,4 @@ void {{class}}::{{property|setter_name}}({{ property|parameter_type }})
{% endfor %}
-{{class}}::ZoneBackend {{class}}::createZoneBackend() {
- ZoneBackend zoneBackend;
-{% for property in interface.properties %}
- zoneBackend.{{property}} = {{property|default_value}};
-{% endfor %}
- return zoneBackend;
-}
-
QT_END_NAMESPACE
-
-#include "moc_{{class|lower}}.cpp"
diff --git a/src/tools/ivigenerator/templates_control_panel/interface.h.tpl b/src/tools/ivigenerator/templates_control_panel/interface.h.tpl
index 04e626d..365ae25 100644
--- a/src/tools/ivigenerator/templates_control_panel/interface.h.tpl
+++ b/src/tools/ivigenerator/templates_control_panel/interface.h.tpl
@@ -49,7 +49,7 @@
#include <QObject>
#include <QHash>
-
+#include <QVariantMap>
QT_BEGIN_NAMESPACE
@@ -62,27 +62,28 @@ class {{exportsymbol}} {{class}} : public QObject {
class {{exportsymbol}} {{class}} : public QObject {
{% endif %}
Q_OBJECT
- Q_PROPERTY(QString currentZone READ currentZone WRITE setCurrentZone NOTIFY currentZoneChanged)
- Q_PROPERTY(QVariantList zones READ zones NOTIFY zonesChanged)
+ Q_PROPERTY(QString currentZone READ currentZone NOTIFY currentZoneChanged)
+ Q_PROPERTY(QStringList zones READ zones NOTIFY zonesChanged)
+ Q_PROPERTY(QVariantMap zoneAt READ zoneAt NOTIFY zonesChanged)
{% for property in interface.properties %}
Q_PROPERTY({{property|return_type}} {{property}} READ {{property|getter_name}} WRITE {{property|setter_name}} NOTIFY {{property}}Changed)
{% endfor %}
Q_CLASSINFO("IviPropertyDomains", "{{ interface.properties|json_domain|replace("\"", "\\\"") }}")
public:
- explicit {{class}}(QObject *parent = nullptr);
+ explicit {{class}}(const QString &zone = QString(), QObject *parent = nullptr);
~{{class}}();
static void registerQmlTypes(const QString& uri, int majorVersion=1, int minorVersion=0, const QString& qmlName = "");
Q_INVOKABLE void addZone(const QString& newZone);
QString currentZone() const;
- QVariantList zones() const;
+ QStringList zones() const;
+ QVariantMap zoneAt() const;
{% for property in interface.properties %}
{{property|return_type}} {{property|getter_name}}() const;
{% endfor %}
public Q_SLOTS:
- void setCurrentZone(const QString& zone);
{% for operation in interface.operations %}
{{operation|return_type}} {{operation}}({{operation.parameters|map('parameter_type')|join(', ')}}){% if operation.const %} const{% endif %};
{% endfor %}
@@ -101,18 +102,15 @@ Q_SIGNALS:
{% endfor %}
private:
- struct ZoneBackend {
{% for property in interface.properties %}
- {{ property|return_type }} {{ property }};
+ {{ property|return_type }} m_{{ property }};
{% endfor %}
- };
- ZoneBackend m_currentZoneBackend ;
{% if interface_zoned %}
- QHash<QString,ZoneBackend> m_zoneMap;
+ QHash<QString,{{class}}*> m_zoneHash;
+ QVariantMap m_zoneMap;
{% endif %}
- QVariantList m_zones;
QString m_currentZone;
- ZoneBackend createZoneBackend();
+ //ZoneBackend createZoneBackend();
};
QT_END_NAMESPACE
diff --git a/src/tools/ivigenerator/templates_control_panel/interface.qml.tpl b/src/tools/ivigenerator/templates_control_panel/interface.qml.tpl
index 6d1f904..e835883 100644
--- a/src/tools/ivigenerator/templates_control_panel/interface.qml.tpl
+++ b/src/tools/ivigenerator/templates_control_panel/interface.qml.tpl
@@ -53,16 +53,15 @@ Flickable {
ScrollBar.vertical: ScrollBar {}
contentHeight: layout.childrenRect.height
- {{interface|qml_type}}Object {
+ {{interface|qml_type}} {
id: {{backend_obj}}
-{% for property in interface.properties %}
- {{property}}: {{property|lowerfirst}}Control.{{property|qml_binding_property}}
-{% endfor%}
-
}
+ property {{interface|qml_type}} currentZoneObject: {{backend_obj}}.zoneAt[comboZones.displayText]
+
ColumnLayout {
id: layout
+ anchors.fill: parent
{% if interface.tags.config.zoned %}
RowLayout {
Text {
@@ -73,12 +72,7 @@ Flickable {
id: comboZones
editable: true
model: {{backend_obj}}.zones
- onCurrentIndexChanged: {
- var newZone = comboZones.textAt(comboZones.currentIndex)
- if (newZone !== "") {
- {{backend_obj}}.currentZone = newZone
- }
- }
+ currentIndex: {{backend_obj}}.zones.indexOf("MainZone")
}
Button {
text:"+"
@@ -100,10 +94,25 @@ Flickable {
{% for property in interface.properties %}
RowLayout {
height: 30
+ Layout.fillWidth: true
Text {
text: "{{property|upperfirst}}: "
}
- {{property|qml_control(backend_obj)}}
+
+ Connections {
+ target: {{property|lowerfirst}}Control
+ on{{property|qml_binding_property|upperfirst}}Changed: {
+ currentZoneObject.{{property}} = {{property|lowerfirst}}Control.{{property|qml_binding_property}}
+ }
+ }
+
+ Binding {
+ target: {{property|lowerfirst}}Control
+ property: "{{property|qml_binding_property}}"
+ value: currentZoneObject.{{property}}
+ }
+
+ {{property|qml_control('currentZoneObject')}}
}
{% endfor %}
{% if interface.operations|count %}
diff --git a/src/tools/ivigenerator/templates_control_panel/main.cpp.tpl b/src/tools/ivigenerator/templates_control_panel/main.cpp.tpl
index 14fed35..006f67f 100644
--- a/src/tools/ivigenerator/templates_control_panel/main.cpp.tpl
+++ b/src/tools/ivigenerator/templates_control_panel/main.cpp.tpl
@@ -53,7 +53,7 @@ int main(int argc, char *argv[])
{% for interface in module.interfaces %}
{{interface}}::registerQmlTypes(QLatin1String("QtIvi.ControlPanel"), 1, 0,
- QLatin1String("{{interface|qml_type}}Object"));
+ QLatin1String("{{interface|qml_type}}"));
{% endfor %}
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
diff --git a/src/tools/ivigenerator/templates_control_panel/qml.qrc.tpl b/src/tools/ivigenerator/templates_control_panel/qml.qrc.tpl
index e95c473..2a6d015 100644
--- a/src/tools/ivigenerator/templates_control_panel/qml.qrc.tpl
+++ b/src/tools/ivigenerator/templates_control_panel/qml.qrc.tpl
@@ -40,6 +40,8 @@
<RCC>
<qresource prefix="/">
<file>main.qml</file>
+ <file>EnumControl.qml</file>
+ <file>FlagControl.qml</file>
{% for interface in module.interfaces %}
<file>{{interface}}.qml</file>
{% endfor %}