From 93c91d71bdd65b0b976b9939e7bf9e8012e72d52 Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Sun, 25 Feb 2018 05:48:36 +0100 Subject: [PATCH] more work --- guh-control/basicconfiguration.cpp | 57 ++++++ guh-control/basicconfiguration.h | 39 ++++ guh-control/devicemanager.cpp | 52 +++++ guh-control/devicemanager.h | 8 + guh-control/engine.cpp | 10 +- guh-control/engine.h | 12 +- guh-control/guh-control.pro | 6 +- guh-control/jsonrpc/jsontypes.cpp | 10 +- guh-control/jsonrpc/jsontypes.h | 1 + guh-control/main.cpp | 4 + guh-control/models/logsmodel.cpp | 3 +- guh-control/resources.qrc | 5 +- guh-control/rulemanager.cpp | 6 +- guh-control/ui/MainPage.qml | 4 +- guh-control/ui/SettingsPage.qml | 173 +++++++++++----- .../ui/actiondelegates/ActionDelegateBool.qml | 2 +- .../actiondelegates/ActionDelegateSlider.qml | 2 +- .../ActionDelegateStringFromStringList.qml | 2 +- guh-control/ui/components/ErrorDialog.qml | 20 ++ .../devicelistpages/GenericDeviceListPage.qml | 4 +- .../ui/devicepages/ConfigureThingPage.qml | 24 +-- guh-control/ui/devicepages/DevicePageBase.qml | 6 + .../ui/devicepages/GenericDevicePage.qml | 2 +- .../GenericDeviceStateDetailsPage.qml | 17 +- .../ui/devicepages/SensorDevicePage.qml | 15 +- guh-control/ui/magic/NewRulePage.qml | 132 ------------ .../ui/magic/SelectRuleActionParamsPage.qml | 6 +- .../ui/paramdelegates-ng/ParamDelegate.qml | 193 ++++++++++++++++++ .../ui/paramdelegates/BoolParamDelegate.qml | 25 +-- .../ui/paramdelegates/DoubleParamDelegate.qml | 2 +- .../ui/paramdelegates/IntParamDelegate.qml | 6 +- .../ParamDescriptorDelegateBase.qml | 156 +++++++++----- guh-control/ui/system/LogViewerPage.qml | 6 +- guh-control/ui/system/PluginParamsPage.qml | 63 ++++++ guh-control/ui/system/PluginsPage.qml | 38 ++++ libguh-common/types/param.cpp | 16 +- libguh-common/types/param.h | 12 +- libguh-common/types/paramdescriptor.cpp | 2 +- libguh-common/types/paramdescriptors.cpp | 6 +- libguh-common/types/params.cpp | 4 +- libguh-common/types/paramtypes.cpp | 6 + libguh-common/types/paramtypes.h | 2 + libguh-common/types/plugin.cpp | 2 +- libguh-common/types/plugin.h | 4 +- 44 files changed, 835 insertions(+), 330 deletions(-) create mode 100644 guh-control/basicconfiguration.cpp create mode 100644 guh-control/basicconfiguration.h create mode 100644 guh-control/ui/components/ErrorDialog.qml delete mode 100644 guh-control/ui/magic/NewRulePage.qml create mode 100644 guh-control/ui/paramdelegates-ng/ParamDelegate.qml create mode 100644 guh-control/ui/system/PluginParamsPage.qml create mode 100644 guh-control/ui/system/PluginsPage.qml diff --git a/guh-control/basicconfiguration.cpp b/guh-control/basicconfiguration.cpp new file mode 100644 index 00000000..49aa393e --- /dev/null +++ b/guh-control/basicconfiguration.cpp @@ -0,0 +1,57 @@ +#include "basicconfiguration.h" + +#include "jsonrpc/jsonrpcclient.h" + +BasicConfiguration::BasicConfiguration(JsonRpcClient* client, QObject *parent) : + QObject(parent), + m_client(client) +{ + +} + +bool BasicConfiguration::debugServerEnabled() const +{ + return m_debugServerEnabled; +} + +void BasicConfiguration::setDebugServerEnabled(bool debugServerEnabled) +{ + QVariantMap params; + params.insert("enabled", debugServerEnabled); + m_client->sendCommand("Configuration.SetDebugServerEnabled", params, this, "setDebugServerEnabledResponse"); +} + +QString BasicConfiguration::serverName() const +{ + return m_serverName; +} + +void BasicConfiguration::setServerName(const QString &serverName) +{ + QVariantMap params; + params.insert("serverName", serverName); + m_client->sendCommand("Configuration.SetServerName", params, this, "setServerNameResponse"); +} + +void BasicConfiguration::init() +{ + m_client->sendCommand("Configuration.GetConfigurations", this, "getConfigurationsResponse"); +} + +void BasicConfiguration::getConfigurationsResponse(const QVariantMap ¶ms) +{ + qDebug() << "have config reply" << params; + QVariantMap basicConfig = params.value("params").toMap().value("basicConfiguration").toMap(); + m_debugServerEnabled = basicConfig.value("debugServerEnabled").toBool(); + m_serverName = basicConfig.value("serverName").toString(); +} + +void BasicConfiguration::setDebugServerEnabledResponse(const QVariantMap ¶ms) +{ + qDebug() << "Debug server set:" << params; +} + +void BasicConfiguration::setServerNameResponse(const QVariantMap ¶ms) +{ + qDebug() << "Server name set:" << params; +} diff --git a/guh-control/basicconfiguration.h b/guh-control/basicconfiguration.h new file mode 100644 index 00000000..c0451539 --- /dev/null +++ b/guh-control/basicconfiguration.h @@ -0,0 +1,39 @@ +#ifndef BASICCONFIGURATION_H +#define BASICCONFIGURATION_H + +#include + +class JsonRpcClient; + +class BasicConfiguration : public QObject +{ + Q_OBJECT + Q_PROPERTY(bool debugServerEnabled READ debugServerEnabled WRITE setDebugServerEnabled NOTIFY debugServerEnabledChanged) + Q_PROPERTY(QString serverName READ serverName WRITE setServerName NOTIFY serverNameChanged) +public: + explicit BasicConfiguration(JsonRpcClient* client, QObject *parent = nullptr); + + bool debugServerEnabled() const; + void setDebugServerEnabled(bool debugServerEnabled); + + QString serverName() const; + void setServerName(const QString &serverName); + + void init(); + +private: + Q_INVOKABLE void getConfigurationsResponse(const QVariantMap ¶ms); + Q_INVOKABLE void setDebugServerEnabledResponse(const QVariantMap ¶ms); + Q_INVOKABLE void setServerNameResponse(const QVariantMap ¶ms); + +signals: + void debugServerEnabledChanged(); + void serverNameChanged(); + +private: + JsonRpcClient* m_client = nullptr; + bool m_debugServerEnabled = false; + QString m_serverName; +}; + +#endif // BASICCONFIGURATION_H diff --git a/guh-control/devicemanager.cpp b/guh-control/devicemanager.cpp index c6930b63..b326ae75 100644 --- a/guh-control/devicemanager.cpp +++ b/guh-control/devicemanager.cpp @@ -151,6 +151,35 @@ void DeviceManager::getPluginsResponse(const QVariantMap ¶ms) } } m_jsonClient->sendCommand("Devices.GetSupportedVendors", this, "getVendorsResponse"); + + if (m_plugins->count() > 0) { + m_currentGetConfigIndex = 0; + QVariantMap configRequestParams; + configRequestParams.insert("pluginId", m_plugins->get(m_currentGetConfigIndex)->pluginId()); + m_jsonClient->sendCommand("Devices.GetPluginConfiguration", configRequestParams, this, "getPluginConfigResponse"); + } +} + +void DeviceManager::getPluginConfigResponse(const QVariantMap ¶ms) +{ + qDebug() << "plugin config response" << params; + Plugin *p = m_plugins->get(m_currentGetConfigIndex); + if (!p) { + qDebug() << "Received a plugin config for a plugin we don't know"; + return; + } + QVariantList pluginParams = params.value("params").toMap().value("configuration").toList(); + foreach (const QVariant ¶mVariant, pluginParams) { + Param* param = JsonTypes::unpackParam(paramVariant.toMap(), p->params()); + p->params()->addParam(param); + } + + m_currentGetConfigIndex++; + if (m_plugins->count() > m_currentGetConfigIndex) { + QVariantMap configRequestParams; + configRequestParams.insert("pluginId", m_plugins->get(m_currentGetConfigIndex)->pluginId()); + m_jsonClient->sendCommand("Devices.GetPluginConfiguration", configRequestParams, this, "getPluginConfigResponse"); + } } void DeviceManager::getConfiguredDevicesResponse(const QVariantMap ¶ms) @@ -221,6 +250,29 @@ void DeviceManager::confirmPairingResponse(const QVariantMap ¶ms) emit confirmPairingReply(params.value("params").toMap()); } +void DeviceManager::setPluginConfigResponse(const QVariantMap ¶ms) +{ + qDebug() << "set plugin config respionse" << params; + emit savePluginConfigReply(params); +} + +void DeviceManager::savePluginConfig(const QUuid &pluginId) +{ + Plugin *p = m_plugins->getPlugin(pluginId); + if (!p) { + qWarning()<< "Error: can't find plugin with id" << pluginId; + return; + } + QVariantMap params; + params.insert("pluginId", pluginId); + QVariantList pluginParams; + for (int i = 0; i < p->params()->rowCount(); i++) { + pluginParams.append(JsonTypes::packParam(p->params()->get(i))); + } + params.insert("configuration", pluginParams); + m_jsonClient->sendCommand("Devices.SetPluginConfiguration", params, this, "setPluginConfigResponse"); +} + void DeviceManager::addDiscoveredDevice(const QUuid &deviceClassId, const QUuid &deviceDescriptorId, const QString &name) { qDebug() << "JsonRpc: add discovered device " << deviceClassId.toString(); diff --git a/guh-control/devicemanager.h b/guh-control/devicemanager.h index 74f2f621..01a2bba7 100644 --- a/guh-control/devicemanager.h +++ b/guh-control/devicemanager.h @@ -63,17 +63,23 @@ private: Q_INVOKABLE void getVendorsResponse(const QVariantMap ¶ms); Q_INVOKABLE void getSupportedDevicesResponse(const QVariantMap ¶ms); Q_INVOKABLE void getPluginsResponse(const QVariantMap ¶ms); + Q_INVOKABLE void getPluginConfigResponse(const QVariantMap ¶ms); Q_INVOKABLE void getConfiguredDevicesResponse(const QVariantMap ¶ms); Q_INVOKABLE void addDeviceResponse(const QVariantMap ¶ms); Q_INVOKABLE void removeDeviceResponse(const QVariantMap ¶ms); Q_INVOKABLE void pairDeviceResponse(const QVariantMap ¶ms); Q_INVOKABLE void confirmPairingResponse(const QVariantMap ¶ms); + Q_INVOKABLE void setPluginConfigResponse(const QVariantMap ¶ms); + +public slots: + void savePluginConfig(const QUuid &pluginId); signals: void pairDeviceReply(const QVariantMap ¶ms); void confirmPairingReply(const QVariantMap ¶ms); void addDeviceReply(const QVariantMap ¶ms); void removeDeviceReply(const QVariantMap ¶ms); + void savePluginConfigReply(const QVariantMap ¶ms); private: Vendors *m_vendors; @@ -81,6 +87,8 @@ private: Devices *m_devices; DeviceClasses *m_deviceClasses; + int m_currentGetConfigIndex = 0; + JsonRpcClient *m_jsonClient = nullptr; }; diff --git a/guh-control/engine.cpp b/guh-control/engine.cpp index 71734b44..153e3b68 100644 --- a/guh-control/engine.cpp +++ b/guh-control/engine.cpp @@ -23,6 +23,7 @@ #include "tcpsocketinterface.h" #include "rulemanager.h" #include "logmanager.h" +#include "basicconfiguration.h" Engine* Engine::s_instance = 0; @@ -62,6 +63,11 @@ LogManager *Engine::logManager() const return m_logManager; } +BasicConfiguration *Engine::basicConfiguration() const +{ + return m_basicConfiguration; +} + GuhConnection *Engine::connection() const { return m_connection; @@ -73,7 +79,8 @@ Engine::Engine(QObject *parent) : m_jsonRpcClient(new JsonRpcClient(m_connection, this)), m_deviceManager(new DeviceManager(m_jsonRpcClient, this)), m_ruleManager(new RuleManager(m_jsonRpcClient, this)), - m_logManager(new LogManager(m_jsonRpcClient, this)) + m_logManager(new LogManager(m_jsonRpcClient, this)), + m_basicConfiguration(new BasicConfiguration(m_jsonRpcClient, this)) { connect(m_jsonRpcClient, &JsonRpcClient::connectedChanged, this, &Engine::onConnectedChanged); connect(m_jsonRpcClient, &JsonRpcClient::authenticationRequiredChanged, this, &Engine::onConnectedChanged); @@ -88,6 +95,7 @@ void Engine::onConnectedChanged() if (!m_jsonRpcClient->initialSetupRequired() && !m_jsonRpcClient->authenticationRequired()) { m_deviceManager->init(); m_ruleManager->init(); + m_basicConfiguration->init(); } } } diff --git a/guh-control/engine.h b/guh-control/engine.h index bc8d2250..a5f01380 100644 --- a/guh-control/engine.h +++ b/guh-control/engine.h @@ -31,14 +31,16 @@ class RuleManager; class LogManager; +class BasicConfiguration; class Engine : public QObject { Q_OBJECT - Q_PROPERTY(GuhConnection *connection READ connection CONSTANT) - Q_PROPERTY(DeviceManager *deviceManager READ deviceManager CONSTANT) - Q_PROPERTY(RuleManager *ruleManager READ ruleManager CONSTANT) - Q_PROPERTY(JsonRpcClient *jsonRpcClient READ jsonRpcClient CONSTANT) + Q_PROPERTY(GuhConnection* connection READ connection CONSTANT) + Q_PROPERTY(DeviceManager* deviceManager READ deviceManager CONSTANT) + Q_PROPERTY(RuleManager* ruleManager READ ruleManager CONSTANT) + Q_PROPERTY(JsonRpcClient* jsonRpcClient READ jsonRpcClient CONSTANT) + Q_PROPERTY(BasicConfiguration* basicConfiguration READ basicConfiguration CONSTANT) public: static Engine *instance(); @@ -52,6 +54,7 @@ public: RuleManager *ruleManager() const; JsonRpcClient *jsonRpcClient() const; LogManager *logManager() const; + BasicConfiguration* basicConfiguration() const; private: explicit Engine(QObject *parent = 0); @@ -62,6 +65,7 @@ private: DeviceManager *m_deviceManager; RuleManager *m_ruleManager; LogManager *m_logManager; + BasicConfiguration *m_basicConfiguration; private slots: void onConnectedChanged(); diff --git a/guh-control/guh-control.pro b/guh-control/guh-control.pro index f0d44b49..9ee099d9 100644 --- a/guh-control/guh-control.pro +++ b/guh-control/guh-control.pro @@ -36,7 +36,8 @@ HEADERS += engine.h \ models/logsmodel.h \ models/valuelogsproxymodel.h \ discovery/guhdiscovery.h \ - logmanager.h + logmanager.h \ + basicconfiguration.h SOURCES += main.cpp \ @@ -68,7 +69,8 @@ SOURCES += main.cpp \ models/logsmodel.cpp \ models/valuelogsproxymodel.cpp \ discovery/guhdiscovery.cpp \ - logmanager.cpp + logmanager.cpp \ + basicconfiguration.cpp withavahi { DEFINES += WITH_AVAHI diff --git a/guh-control/jsonrpc/jsontypes.cpp b/guh-control/jsonrpc/jsontypes.cpp index 83953e50..cb2d3277 100644 --- a/guh-control/jsonrpc/jsontypes.cpp +++ b/guh-control/jsonrpc/jsontypes.cpp @@ -254,7 +254,7 @@ QVariantMap JsonTypes::packRule(Rule *rule) QVariantList paramDescriptors; for (int j = 0; j < rule->eventDescriptors()->get(i)->paramDescriptors()->rowCount(); j++) { QVariantMap paramDescriptor; - paramDescriptor.insert("paramTypeId", rule->eventDescriptors()->get(i)->paramDescriptors()->get(j)->id()); + paramDescriptor.insert("paramTypeId", rule->eventDescriptors()->get(i)->paramDescriptors()->get(j)->paramTypeId()); paramDescriptor.insert("value", rule->eventDescriptors()->get(i)->paramDescriptors()->get(j)->value()); QMetaEnum operatorEnum = QMetaEnum::fromType(); paramDescriptor.insert("operator", operatorEnum.valueToKey(rule->eventDescriptors()->get(i)->paramDescriptors()->get(j)->operatorType())); @@ -270,6 +270,14 @@ QVariantMap JsonTypes::packRule(Rule *rule) return ret; } +QVariantMap JsonTypes::packParam(Param *param) +{ + QVariantMap ret; + ret.insert("paramTypeId", param->paramTypeId()); + ret.insert("value", param->value()); + return ret; +} + DeviceClass::SetupMethod JsonTypes::stringToSetupMethod(const QString &setupMethodString) { if (setupMethodString == "SetupMethodJustAdd") { diff --git a/guh-control/jsonrpc/jsontypes.h b/guh-control/jsonrpc/jsontypes.h index e750fc7c..6c447079 100644 --- a/guh-control/jsonrpc/jsontypes.h +++ b/guh-control/jsonrpc/jsontypes.h @@ -56,6 +56,7 @@ public: static Device *unpackDevice(const QVariantMap &deviceMap, QObject *parent); static QVariantMap packRule(Rule* rule); + static QVariantMap packParam(Param *param); private: static DeviceClass::SetupMethod stringToSetupMethod(const QString &setupMethodString); static QList stringListToBasicTags(const QStringList &basicTagsStringList); diff --git a/guh-control/main.cpp b/guh-control/main.cpp index fa740a6c..6a27edad 100644 --- a/guh-control/main.cpp +++ b/guh-control/main.cpp @@ -44,6 +44,7 @@ #include "types/rule.h" #include "models/logsmodel.h" #include "models/valuelogsproxymodel.h" +#include "basicconfiguration.h" int main(int argc, char *argv[]) { @@ -105,6 +106,7 @@ int main(int argc, char *argv[]) qmlRegisterUncreatableType(uri, 1, 0, "EventDescriptor", "Get them from rules"); qmlRegisterUncreatableType(uri, 1, 0, "ParamTypes", "Uncreatable"); qmlRegisterUncreatableType(uri, 1, 0, "ParamType", "Uncreatable"); + qmlRegisterType(uri, 1, 0, "Param"); qmlRegisterUncreatableType(uri, 1, 0, "ParamDescriptor", "Uncreatable"); qmlRegisterUncreatableType(uri, 1, 0, "ParamDescriptors", "Uncreatable"); @@ -112,6 +114,8 @@ int main(int argc, char *argv[]) qmlRegisterUncreatableType(uri, 1, 0, "Plugins", "Can't create this in QML. Get it from the DeviceManager."); qmlRegisterType(uri, 1, 0, "PluginsProxy"); + qmlRegisterUncreatableType(uri, 1, 0, "BasicConfiguration", "Uncreatable"); + qmlRegisterType(uri, 1, 0, "GuhDiscovery"); qmlRegisterUncreatableType(uri, 1, 0, "DiscoveryModel", "Get it from GuhDiscovery"); diff --git a/guh-control/models/logsmodel.cpp b/guh-control/models/logsmodel.cpp index 7dea1170..5fbe49de 100644 --- a/guh-control/models/logsmodel.cpp +++ b/guh-control/models/logsmodel.cpp @@ -15,6 +15,7 @@ bool LogsModel::busy() const int LogsModel::rowCount(const QModelIndex &parent) const { + Q_UNUSED(parent) return m_list.count(); } @@ -174,7 +175,6 @@ void LogsModel::logsReply(const QVariantMap &data) LogEntry::LoggingEventType loggingEventType = (LogEntry::LoggingEventType)loggingEventTypeEnum.keyToValue(entryMap.value("eventType").toByteArray()); LogEntry *entry = new LogEntry(timeStamp, value, deviceId, typeId, loggingSource, loggingEventType, this); m_list.append(entry); - qDebug() << "Added log entry" << entry->dayString() << entry->value() << entry->deviceId() << entryMap << loggingEventType; } endResetModel(); @@ -199,7 +199,6 @@ void LogsModel::newLogEntryReceived(const QVariantMap &data) LogEntry::LoggingEventType loggingEventType = (LogEntry::LoggingEventType)loggingEventTypeEnum.keyToValue(entryMap.value("eventType").toByteArray()); LogEntry *entry = new LogEntry(timeStamp, value, deviceId, typeId, loggingSource, loggingEventType, this); m_list.append(entry); - qDebug() << "Added log entry" << entry->dayString() << entry->value() << entry->deviceId() << entryMap << loggingEventType; endInsertRows(); emit countChanged(); } diff --git a/guh-control/resources.qrc b/guh-control/resources.qrc index 3f21d68d..44a62967 100644 --- a/guh-control/resources.qrc +++ b/guh-control/resources.qrc @@ -34,7 +34,6 @@ ui/images/torch-on.svg ui/images/media-preview-start.svg ui/MagicPage.qml - ui/magic/NewRulePage.qml ui/images/mediaplayer-app-symbolic.svg ui/images/system-shutdown.svg ui/devicepages/ButtonDevicePage.qml @@ -121,5 +120,9 @@ ui/system/LogViewerPage.qml ui/images/next.svg ui/images/go-down.svg + ui/system/PluginsPage.qml + ui/system/PluginParamsPage.qml + ui/paramdelegates-ng/ParamDelegate.qml + ui/components/ErrorDialog.qml diff --git a/guh-control/rulemanager.cpp b/guh-control/rulemanager.cpp index dece0786..3dbf7f13 100644 --- a/guh-control/rulemanager.cpp +++ b/guh-control/rulemanager.cpp @@ -74,7 +74,7 @@ void RuleManager::editRule(Rule *rule) void RuleManager::handleRulesNotification(const QVariantMap ¶ms) { - qDebug() << "rules notification received" << params; +// qDebug() << "rules notification received" << params; if (params.value("notification").toString() == "Rules.RuleAdded") { QVariantMap ruleMap = params.value("params").toMap().value("rule").toMap(); QUuid ruleId = ruleMap.value("id").toUuid(); @@ -94,6 +94,8 @@ void RuleManager::handleRulesNotification(const QVariantMap ¶ms) } else if (params.value("notification").toString() == "Rules.RuleRemoved") { QUuid ruleId = params.value("params").toMap().value("ruleId").toUuid(); m_rules->remove(ruleId); + } else { + qWarning() << "Unhandled rule notification" << params; } } @@ -146,7 +148,7 @@ void RuleManager::removeRuleReply(const QVariantMap ¶ms) void RuleManager::onEditRuleReply(const QVariantMap ¶ms) { - qDebug() << "Edit rule reply:" << params.value("params").toMap(); + qDebug() << "Edit rule reply:" << params.value("params").toMap().value("ruleError").toString(); emit editRuleReply(params.value("params").toMap().value("ruleError").toString()); } diff --git a/guh-control/ui/MainPage.qml b/guh-control/ui/MainPage.qml index 433b48a6..f136675e 100644 --- a/guh-control/ui/MainPage.qml +++ b/guh-control/ui/MainPage.qml @@ -37,7 +37,7 @@ Page { MenuSeparator {} IconMenuItem { iconSource: "../images/settings.svg" - text: "App settings" + text: "Settings" onTriggered: pageStack.push(Qt.resolvedUrl("SettingsPage.qml")) } MenuSeparator {} @@ -50,13 +50,13 @@ Page { ColumnLayout { anchors.fill: parent - anchors.margins: app.margins SwipeView { id: swipeView Layout.fillWidth: true Layout.fillHeight: true currentIndex: pageIndicator.currentIndex + clip: true DevicesPage { width: parent.view.width diff --git a/guh-control/ui/SettingsPage.qml b/guh-control/ui/SettingsPage.qml index 090e53ae..4f7943eb 100644 --- a/guh-control/ui/SettingsPage.qml +++ b/guh-control/ui/SettingsPage.qml @@ -14,74 +14,141 @@ Page { } ColumnLayout { - anchors { left: parent.left; right: parent.right; top: parent.top; margins: app.margins } + anchors { left: parent.left; right: parent.right; top: parent.top } + + ColumnLayout { + Layout.fillWidth: true + Layout.margins: app.margins + + Label { + text: "Application".toUpperCase() + color: app.guhAccent + Layout.fillWidth: true + } + + RowLayout { + Layout.fillWidth: true + Label { + Layout.fillWidth: true + text: "View mode" + } + ComboBox { + model: ["Windowed", "Maximized", "Fullscreen"] + currentIndex: { + switch (settings.viewMode) { + case ApplicationWindow.Windowed: + return 0; + case ApplicationWindow.Maximized: + return 1; + case ApplicationWindow.FullScreen: + return 2; + } + } + + onCurrentIndexChanged: { + switch (currentIndex) { + case 0: + settings.viewMode = ApplicationWindow.Windowed; + break; + case 1: + settings.viewMode = ApplicationWindow.Maximized; + break; + case 2: + settings.viewMode = ApplicationWindow.FullScreen; + } + } + } + } + RowLayout { + Layout.fillWidth: true + Label { + Layout.fillWidth: true + text: "Return to home on idle" + } + CheckBox { + checked: settings.returnToHome + onClicked: settings.returnToHome = checked + } + } + RowLayout { + Layout.fillWidth: true + Label { + Layout.fillWidth: true + text: "Graph style" + } + RadioButton { + checked: settings.graphStyle === "bars" + text: "Bars" + onClicked: settings.graphStyle = "bars" + } + RadioButton { + checked: settings.graphStyle === "bezier" + text: "Lines" + onClicked: settings.graphStyle = "bezier" + } + + } + } + + + ThinDivider {} Label { Layout.fillWidth: true - text: "Application".toUpperCase() + Layout.leftMargin: app.margins + Layout.rightMargin: app.margins + Layout.topMargin: app.margins + text: "System".toUpperCase() color: app.guhAccent } + RowLayout { Layout.fillWidth: true + Layout.leftMargin: app.margins + Layout.rightMargin: app.margins + spacing: app.margins Label { + text: qsTr("Debug server enabled") Layout.fillWidth: true - text: "View mode" } - ComboBox { - model: ["Windowed", "Maximized", "Fullscreen"] - currentIndex: { - switch (settings.viewMode) { - case ApplicationWindow.Windowed: - return 0; - case ApplicationWindow.Maximized: - return 1; - case ApplicationWindow.FullScreen: - return 2; - } - } + Switch { + checked: Engine.basicConfiguration.debugServerEnabled + onClicked: Engine.basicConfiguration.debugServerEnabled = checked + } + } - onCurrentIndexChanged: { - switch (currentIndex) { - case 0: - settings.viewMode = ApplicationWindow.Windowed; - break; - case 1: - settings.viewMode = ApplicationWindow.Maximized; - break; - case 2: - settings.viewMode = ApplicationWindow.FullScreen; - } + RowLayout { + Layout.fillWidth: true + Layout.leftMargin: app.margins + Layout.rightMargin: app.margins + spacing: app.margins + Label { + text: qsTr("Server name") + } + TextField { + Layout.fillWidth: true + text: Engine.basicConfiguration.serverName + onAccepted: Engine.basicConfiguration.serverName = text + } + } + + ItemDelegate { + Layout.fillWidth: true + contentItem: RowLayout { + Label { + Layout.fillWidth: true + text: "Plugins" + } + Image { + source: "images/next.svg" + Layout.preferredHeight: parent.height + Layout.preferredWidth: height } } - } - RowLayout { - Layout.fillWidth: true - Label { - Layout.fillWidth: true - text: "Return to home on idle" - } - CheckBox { - checked: settings.returnToHome - onClicked: settings.returnToHome = checked + onClicked: { + pageStack.push(Qt.resolvedUrl("system/PluginsPage.qml")) } } - RowLayout { - Layout.fillWidth: true - Label { - Layout.fillWidth: true - text: "Graph style" - } - RadioButton { - checked: settings.graphStyle === "bars" - text: "Bars" - onClicked: settings.graphStyle = "bars" - } - RadioButton { - checked: settings.graphStyle === "bezier" - text: "Lines" - onClicked: settings.graphStyle = "bezier" - } - } } } diff --git a/guh-control/ui/actiondelegates/ActionDelegateBool.qml b/guh-control/ui/actiondelegates/ActionDelegateBool.qml index 9b1888a0..1a931126 100644 --- a/guh-control/ui/actiondelegates/ActionDelegateBool.qml +++ b/guh-control/ui/actiondelegates/ActionDelegateBool.qml @@ -14,7 +14,7 @@ ActionDelegateBase { Label { Layout.fillWidth: true verticalAlignment: Text.AlignVCenter - text: root.actionType ? root.actionType.name : "" + text: root.actionType ? root.actionType.displayName : "" } Switch { position: root.actionState ? root.actionState : 0 diff --git a/guh-control/ui/actiondelegates/ActionDelegateSlider.qml b/guh-control/ui/actiondelegates/ActionDelegateSlider.qml index c67fbe7c..826ca616 100644 --- a/guh-control/ui/actiondelegates/ActionDelegateSlider.qml +++ b/guh-control/ui/actiondelegates/ActionDelegateSlider.qml @@ -12,7 +12,7 @@ ActionDelegateBase { Label { Layout.fillWidth: true - text: root.actionType.paramTypes.get(0).name + text: root.actionType.paramTypes.get(0).displayName } Slider { diff --git a/guh-control/ui/actiondelegates/ActionDelegateStringFromStringList.qml b/guh-control/ui/actiondelegates/ActionDelegateStringFromStringList.qml index 19d90d14..267ff7f5 100644 --- a/guh-control/ui/actiondelegates/ActionDelegateStringFromStringList.qml +++ b/guh-control/ui/actiondelegates/ActionDelegateStringFromStringList.qml @@ -11,7 +11,7 @@ ActionDelegateBase { id: layout anchors { left: parent.left; top: parent.top; right: parent.right; margins: app.margins } Label { - text: root.paramType.name + text: root.paramType.displayName Layout.fillWidth: true } ComboBox { diff --git a/guh-control/ui/components/ErrorDialog.qml b/guh-control/ui/components/ErrorDialog.qml new file mode 100644 index 00000000..bf6bf41d --- /dev/null +++ b/guh-control/ui/components/ErrorDialog.qml @@ -0,0 +1,20 @@ +import QtQuick 2.8 +import QtQuick.Controls 2.1 + +Dialog { + width: parent.width * .6 + height: parent.height * .6 + x: (parent.width - width) / 2 + y: (parent.height - height) / 2 + + title: qsTr("Error") + property alias text: contentLabel.text + + standardButtons: Dialog.Ok + + Label { + id: contentLabel + width: parent.width + wrapMode: Text.WordWrap + } +} diff --git a/guh-control/ui/devicelistpages/GenericDeviceListPage.qml b/guh-control/ui/devicelistpages/GenericDeviceListPage.qml index 994d9e64..ddf5901a 100644 --- a/guh-control/ui/devicelistpages/GenericDeviceListPage.qml +++ b/guh-control/ui/devicelistpages/GenericDeviceListPage.qml @@ -39,8 +39,8 @@ Page { page = "ButtonDevicePage.qml"; } else if (deviceClass.interfaces.indexOf("weather") >= 0) { page = "WeatherDevicePage.qml"; -// } else if (deviceClass.interfaces.indexOf("sensor") >= 0) { -// page = "SensorDevicePage.qml"; + } else if (deviceClass.interfaces.indexOf("sensor") >= 0) { + page = "SensorDevicePage.qml"; } else { page = "GenericDevicePage.qml"; } diff --git a/guh-control/ui/devicepages/ConfigureThingPage.qml b/guh-control/ui/devicepages/ConfigureThingPage.qml index 789ca806..e293dd71 100644 --- a/guh-control/ui/devicepages/ConfigureThingPage.qml +++ b/guh-control/ui/devicepages/ConfigureThingPage.qml @@ -3,6 +3,7 @@ import QtQuick.Controls 2.1 import QtQuick.Layouts 1.2 import Guh 1.0 import "../components" +import "../paramdelegates-ng" Page { id: root @@ -29,25 +30,24 @@ Page { pageStack.pop(); return; } - print("Remove device error!", params) + var popup = errorDialog.createObject(root, {text: "Remove device error: " + JSON.stringify(params.deviceError) }) + popup.open(); } } ListView { anchors.fill: parent model: root.device.params - delegate: ItemDelegate { + delegate: ParamDelegate { width: parent.width - contentItem: RowLayout { - Label { - text: root.deviceClass.paramTypes.getParamType(model.id).displayName - } - Label { - Layout.fillWidth: true - text: model.value - horizontalAlignment: Text.AlignRight - } - } + paramType: root.deviceClass.paramTypes.getParamType(model.id) + param: root.device.params.get(index) + writable: false } } + + Component { + id: errorDialog + ErrorDialog { } + } } diff --git a/guh-control/ui/devicepages/DevicePageBase.qml b/guh-control/ui/devicepages/DevicePageBase.qml index d431112d..47268286 100644 --- a/guh-control/ui/devicepages/DevicePageBase.qml +++ b/guh-control/ui/devicepages/DevicePageBase.qml @@ -42,6 +42,11 @@ Page { height: app.iconSize } + Label { + text: qsTr("Thing is not connected!") + visible: infoPane.connectedState !== null && infoPane.connectedState.value === false + } + ColorIcon { height: app.iconSize width: height @@ -54,6 +59,7 @@ Page { height: app.iconSize width: height * 1.23 name: infoPane.batteryState !== null ? "../images/battery/battery-" + ("00" + (Math.floor(infoPane.batteryState.value / 10) * 10)).slice(-3) + ".svg" : "" + visible: infoPane.batteryState !== null } } } diff --git a/guh-control/ui/devicepages/GenericDevicePage.qml b/guh-control/ui/devicepages/GenericDevicePage.qml index 97dfd9fe..80fecea9 100644 --- a/guh-control/ui/devicepages/GenericDevicePage.qml +++ b/guh-control/ui/devicepages/GenericDevicePage.qml @@ -27,7 +27,7 @@ DevicePageBase { id: interfaceViewsRepeater property bool unhandledInterface: false - model: deviceClass.interfaces +// model: deviceClass.interfaces delegate: Loader { id: stateViewLoader Layout.fillWidth: true diff --git a/guh-control/ui/devicepages/GenericDeviceStateDetailsPage.qml b/guh-control/ui/devicepages/GenericDeviceStateDetailsPage.qml index e2222bf9..f816f7aa 100644 --- a/guh-control/ui/devicepages/GenericDeviceStateDetailsPage.qml +++ b/guh-control/ui/devicepages/GenericDeviceStateDetailsPage.qml @@ -10,6 +10,7 @@ Page { property var device readonly property var deviceClass: Engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId) + property bool readOnly: true header: GuhHeader { text: "Details for " + root.device.name @@ -43,7 +44,7 @@ Page { Layout.fillWidth: true sourceComponent: { var writable = deviceClass.actionTypes.getActionType(id) !== null; - if (!writable) { + if (root.readOnly || !writable) { return labelComponent; } @@ -58,6 +59,8 @@ Page { return textFieldComponent; case "String": return textFieldComponent; + case "Color": + return colorPreviewComponent; } console.warn("DeviceStateDetailsPage: Type delegate not implemented", stateType.type) return null; @@ -126,6 +129,18 @@ Page { } } + Component { + id: colorPreviewComponent + Rectangle { + property var value: "blue" + property var stateTypeId: null + color: value + implicitHeight: app.mediumFont + implicitWidth: height + radius: height / 4 + } + } + function executeAction(stateTypeId, value) { var paramList = [] var muteParam = {} diff --git a/guh-control/ui/devicepages/SensorDevicePage.qml b/guh-control/ui/devicepages/SensorDevicePage.qml index 7d102f01..05ca412b 100644 --- a/guh-control/ui/devicepages/SensorDevicePage.qml +++ b/guh-control/ui/devicepages/SensorDevicePage.qml @@ -5,21 +5,8 @@ import Guh 1.0 import "../components" import "../customviews" -Page { +DevicePageBase { id: root - property var device: null - readonly property var deviceClass: Engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId) - - - header: GuhHeader { - text: device.name - onBackPressed: pageStack.pop() - - HeaderButton { - imageSource: "../images/info.svg" - onClicked: pageStack.push(Qt.resolvedUrl("GenericDeviceStateDetailsPage.qml"), {device: root.device}) - } - } ListView { anchors { fill: parent } diff --git a/guh-control/ui/magic/NewRulePage.qml b/guh-control/ui/magic/NewRulePage.qml deleted file mode 100644 index 791bd122..00000000 --- a/guh-control/ui/magic/NewRulePage.qml +++ /dev/null @@ -1,132 +0,0 @@ -import QtQuick 2.8 -import QtQuick.Layouts 1.3 -import QtQuick.Controls 2.1 -import "../components" -import Guh 1.0 - -Page { - id: root - - property var rule: null - - StackView { - id: internalPageStack - anchors.fill: parent - initialItem: newRulePage1 - } - - function addEventDescriptor() { - var eventDescriptor = root.rule.eventDescriptors.createNewEventDescriptor(); - var page = internalPageStack.push(Qt.resolvedUrl("SelectThingPage.qml")); - page.onBackPressed.connect(function() { internalPageStack.pop(); }); - page.onThingSelected.connect(function(device) { - eventDescriptor.deviceId = device.id; - selectEventDescriptorData(eventDescriptor) - }) - page.onInterfaceSelected.connect(function(interfaceName) { - eventDescriptor.interfaceName = interfaceName; - selectEventDescriptorData(eventDescriptor) - }) - } - - function selectEventDescriptorData(eventDescriptor) { - var eventPage = internalPageStack.push(Qt.resolvedUrl("SelectEventPage.qml"), {text: "Select event", eventDescriptor: eventDescriptor}); - eventPage.onBackPressed.connect(function() {internalPageStack.pop()}) - eventPage.onDone.connect(function() { - root.rule.eventDescriptors.addEventDescriptor(eventPage.eventDescriptor); - internalPageStack.pop(newRulePage1) - }) - } - - function addAction() { - - } - - Page { - id: newRulePage1 - - header: GuhHeader { - text: "New rule" - onBackPressed: pageStack.pop() - } - - ColumnLayout { - anchors.fill: parent - RowLayout { - Layout.fillWidth: true - RadioButton { - id: whenButton - text: "When" - checked: true - } - RadioButton { - id: whileButton - text: "While" - } - } - - RowLayout { - Layout.fillWidth: true - visible: eventsRepeater.count == 0 - Label { - Layout.fillWidth: true - text: "Add an event which should trigger the execution of the rule" - } - Button { - text: "+" - onClicked: root.addEventDescriptor(); - } - } - - Repeater { - id: eventsRepeater - model: root.rule.eventDescriptors - delegate: ItemDelegate { - id: eventDelegate - property var device: Engine.deviceManager.devices.getDevice(root.rule.eventDescriptors.get(index).deviceId) - property var deviceClass: device ? Engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId) : null - property var eventType: deviceClass ? deviceClass.eventTypes.getEventType(root.rule.eventDescriptors.get(index).eventTypeId) : null - contentItem: ColumnLayout { - Label { - text: eventDelegate.device ? eventDelegate.device.name : "Unknown device" + root.rule.eventDescriptors.get(index).deviceId - Layout.fillWidth: true - } - Label { - text: eventDelegate.eventType ? eventDelegate.eventType.displayName : "Unknown event" + root.rule.eventDescriptors.get(index).eventTypeId - } - } - } - } - - Label { - text: "do the following:" - } - - RowLayout { - Layout.fillWidth: true - visible: actionsRepeater.count == 0 - Label { - Layout.fillWidth: true - text: "Add action which should be executed when the rule is triggered" - } - Button { - text: "+" - onClicked: root.addAction(); - } - } - - Repeater { - id: actionsRepeater - model: root.rule.actions - delegate: ItemDelegate { - id: actionDelegate - contentItem: ColumnLayout { - Label { - text: "bla" - } - } - } - } - } - } -} diff --git a/guh-control/ui/magic/SelectRuleActionParamsPage.qml b/guh-control/ui/magic/SelectRuleActionParamsPage.qml index a176fc70..45cd7e7f 100644 --- a/guh-control/ui/magic/SelectRuleActionParamsPage.qml +++ b/guh-control/ui/magic/SelectRuleActionParamsPage.qml @@ -2,7 +2,7 @@ import QtQuick 2.8 import QtQuick.Controls 2.1 import QtQuick.Layouts 1.2 import "../components" -import "../paramdelegates" +import "../paramdelegates-ng" import Guh 1.0 Page { @@ -27,10 +27,8 @@ Page { id: delegateRepeater model: root.actionType.paramTypes delegate: ParamDelegate { - width: parent.width + Layout.fillWidth: true paramType: root.actionType.paramTypes.get(index) - value: paramType.defaultValue - } } Item { diff --git a/guh-control/ui/paramdelegates-ng/ParamDelegate.qml b/guh-control/ui/paramdelegates-ng/ParamDelegate.qml new file mode 100644 index 00000000..b79435bd --- /dev/null +++ b/guh-control/ui/paramdelegates-ng/ParamDelegate.qml @@ -0,0 +1,193 @@ +import QtQuick 2.8 +import QtQuick.Layouts 1.2 +import QtQuick.Controls 2.1 +import QtQuick.Controls.Material 2.1 +import Guh 1.0 +import "../components" + +ItemDelegate { + id: root + + property var paramType: null + property alias value: d.value + property var param: Param { + id: d + paramTypeId: paramType.id + value: paramType.defaultValue + } + property bool writable: true + + contentItem: ColumnLayout { + RowLayout { + Label { + Layout.fillWidth: true + text: root.paramType.displayName + elide: Text.ElideRight + } + Loader { + id: loader + Layout.fillWidth: sourceComponent == textFieldComponent + sourceComponent: { + if (!root.writable) { + return stringComponent; + } + + switch (root.paramType.type) { + case "Bool": + return boolComponent; + case "Int": + return stringComponent; + case "String": + if (root.paramType.allowedValues.length > 0) { + return comboBoxComponent; + } + return textFieldComponent; + case "Color": + return colorPreviewComponent; + } + console.warn("Param Delegate: Fallback to stringComponent", root.paramType.name, root.paramType.type) + return stringComponent; + } + } + } + Loader { + Layout.fillWidth: true + sourceComponent: { + switch (root.paramType.type) { + case "Int": + case "Double": + if (root.paramType.minValue != undefined && root.paramType.maxValue != undefined) { + return sliderComponent + } + break; + case "Color": + return colorPickerComponent + } + return null; + } + } + } + + Component { + id: stringComponent + Label { + text: { + switch (root.paramType.type) { + case "Int": + return Math.round(root.param.value); + } + return root.param.value; + } + + } + } + Component { + id: boolComponent + Switch { + checked: root.param.value === true + onClicked: { + root.param.value = checked; + } + } + } + Component { + id: sliderComponent + RowLayout { + spacing: app.margins + Label { + text: root.paramType.minValue + } + Slider { + Layout.fillWidth: true + from: root.paramType.minValue + to: root.paramType.maxValue + value: root.param.value + stepSize: { + switch (root.paramType.type) { + case "Int": + return 1; + } + return 0.01; + + } + + onMoved: { + root.param.value = value; + } + } + Label { + text: root.paramType.maxValue + } + } + + } + + Component { + id: textFieldComponent + TextField { + text: root.param.value + onEditingFinished: { + root.param.value = text + } + } + } + + Component { + id: comboBoxComponent + ComboBox { + model: root.paramType.allowedValues + currentIndex: root.paramType.allowedValues.indexOf(root.param.value) + onActivated: { + root.param.value = root.paramType.allowedValues[index] + print("setting value to", root.param.value) + } + } + } + + Component { + id: colorPickerComponent + ColorPicker { + id: colorPicker + implicitHeight: 200 +// color: root.param.value + + Binding { + target: colorPicker + property: "color" + value: root.param.value + when: !colorPicker.pressed + } + + onColorChanged: { + root.param.value = color; + } + + touchDelegate: Rectangle { + height: 15 + width: height + radius: height / 2 + color: Material.accent + + + Rectangle { + color: colorPicker.hovered || colorPicker.pressed ? "#11000000" : "transparent" + anchors.centerIn: parent + height: 30 + width: height + radius: width / 2 + Behavior on color { ColorAnimation { duration: 200 } } + } + } + } + } + + Component { + id: colorPreviewComponent + Rectangle { + implicitHeight: app.mediumFont + implicitWidth: implicitHeight + color: root.param.value + radius: width / 4 + } + } +} diff --git a/guh-control/ui/paramdelegates/BoolParamDelegate.qml b/guh-control/ui/paramdelegates/BoolParamDelegate.qml index e11b0dab..c95993a0 100644 --- a/guh-control/ui/paramdelegates/BoolParamDelegate.qml +++ b/guh-control/ui/paramdelegates/BoolParamDelegate.qml @@ -2,19 +2,20 @@ import QtQuick 2.8 import QtQuick.Layouts 1.2 import QtQuick.Controls 2.1 -RowLayout { +ParamDelegateBase { id: root + contentItem: RowLayout { - property alias text: label.text - property alias value: theSwitch.checked - - Label { - id: label - Layout.fillWidth: true - } - Switch { - id: theSwitch - checked: root.value === true - onClicked: root.value = checked + Label { + id: label + Layout.fillWidth: true + text: root.paramType.displayName + "- " + root.value + } + Switch { + id: theSwitch + checked: root.value == true + onClicked: root.value = checked + } } } + diff --git a/guh-control/ui/paramdelegates/DoubleParamDelegate.qml b/guh-control/ui/paramdelegates/DoubleParamDelegate.qml index 43b745b0..b2928159 100644 --- a/guh-control/ui/paramdelegates/DoubleParamDelegate.qml +++ b/guh-control/ui/paramdelegates/DoubleParamDelegate.qml @@ -10,7 +10,7 @@ ParamDelegateBase { Label { id: label - text: root.paramType.name + text: root.paramType.displayName } TextField { id: textField diff --git a/guh-control/ui/paramdelegates/IntParamDelegate.qml b/guh-control/ui/paramdelegates/IntParamDelegate.qml index cf4cb908..a11165ae 100644 --- a/guh-control/ui/paramdelegates/IntParamDelegate.qml +++ b/guh-control/ui/paramdelegates/IntParamDelegate.qml @@ -10,16 +10,16 @@ ParamDelegateBase { Label { id: label - text: root.paramType.name + text: root.paramType.displayName + Layout.fillWidth: true } TextField { id: textField - Layout.fillWidth: true text: root.value ? root.value : root.paramType.defaultValue + Layout.preferredWidth: implicitWidth onTextChanged: { root.value = text; } - } } } diff --git a/guh-control/ui/paramdescriptordelegates/ParamDescriptorDelegateBase.qml b/guh-control/ui/paramdescriptordelegates/ParamDescriptorDelegateBase.qml index 128f3899..33cd5f49 100644 --- a/guh-control/ui/paramdescriptordelegates/ParamDescriptorDelegateBase.qml +++ b/guh-control/ui/paramdescriptordelegates/ParamDescriptorDelegateBase.qml @@ -5,78 +5,112 @@ import Guh 1.0 ItemDelegate { id: root - height: layout.height property var paramType: null property var value: null property int operatorType: ParamDescriptors.ValueOperatorEquals - RowLayout { - id: layout - anchors { left: parent.left; top: parent.top; right: parent.right} - anchors.margins: app.margins - spacing: app.margins - Label { - text: paramType.displayName - } - ComboBox { - model: { - switch (paramType.type) { - case "Bool": - case "String": - return ["is", "is not"]; - case "Int": - case "Double": - return ["is", "is not", "is greater", "is smaller", "is greater or equal", "is smaller or equal"] + contentItem: ColumnLayout { + RowLayout { + Layout.fillWidth: true + spacing: app.margins + Label { + text: paramType.displayName + } + ComboBox { + Layout.fillWidth: true + model: { + switch (paramType.type) { + case "Bool": + case "String": + return ["is", "is not"]; + case "Int": + case "Double": + return ["is", "is not", "is greater", "is smaller", "is greater or equal", "is smaller or equal"] + } + } + onCurrentTextChanged: { + switch (currentText) { + case "is": + root.operatorType = ParamDescriptor.ValueOperatorEquals; + break; + case "is not": + root.operatorType = ParamDescriptor.ValueOperatorNotEquals; + break; + case "is greater": + root.operatorType = ParamDescriptor.ValueOperatorGreater; + break; + case "is smaller": + root.operatorType = ParamDescriptor.ValueOperatorLess; + break; + case "is greater or equal": + root.operatorType = ParamDescriptor.ValueOperatorGreaterOrEqual; + break; + case "is smaller or equal": + root.operatorType = ParamDescriptor.ValueOperatorLessOrEqual; + break; + } + print("set operator to", root.operatorType, currentText) } } - onCurrentTextChanged: { - switch (currentText) { - case "is": - root.operatorType = ParamDescriptor.ValueOperatorEquals; - break; - case "is not": - root.operatorType = ParamDescriptor.ValueOperatorNotEquals; - break; - case "is greater": - root.operatorType = ParamDescriptor.ValueOperatorGreater; - break; - case "is smaller": - root.operatorType = ParamDescriptor.ValueOperatorLess; - break; - case "is greater or equal": - root.operatorType = ParamDescriptor.ValueOperatorGreaterOrEqual; - break; - case "is smaller or equal": - root.operatorType = ParamDescriptor.ValueOperatorLessOrEqual; - break; + + + Loader { + id: placeHolder + Layout.fillWidth: true + + sourceComponent: { + print("Datatye is:", paramType.type, paramType.minValue, paramType.maxValue) + switch (paramType.type) { + case "Bool": + return boolComponent; + case "Int": + case "Double": + if (paramType.minValue !== undefined && paramType.maxValue !== undefined) { + return labelComponent; + } + return textFieldComponent; + case "String": + if (paramType.allowedValues.length > 0) { + return comboBoxComponent + } + return textFieldComponent; + } + console.warn("ParamDescriptorDelegate: Type delegate not implemented", paramType.type) + return null; } - print("set operator to", root.operatorType, currentText) } } Loader { - id: placeHolder Layout.fillWidth: true sourceComponent: { - print("Datatye is:", paramType.type, paramType.minValue, paramType.maxValue) switch (paramType.type) { - case "Bool": - return boolComponent; case "Int": case "Double": if (paramType.minValue !== undefined && paramType.maxValue !== undefined) { - return sliderComponent; + return sliderComponent } - return textFieldComponent; + } - console.warn("ParamDescriptorDelegate: Type delegate not implemented", paramType.type) - return null; } } } + Component { + id: labelComponent + Label { + text: { + switch (root.paramType.type) { + case "Int": + return Math.round(root.value) + } + return root.value + } + } + } + Component { id: textFieldComponent TextField { @@ -89,13 +123,20 @@ ItemDelegate { Component { id: sliderComponent - Slider { - from: paramType.minValue - to: paramType.maxValue - onMoved: { - root.value = value; + RowLayout { + spacing: app.margins + Label { text: root.paramType.minValue } + Slider { + from: paramType.minValue + to: paramType.maxValue + Layout.fillWidth: true + onMoved: { + root.value = value; + } } + Label { text: root.paramType.maxValue } } + } Component { @@ -110,4 +151,15 @@ ItemDelegate { } } } + + Component { + id: comboBoxComponent + ComboBox { + model: paramType.allowedValues + currentIndex: root.paramType.value + onActivated: { + root.value = paramType.allowedValues[index] + } + } + } } diff --git a/guh-control/ui/system/LogViewerPage.qml b/guh-control/ui/system/LogViewerPage.qml index 8fabd65a..07ee7e9f 100644 --- a/guh-control/ui/system/LogViewerPage.qml +++ b/guh-control/ui/system/LogViewerPage.qml @@ -49,10 +49,10 @@ Page { clip: true headerPositioning: ListView.OverlayHeader - property int column0Width: root.width / 10 * 3 + property int column0Width: root.width / 10 * 2 property int column1Width: root.width / 10 * 1 property int column2Width: root.width / 10 * 3 - property int column3Width: root.width / 10 * 2 + property int column3Width: root.width / 10 * 3 property int column4Width: root.width / 10 * 1 header: Rectangle { @@ -97,7 +97,7 @@ Page { property var deviceClass: device ? Engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId) : null Label { width: listView.column0Width - text: Qt.formatDateTime(model.timestamp,"dd.MM.yy - hh:mm:ss") + text: width > 130 ? Qt.formatDateTime(model.timestamp,"dd.MM.yy - hh:mm:ss") : Qt.formatDateTime(model.timestamp,"hh:mm:ss") elide: Text.ElideRight } Label { diff --git a/guh-control/ui/system/PluginParamsPage.qml b/guh-control/ui/system/PluginParamsPage.qml new file mode 100644 index 00000000..bb6b3aa5 --- /dev/null +++ b/guh-control/ui/system/PluginParamsPage.qml @@ -0,0 +1,63 @@ +import QtQuick 2.8 +import QtQuick.Controls 2.1 +import QtQuick.Controls.Material 2.1 +import QtQuick.Layouts 1.3 +import "../components" +import "../paramdelegates-ng" +import Guh 1.0 + +Page { + id: root + property var plugin: null + + header: GuhHeader { + text: qsTr("%1 settings").arg(plugin.name) + backButtonVisible: true + onBackPressed: pageStack.pop() + + HeaderButton { + imageSource: "../images/tick.svg" + onClicked: { + Engine.deviceManager.savePluginConfig(root.plugin.pluginId) + } + } + } + + Connections { + target: Engine.deviceManager + onSavePluginConfigReply: { + if (params.params.deviceError == "DeviceErrorNoError") { + pageStack.pop(); + } else { + console.warn("Error saving plugin params:", JSON.stringify(params)) + var dialog = errorDialog.createObject(root, {title: "Error", text: "Error saving params: " + JSON.stringify(params.params.deviceError)}); + dialog.open(); + } + } + } + + Flickable { + anchors.fill: parent + contentHeight: column.implicitHeight + + ColumnLayout { + id: column + width: parent.width + + Repeater { + model: plugin.paramTypes + + delegate: ParamDelegate { + Layout.fillWidth: true + paramType: root.plugin.paramTypes.get(index) + param: root.plugin.params.getParam(model.id) + } + } + } + } + + Component { + id: errorDialog + ErrorDialog { } + } +} diff --git a/guh-control/ui/system/PluginsPage.qml b/guh-control/ui/system/PluginsPage.qml new file mode 100644 index 00000000..f96d0ea9 --- /dev/null +++ b/guh-control/ui/system/PluginsPage.qml @@ -0,0 +1,38 @@ +import QtQuick 2.8 +import QtQuick.Controls 2.1 +import QtQuick.Controls.Material 2.1 +import QtQuick.Layouts 1.3 +import "../components" +import Guh 1.0 + +Page { + id: root + header: GuhHeader { + text: "Plugins" + backButtonVisible: true + onBackPressed: pageStack.pop() + } + + ListView { + anchors.fill: parent + model: Engine.deviceManager.plugins + clip: true + + delegate: ItemDelegate { + width: parent.width + contentItem: RowLayout { + Label { + Layout.fillWidth: true + text: model.name + } + Image { + source: "../images/next.svg" + Layout.preferredHeight: parent.height + Layout.preferredWidth: height + } + } + onClicked: pageStack.push(Qt.resolvedUrl("PluginParamsPage.qml"), {plugin: Engine.deviceManager.plugins.get(index)}) + } + } + +} diff --git a/libguh-common/types/param.cpp b/libguh-common/types/param.cpp index 43cc8afb..12d97cd8 100644 --- a/libguh-common/types/param.cpp +++ b/libguh-common/types/param.cpp @@ -22,22 +22,24 @@ #include "param.h" -Param::Param(const QString &id, const QVariant &value, QObject *parent) : +Param::Param(const QString ¶mTypeId, const QVariant &value, QObject *parent) : QObject(parent), - m_id(id), + m_paramTypeId(paramTypeId), m_value(value) { } -QString Param::id() const +QString Param::paramTypeId() const { - return m_id; + return m_paramTypeId; } -void Param::setId(const QString &id) +void Param::setParamTypeId(const QString ¶mTypeId) { - m_id = id; - emit idChanged(); + if (m_paramTypeId != paramTypeId) { + m_paramTypeId = paramTypeId; + emit paramTypeIdChanged(); + } } QVariant Param::value() const diff --git a/libguh-common/types/param.h b/libguh-common/types/param.h index 95604f47..8f6986d0 100644 --- a/libguh-common/types/param.h +++ b/libguh-common/types/param.h @@ -30,24 +30,24 @@ class Param : public QObject { Q_OBJECT - Q_PROPERTY(QString id READ id WRITE setId NOTIFY idChanged) + Q_PROPERTY(QString paramTypeId READ paramTypeId WRITE setParamTypeId NOTIFY paramTypeIdChanged) Q_PROPERTY(QVariant value READ value WRITE setValue NOTIFY valueChanged) public: - Param(const QString &id = QString(), const QVariant &value = QVariant(), QObject *parent = 0); + Param(const QString ¶mTypeId = QString(), const QVariant &value = QVariant(), QObject *parent = 0); - QString id() const; - void setId(const QString &id); + QString paramTypeId() const; + void setParamTypeId(const QString ¶mTypeId); QVariant value() const; void setValue(const QVariant &value); private: - QString m_id; + QString m_paramTypeId; QVariant m_value; signals: - void idChanged(); + void paramTypeIdChanged(); void valueChanged(); }; diff --git a/libguh-common/types/paramdescriptor.cpp b/libguh-common/types/paramdescriptor.cpp index 31c846c2..32f925cf 100644 --- a/libguh-common/types/paramdescriptor.cpp +++ b/libguh-common/types/paramdescriptor.cpp @@ -20,7 +20,7 @@ void ParamDescriptor::setOperatorType(ParamDescriptor::ValueOperator operatorTyp ParamDescriptor *ParamDescriptor::clone() const { - ParamDescriptor *ret = new ParamDescriptor(this->id(), this->value()); + ParamDescriptor *ret = new ParamDescriptor(this->paramTypeId(), this->value()); ret->setOperatorType(this->operatorType()); return ret; } diff --git a/libguh-common/types/paramdescriptors.cpp b/libguh-common/types/paramdescriptors.cpp index 9475e269..b88e2b96 100644 --- a/libguh-common/types/paramdescriptors.cpp +++ b/libguh-common/types/paramdescriptors.cpp @@ -16,7 +16,7 @@ QVariant ParamDescriptors::data(const QModelIndex &index, int role) const { switch (role) { case RoleId: - return m_list.at(index.row())->id(); + return m_list.at(index.row())->paramTypeId(); case RoleValue: return m_list.at(index.row())->value(); case RoleOperator: @@ -56,7 +56,7 @@ void ParamDescriptors::addParamDescriptor(ParamDescriptor *paramDescriptor) void ParamDescriptors::setParamDescriptor(const QString ¶mTypeId, const QVariant &value, ValueOperator operatorType) { foreach (ParamDescriptor* paramDescriptor, m_list) { - if (paramDescriptor->id() == paramTypeId) { + if (paramDescriptor->paramTypeId() == paramTypeId) { paramDescriptor->setValue(value); paramDescriptor->setOperatorType((ParamDescriptor::ValueOperator)operatorType); return; @@ -64,7 +64,7 @@ void ParamDescriptors::setParamDescriptor(const QString ¶mTypeId, const QVar } // Still here? need to add a new one ParamDescriptor* paramDescriptor = createNewParamDescriptor(); - paramDescriptor->setId(paramTypeId); + paramDescriptor->setParamTypeId(paramTypeId); paramDescriptor->setValue(value); paramDescriptor->setOperatorType((ParamDescriptor::ValueOperator)operatorType); addParamDescriptor(paramDescriptor); diff --git a/libguh-common/types/params.cpp b/libguh-common/types/params.cpp index da2525af..da03d10c 100644 --- a/libguh-common/types/params.cpp +++ b/libguh-common/types/params.cpp @@ -47,7 +47,7 @@ Param *Params::get(int index) const Param *Params::getParam(QString paramTypeId) const { foreach (Param *param, m_params) { - if (param->id() == paramTypeId) { + if (param->paramTypeId() == paramTypeId) { return param; } } @@ -72,7 +72,7 @@ QVariant Params::data(const QModelIndex &index, int role) const Param *param = m_params.at(index.row()); if (role == RoleId) { - return param->id(); + return param->paramTypeId(); } else if (role == RoleValue) { return param->value(); } diff --git a/libguh-common/types/paramtypes.cpp b/libguh-common/types/paramtypes.cpp index 14feaa00..e5dcd348 100644 --- a/libguh-common/types/paramtypes.cpp +++ b/libguh-common/types/paramtypes.cpp @@ -71,6 +71,10 @@ QVariant ParamTypes::data(const QModelIndex &index, int role) const ParamType *paramType = m_paramTypes.at(index.row()); if (role == NameRole) { return paramType->name(); + } else if (role == DisplayNameRole) { + return paramType->displayName(); + } else if (role == IdRole) { + return paramType->id(); } else if (role == TypeRole) { return paramType->type(); } else if (role == DefaultValueRole) { @@ -111,7 +115,9 @@ void ParamTypes::clearModel() QHash ParamTypes::roleNames() const { QHash roles; + roles[IdRole] = "id"; roles[NameRole] = "name"; + roles[DisplayNameRole] = "displayName"; roles[TypeRole] = "type"; roles[MinValueRole] = "minValue"; roles[MaxValueRole] = "maxValue"; diff --git a/libguh-common/types/paramtypes.h b/libguh-common/types/paramtypes.h index 7328720c..6f3f226b 100644 --- a/libguh-common/types/paramtypes.h +++ b/libguh-common/types/paramtypes.h @@ -34,6 +34,8 @@ class ParamTypes : public QAbstractListModel public: enum ParamTypeRole { NameRole = Qt::DisplayRole, + DisplayNameRole, + IdRole, TypeRole, DefaultValueRole, MinValueRole, diff --git a/libguh-common/types/plugin.cpp b/libguh-common/types/plugin.cpp index 678a39c3..6d5d7333 100644 --- a/libguh-common/types/plugin.cpp +++ b/libguh-common/types/plugin.cpp @@ -24,7 +24,7 @@ Plugin::Plugin(QObject *parent) : QObject(parent) { - + m_params = new Params(this); } QString Plugin::name() const diff --git a/libguh-common/types/plugin.h b/libguh-common/types/plugin.h index 8e4e6e4f..716dd9d2 100644 --- a/libguh-common/types/plugin.h +++ b/libguh-common/types/plugin.h @@ -55,8 +55,8 @@ public: private: QString m_name; QUuid m_pluginId; - ParamTypes *m_paramTypes; - Params *m_params; + ParamTypes *m_paramTypes = nullptr; + Params *m_params = nullptr; }; #endif // PLUGIN_H