From 6de33ca71819c266fbc2f26757197e44a36e5ef7 Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Thu, 26 Oct 2017 01:08:59 +0200 Subject: [PATCH] add support for creating basic rules --- guh-control/devicemanager.cpp | 2 +- guh-control/engine.cpp | 24 ++- guh-control/engine.h | 8 +- guh-control/interfacesmodel.cpp | 1 + guh-control/jsonrpc/jsonrpcclient.cpp | 4 +- guh-control/jsonrpc/jsonrpcclient.h | 4 +- guh-control/main.cpp | 16 ++ guh-control/models/rulesfiltermodel.cpp | 66 +++++++ guh-control/models/rulesfiltermodel.h | 39 ++++ guh-control/resources.qrc | 6 + guh-control/rulemanager.cpp | 142 ++++++++++++++ guh-control/rulemanager.h | 45 +++++ guh-control/ui/DevicesPage.qml | 2 +- guh-control/ui/MagicPage.qml | 10 +- .../devicelistpages/GenericDeviceListPage.qml | 8 +- .../ui/devicepages/ButtonDevicePage.qml | 108 +++++++++++ .../ui/devicepages/GenericDevicePage.qml | 36 +--- .../GenericDeviceStateDetailsPage.qml | 41 ++++ .../ui/devicepages/MediaDevicePage.qml | 2 +- guh-control/ui/images/delete.svg | 166 ++++++++++++++++ .../ui/images/mediaplayer-app-symbolic.svg | 20 ++ guh-control/ui/images/system-shutdown.svg | 18 ++ guh-control/ui/magic/SelectActionPage.qml | 180 ++++++++++++++++++ guh-control/ui/main.qml | 6 +- libguh-common/libguh-common.pro | 16 ++ libguh-common/types/eventdescriptor.cpp | 26 +++ libguh-common/types/eventdescriptor.h | 29 +++ libguh-common/types/eventdescriptors.cpp | 40 ++++ libguh-common/types/eventdescriptors.h | 33 ++++ libguh-common/types/eventtypes.cpp | 11 ++ libguh-common/types/eventtypes.h | 2 + libguh-common/types/rule.cpp | 54 ++++++ libguh-common/types/rule.h | 44 +++++ libguh-common/types/ruleaction.cpp | 39 ++++ libguh-common/types/ruleaction.h | 37 ++++ libguh-common/types/ruleactionparam.cpp | 32 ++++ libguh-common/types/ruleactionparam.h | 31 +++ libguh-common/types/ruleactionparams.cpp | 31 +++ libguh-common/types/ruleactionparams.h | 29 +++ libguh-common/types/ruleactions.cpp | 30 +++ libguh-common/types/ruleactions.h | 29 +++ libguh-common/types/rules.cpp | 72 +++++++ libguh-common/types/rules.h | 33 ++++ 43 files changed, 1518 insertions(+), 54 deletions(-) create mode 100644 guh-control/models/rulesfiltermodel.cpp create mode 100644 guh-control/models/rulesfiltermodel.h create mode 100644 guh-control/rulemanager.cpp create mode 100644 guh-control/rulemanager.h create mode 100644 guh-control/ui/devicepages/ButtonDevicePage.qml create mode 100644 guh-control/ui/devicepages/GenericDeviceStateDetailsPage.qml create mode 100644 guh-control/ui/images/delete.svg create mode 100644 guh-control/ui/images/mediaplayer-app-symbolic.svg create mode 100644 guh-control/ui/images/system-shutdown.svg create mode 100644 guh-control/ui/magic/SelectActionPage.qml create mode 100644 libguh-common/types/eventdescriptor.cpp create mode 100644 libguh-common/types/eventdescriptor.h create mode 100644 libguh-common/types/eventdescriptors.cpp create mode 100644 libguh-common/types/eventdescriptors.h create mode 100644 libguh-common/types/rule.cpp create mode 100644 libguh-common/types/rule.h create mode 100644 libguh-common/types/ruleaction.cpp create mode 100644 libguh-common/types/ruleaction.h create mode 100644 libguh-common/types/ruleactionparam.cpp create mode 100644 libguh-common/types/ruleactionparam.h create mode 100644 libguh-common/types/ruleactionparams.cpp create mode 100644 libguh-common/types/ruleactionparams.h create mode 100644 libguh-common/types/ruleactions.cpp create mode 100644 libguh-common/types/ruleactions.h create mode 100644 libguh-common/types/rules.cpp create mode 100644 libguh-common/types/rules.h diff --git a/guh-control/devicemanager.cpp b/guh-control/devicemanager.cpp index 745fcce3..ab467f3d 100644 --- a/guh-control/devicemanager.cpp +++ b/guh-control/devicemanager.cpp @@ -117,7 +117,7 @@ void DeviceManager::getSupportedDevicesResponse(const QVariantMap ¶ms) QVariantList deviceClassList = params.value("params").toMap().value("deviceClasses").toList(); foreach (QVariant deviceClassVariant, deviceClassList) { DeviceClass *deviceClass = JsonTypes::unpackDeviceClass(deviceClassVariant.toMap(), Engine::instance()->deviceManager()->deviceClasses()); - qDebug() << "Server has device class:" << deviceClass->name() << deviceClass->id(); +// qDebug() << "Server has device class:" << deviceClass->name() << deviceClass->id(); m_deviceClasses->addDeviceClass(deviceClass); } } diff --git a/guh-control/engine.cpp b/guh-control/engine.cpp index dafaa900..1585bf34 100644 --- a/guh-control/engine.cpp +++ b/guh-control/engine.cpp @@ -21,6 +21,7 @@ #include "engine.h" #include "tcpsocketinterface.h" +#include "rulemanager.h" Engine* Engine::s_instance = 0; @@ -45,6 +46,11 @@ DeviceManager *Engine::deviceManager() const return m_deviceManager; } +RuleManager *Engine::ruleManager() const +{ + return m_ruleManager; +} + JsonRpcClient *Engine::jsonRpcClient() const { return m_jsonRpcClient; @@ -59,18 +65,22 @@ Engine::Engine(QObject *parent) : QObject(parent), m_connection(new GuhConnection(this)), m_jsonRpcClient(new JsonRpcClient(m_connection, this)), - m_deviceManager(new DeviceManager(m_jsonRpcClient, this)) + m_deviceManager(new DeviceManager(m_jsonRpcClient, this)), + m_ruleManager(new RuleManager(m_jsonRpcClient, this)) { connect(m_jsonRpcClient, &JsonRpcClient::connectedChanged, this, &Engine::onConnectedChanged); + connect(m_jsonRpcClient, &JsonRpcClient::authenticationRequiredChanged, this, &Engine::onConnectedChanged); } -void Engine::onConnectedChanged(bool connected) +void Engine::onConnectedChanged() { - qDebug() << "Engine: connected changed:" << connected; - deviceManager()->clear(); - if (connected) { - if (!jsonRpcClient()->initialSetupRequired() && !jsonRpcClient()->authenticationRequired()) { - deviceManager()->init(); + qDebug() << "Engine: connected changed:" << m_jsonRpcClient->connected(); + m_deviceManager->clear(); + m_ruleManager->clear(); + if (m_jsonRpcClient->connected()) { + if (!m_jsonRpcClient->initialSetupRequired() && !m_jsonRpcClient->authenticationRequired()) { + m_deviceManager->init(); + m_ruleManager->init(); } } } diff --git a/guh-control/engine.h b/guh-control/engine.h index fb525708..5068a728 100644 --- a/guh-control/engine.h +++ b/guh-control/engine.h @@ -29,11 +29,15 @@ #include "guhinterface.h" #include "jsonrpc/jsonrpcclient.h" + +class RuleManager; + 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) public: @@ -45,6 +49,7 @@ public: GuhConnection *connection() const; DeviceManager *deviceManager() const; + RuleManager *ruleManager() const; JsonRpcClient *jsonRpcClient() const; private: @@ -54,9 +59,10 @@ private: GuhConnection *m_connection; JsonRpcClient *m_jsonRpcClient; DeviceManager *m_deviceManager; + RuleManager *m_ruleManager; private slots: - void onConnectedChanged(bool connected); + void onConnectedChanged(); }; diff --git a/guh-control/interfacesmodel.cpp b/guh-control/interfacesmodel.cpp index 3a27102a..93211f43 100644 --- a/guh-control/interfacesmodel.cpp +++ b/guh-control/interfacesmodel.cpp @@ -70,6 +70,7 @@ void InterfacesModel::syncInterfaces() QStringList interfacesInSource; for (int i = 0; i < m_devices->count(); i++) { DeviceClass *dc = Engine::instance()->deviceManager()->deviceClasses()->getDeviceClass(m_devices->get(i)->deviceClassId()); +// qDebug() << "device" <name() << "has interfaces" << dc->interfaces(); foreach (const QString &interface, dc->interfaces()) { if (!m_shownInterfaces.contains(interface)) { diff --git a/guh-control/jsonrpc/jsonrpcclient.cpp b/guh-control/jsonrpc/jsonrpcclient.cpp index 709cd65a..f35803bf 100644 --- a/guh-control/jsonrpc/jsonrpcclient.cpp +++ b/guh-control/jsonrpc/jsonrpcclient.cpp @@ -52,7 +52,7 @@ void JsonRpcClient::registerNotificationHandler(JsonHandler *handler, const QStr m_notificationHandlers.insert(handler->nameSpace(), qMakePair(handler, method)); } -JsonRpcReply *JsonRpcClient::sendCommand(const QString &method, const QVariantMap ¶ms, QObject *caller, const QString &callbackMethod) +void JsonRpcClient::sendCommand(const QString &method, const QVariantMap ¶ms, QObject *caller, const QString &callbackMethod) { JsonRpcReply *reply = createReply(method, params, caller, callbackMethod); m_replies.insert(reply->commandId(), reply); @@ -60,7 +60,7 @@ JsonRpcReply *JsonRpcClient::sendCommand(const QString &method, const QVariantMa } -JsonRpcReply *JsonRpcClient::sendCommand(const QString &method, QObject *caller, const QString &callbackMethod) +void JsonRpcClient::sendCommand(const QString &method, QObject *caller, const QString &callbackMethod) { return sendCommand(method, QVariantMap(), caller, callbackMethod); } diff --git a/guh-control/jsonrpc/jsonrpcclient.h b/guh-control/jsonrpc/jsonrpcclient.h index 1f03a8b2..172348e4 100644 --- a/guh-control/jsonrpc/jsonrpcclient.h +++ b/guh-control/jsonrpc/jsonrpcclient.h @@ -45,8 +45,8 @@ public: void registerNotificationHandler(JsonHandler *handler, const QString &method); - JsonRpcReply* sendCommand(const QString &method, const QVariantMap ¶ms, QObject *caller = nullptr, const QString &callbackMethod = QString()); - JsonRpcReply* sendCommand(const QString &method, QObject *caller = nullptr, const QString &callbackMethod = QString()); + void sendCommand(const QString &method, const QVariantMap ¶ms, QObject *caller = nullptr, const QString &callbackMethod = QString()); + void sendCommand(const QString &method, QObject *caller = nullptr, const QString &callbackMethod = QString()); void setConnection(GuhConnection *connection); bool connected() const; diff --git a/guh-control/main.cpp b/guh-control/main.cpp index 3f797d0a..702bc783 100644 --- a/guh-control/main.cpp +++ b/guh-control/main.cpp @@ -33,6 +33,13 @@ #include "discovery/upnpdiscovery.h" #include "discovery/zeroconfdiscovery.h" #include "interfacesmodel.h" +#include "rulemanager.h" +#include "models/rulesfiltermodel.h" +#include "types/ruleactions.h" +#include "types/ruleaction.h" +#include "types/ruleactionparams.h" +#include "types/ruleactionparam.h" +#include "types/rule.h" int main(int argc, char *argv[]) { @@ -81,6 +88,15 @@ int main(int argc, char *argv[]) qmlRegisterType(uri, 1, 0, "DeviceClassesProxy"); qmlRegisterType(uri, 1, 0, "DeviceDiscovery"); + qmlRegisterUncreatableType(uri, 1, 0, "RuleManager", "Get it from the Engine"); + qmlRegisterUncreatableType(uri, 1, 0, "Rules", "Get it from RuleManager"); + qmlRegisterUncreatableType(uri, 1, 0, "Rule", "Get it from Rules"); + qmlRegisterUncreatableType(uri, 1, 0, "RuleActions", "Get them from the rule"); + qmlRegisterUncreatableType(uri, 1, 0, "RuleAction", "Get it from RuleActions"); + qmlRegisterUncreatableType(uri, 1, 0, "RuleActionParams", "Get it from RuleActions"); + qmlRegisterUncreatableType(uri, 1, 0, "RuleActionParam", "Get it from RuleActionParams"); + qmlRegisterType(uri, 1, 0, "RulesFilterModel"); + qmlRegisterUncreatableType(uri, 1, 0, "Plugin", "Can't create this in QML. Get it from the Plugins."); qmlRegisterUncreatableType(uri, 1, 0, "Plugins", "Can't create this in QML. Get it from the DeviceManager."); qmlRegisterType(uri, 1, 0, "PluginsProxy"); diff --git a/guh-control/models/rulesfiltermodel.cpp b/guh-control/models/rulesfiltermodel.cpp new file mode 100644 index 00000000..2c5d16db --- /dev/null +++ b/guh-control/models/rulesfiltermodel.cpp @@ -0,0 +1,66 @@ +#include "rulesfiltermodel.h" +#include "types/rules.h" +#include "types/rule.h" +#include "types/eventdescriptors.h" +#include "types/eventdescriptor.h" + +#include + +RulesFilterModel::RulesFilterModel(QObject *parent) : QSortFilterProxyModel(parent) +{ + +} + +Rules *RulesFilterModel::rules() const +{ + return m_rules; +} + +void RulesFilterModel::setRules(Rules *rules) +{ + if (m_rules != rules) { + m_rules = rules; + setSourceModel(rules); + emit rulesChanged(); + invalidateFilter(); + } +} + +QUuid RulesFilterModel::filterEventDeviceId() const +{ + return m_filterEventDeviceId; +} + +void RulesFilterModel::setFilterEventDeviceId(const QUuid &filterEventDeviceId) +{ + if (m_filterEventDeviceId != filterEventDeviceId) { + m_filterEventDeviceId = filterEventDeviceId; + emit filterEventDeviceIdChanged(); + invalidateFilter(); + } +} + +Rule *RulesFilterModel::get(int index) const +{ + return m_rules->get(mapToSource(this->index(index, 0)).row()); +} + +bool RulesFilterModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const +{ + Q_UNUSED(source_parent) + if (!m_filterEventDeviceId.isNull()) { + Rule* rule = m_rules->get(source_row); + bool found = false; + for (int i = 0; i < rule->eventDescriptors()->rowCount(); i++) { + EventDescriptor *ed = rule->eventDescriptors()->get(i); + if (ed->deviceId() == m_filterEventDeviceId) { + found = true; + break; + } + } + if (!found) { + return false; + } + } + return true; +} diff --git a/guh-control/models/rulesfiltermodel.h b/guh-control/models/rulesfiltermodel.h new file mode 100644 index 00000000..e9cdce52 --- /dev/null +++ b/guh-control/models/rulesfiltermodel.h @@ -0,0 +1,39 @@ +#ifndef RULESFILTERMODEL_H +#define RULESFILTERMODEL_H + +#include +#include + +class Rules; +class Rule; + +class RulesFilterModel : public QSortFilterProxyModel +{ + Q_OBJECT + Q_PROPERTY(Rules* rules READ rules WRITE setRules NOTIFY rulesChanged) + Q_PROPERTY(QUuid filterEventDeviceId READ filterEventDeviceId WRITE setFilterEventDeviceId NOTIFY filterEventDeviceIdChanged) + +public: + explicit RulesFilterModel(QObject *parent = nullptr); + + Rules* rules() const; + void setRules(Rules* rules); + + QUuid filterEventDeviceId() const; + void setFilterEventDeviceId(const QUuid &filterEventDeviceId); + + Q_INVOKABLE Rule* get(int index) const; + +signals: + void rulesChanged(); + void filterEventDeviceIdChanged(); + +protected: + bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override; + +private: + Rules *m_rules = nullptr; + QUuid m_filterEventDeviceId; +}; + +#endif // RULESFILTERMODEL_H diff --git a/guh-control/resources.qrc b/guh-control/resources.qrc index 6271db2b..a6ba8baa 100644 --- a/guh-control/resources.qrc +++ b/guh-control/resources.qrc @@ -52,5 +52,11 @@ 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 + ui/magic/SelectActionPage.qml + ui/devicepages/GenericDeviceStateDetailsPage.qml + ui/images/delete.svg diff --git a/guh-control/rulemanager.cpp b/guh-control/rulemanager.cpp new file mode 100644 index 00000000..7400ece6 --- /dev/null +++ b/guh-control/rulemanager.cpp @@ -0,0 +1,142 @@ +#include "rulemanager.h" + +#include "jsonrpc/jsonrpcclient.h" +#include "types/rule.h" +#include "types/eventdescriptor.h" +#include "types/eventdescriptors.h" +#include "types/ruleactions.h" +#include "types/ruleaction.h" +#include "types/ruleactionparams.h" +#include "types/ruleactionparam.h" + +RuleManager::RuleManager(JsonRpcClient* jsonClient, QObject *parent) : + JsonHandler(parent), + m_jsonClient(jsonClient), + m_rules(new Rules(this)) +{ + m_jsonClient->registerNotificationHandler(this, "handleRulesNotification"); +} + +QString RuleManager::nameSpace() const +{ + return "Rules"; +} + +void RuleManager::clear() +{ + m_rules->clear(); +} + +void RuleManager::init() +{ + m_jsonClient->sendCommand("Rules.GetRules", this, "getRulesReply"); +} + +Rules *RuleManager::rules() const +{ + return m_rules; +} + +void RuleManager::addRule(const QVariantMap params) +{ + m_jsonClient->sendCommand("Rules.AddRule", params, this, "addRuleReply"); +} + +void RuleManager::removeRule(const QUuid &ruleId) +{ + QVariantMap params; + params.insert("ruleId", ruleId); + m_jsonClient->sendCommand("Rules.RemoveRule", params, this, "removeRuleReply"); +} + +void RuleManager::handleRulesNotification(const QVariantMap ¶ms) +{ + 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(); + QString name = ruleMap.value("name").toString(); + bool enabled = ruleMap.value("enabled").toBool(); + Rule* rule = new Rule(ruleId, m_rules); + rule->setName(name); + rule->setEnabled(enabled); + parseEventDescriptors(ruleMap.value("eventDescriptors").toList(), rule); + parseRuleActions(ruleMap.value("actions").toList(), rule); + m_rules->insert(rule); + } else if (params.value("notification").toString() == "Rules.RuleRemoved") { + QUuid ruleId = params.value("params").toMap().value("ruleId").toUuid(); + m_rules->remove(ruleId); + } +} + +void RuleManager::getRulesReply(const QVariantMap ¶ms) +{ + if (params.value("status").toString() != "success") { + qWarning() << "Error getting rules:" << params.value("error").toString(); + return; + } + foreach (const QVariant &ruleDescriptionVariant, params.value("params").toMap().value("ruleDescriptions").toList()) { + QUuid ruleId = ruleDescriptionVariant.toMap().value("id").toUuid(); + QString name = ruleDescriptionVariant.toMap().value("name").toString(); + bool enabled = ruleDescriptionVariant.toMap().value("enabled").toBool(); + + Rule *rule = new Rule(ruleId, m_rules); + rule->setName(name); + rule->setEnabled(enabled); + m_rules->insert(rule); + + QVariantMap requestParams; + requestParams.insert("ruleId", rule->id()); + m_jsonClient->sendCommand("Rules.GetRuleDetails", requestParams, this, "getRuleDetailsReply"); + } +} + +void RuleManager::getRuleDetailsReply(const QVariantMap ¶ms) +{ + QVariantMap ruleMap = params.value("params").toMap().value("rule").toMap(); + Rule* rule = m_rules->getRule(ruleMap.value("id").toUuid()); + if (!rule) { + qDebug() << "Got rule details for a rule we don't know"; + return; + } + qDebug() << "got rule details for rule" << ruleMap; + parseEventDescriptors(ruleMap.value("eventDescriptors").toList(), rule); + parseRuleActions(ruleMap.value("actions").toList(), rule); +} + +void RuleManager::addRuleReply(const QVariantMap ¶ms) +{ + qDebug() << "Add rule reply" << params; +} + +void RuleManager::removeRuleReply(const QVariantMap ¶ms) +{ + qDebug() << "Have remove rule reply" << params; +} + +void RuleManager::parseEventDescriptors(const QVariantList &eventDescriptorList, Rule *rule) +{ + foreach (const QVariant &eventDescriptorVariant, eventDescriptorList) { + EventDescriptor *eventDescriptor = new EventDescriptor(rule); + eventDescriptor->setDeviceId(eventDescriptorVariant.toMap().value("deviceId").toUuid()); + eventDescriptor->setEventTypeId(eventDescriptorVariant.toMap().value("eventTypeId").toUuid()); +// eventDescriptor->setParamDescriptors(eventDescriptorVariant.toMap().value("deviceId").toUuid()); + rule->eventDescriptors()->addEventDescriptor(eventDescriptor); + } +} + +void RuleManager::parseRuleActions(const QVariantList &ruleActions, Rule *rule) +{ + foreach (const QVariant &ruleActionVariant, ruleActions) { + RuleAction *ruleAction = new RuleAction(); + ruleAction->setDeviceId(ruleActionVariant.toMap().value("deviceId").toUuid()); + ruleAction->setActionTypeId(ruleActionVariant.toMap().value("actionTypeId").toUuid()); + foreach (const QVariant &ruleActionParamVariant, ruleActionVariant.toMap().value("ruleActionParams").toList()) { + RuleActionParam *param = new RuleActionParam(); + param->setParamTypeId(ruleActionParamVariant.toMap().value("paramTypeId").toUuid()); + param->setValue(ruleActionParamVariant.toMap().value("value")); + ruleAction->ruleActionParams()->addRuleActionParam(param); + } + rule->ruleActions()->addRuleAction(ruleAction); + } +} diff --git a/guh-control/rulemanager.h b/guh-control/rulemanager.h new file mode 100644 index 00000000..cbf4a9ea --- /dev/null +++ b/guh-control/rulemanager.h @@ -0,0 +1,45 @@ +#ifndef RULEMANAGER_H +#define RULEMANAGER_H + +#include + +#include "types/rules.h" +#include "jsonrpc/jsonhandler.h" + +class JsonRpcClient; + +class RuleManager : public JsonHandler +{ + Q_OBJECT + Q_PROPERTY(Rules* rules READ rules CONSTANT) + +public: + explicit RuleManager(JsonRpcClient *jsonClient, QObject *parent = nullptr); + + QString nameSpace() const override; + + void clear(); + void init(); + + Rules* rules() const; + + Q_INVOKABLE void addRule(const QVariantMap params); + Q_INVOKABLE void removeRule(const QUuid &ruleId); + +private slots: + void handleRulesNotification(const QVariantMap ¶ms); + void getRulesReply(const QVariantMap ¶ms); + void getRuleDetailsReply(const QVariantMap ¶ms); + void addRuleReply(const QVariantMap ¶ms); + void removeRuleReply(const QVariantMap ¶ms); + +private: + void parseEventDescriptors(const QVariantList &eventDescriptorList, Rule *rule); + void parseRuleActions(const QVariantList &ruleActions, Rule *rule); + +private: + JsonRpcClient *m_jsonClient; + Rules* m_rules; +}; + +#endif // RULEMANAGER_H diff --git a/guh-control/ui/DevicesPage.qml b/guh-control/ui/DevicesPage.qml index 16a8fdd7..fbc5d12c 100644 --- a/guh-control/ui/DevicesPage.qml +++ b/guh-control/ui/DevicesPage.qml @@ -31,7 +31,7 @@ Page { model: InterfacesModel { id: interfacesModel devices: Engine.deviceManager.devices - shownInterfaces: ["light", "weather", "sensor", "media"] + shownInterfaces: ["light", "weather", "sensor", "media", "button"] } cellWidth: { diff --git a/guh-control/ui/MagicPage.qml b/guh-control/ui/MagicPage.qml index 4f61a566..a73ce661 100644 --- a/guh-control/ui/MagicPage.qml +++ b/guh-control/ui/MagicPage.qml @@ -1,6 +1,7 @@ import QtQuick 2.8 import QtQuick.Controls 2.2 import "components" +import Guh 1.0 Page { id: root @@ -16,6 +17,13 @@ Page { ListView { anchors.fill: parent -// model: Engine. + + model: Engine.ruleManager.rules + delegate: ItemDelegate { + width: parent.width + Label { + text: model.name + } + } } } diff --git a/guh-control/ui/devicelistpages/GenericDeviceListPage.qml b/guh-control/ui/devicelistpages/GenericDeviceListPage.qml index 9e1518c4..bfdf7857 100644 --- a/guh-control/ui/devicelistpages/GenericDeviceListPage.qml +++ b/guh-control/ui/devicelistpages/GenericDeviceListPage.qml @@ -40,11 +40,15 @@ Page { var device = devicesProxy.get(index); var deviceClass = Engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId); print("clicked", deviceClass.interfaces) + var page; if (deviceClass.interfaces.indexOf("media") >= 0) { - pageStack.push(Qt.resolvedUrl("../devicepages/MediaDevicePage.qml"), {device: devicesProxy.get(index)}) + page = "MediaDevicePage.qml"; + } else if (deviceClass.interfaces.indexOf("button") >= 0) { + page = "ButtonDevicePage.qml"; } else { - pageStack.push(Qt.resolvedUrl("../devicepages/GenericDevicePage.qml"), {device: devicesProxy.get(index)}) + page = "GenericDevicePage.qml"; } + pageStack.push(Qt.resolvedUrl("../devicepages/" + page), {device: devicesProxy.get(index)}) } } } diff --git a/guh-control/ui/devicepages/ButtonDevicePage.qml b/guh-control/ui/devicepages/ButtonDevicePage.qml new file mode 100644 index 00000000..ef9b8120 --- /dev/null +++ b/guh-control/ui/devicepages/ButtonDevicePage.qml @@ -0,0 +1,108 @@ +import QtQuick 2.5 +import QtQuick.Controls 2.1 +import QtQuick.Layouts 1.1 +import Guh 1.0 +import "../components" + +Page { + 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}) + } + } + + ColumnLayout { + anchors { fill: parent } + spacing: app.margins + Label { + Layout.fillWidth: true + Layout.margins: app.margins + text: "When this switch is pressed..." + visible: actionListView.count > 0 + } + + ListView { + id: actionListView + Layout.fillWidth: true + Layout.fillHeight: true + model: RulesFilterModel { + id: rulesFilterModel + rules: Engine.ruleManager.rules + filterEventDeviceId: root.device.id + } + delegate: SwipeDelegate { + width: parent.width + property var ruleActions: rulesFilterModel.get(index).ruleActions + property var ruleAction: ruleActions.count == 1 ? ruleActions.get(0) : null + property var ruleActionType: ruleAction ? ruleActionDeviceClass.actionTypes.getActionType(ruleAction.actionTypeId) : null + property var ruleActionDevice: ruleAction ? Engine.deviceManager.devices.getDevice(ruleAction.deviceId) : null + property var ruleActionDeviceClass: ruleActionDevice ? Engine.deviceManager.deviceClasses.getDeviceClass(ruleActionDevice.deviceClassId) : null + property var ruleActionParams: ruleAction ? ruleAction.ruleActionParams : null + property var ruleActionParam: ruleActionParams.count == 1 ? ruleActionParams.get(0) : null + text: ruleActions.count > 1 ? "Multiple actions" : qsTr("%1: Set %2 to %3").arg(ruleActionDevice.name).arg(ruleActionType.name).arg(ruleActionParam.value) + swipe.right: MouseArea { + anchors.right: parent.right + height: parent.height + width: height + ColorIcon { + anchors.fill: parent + anchors.margins: app.margins + name: "../images/delete.svg" + color: "red" + } + onClicked: { + Engine.ruleManager.removeRule(rulesFilterModel.get(index).id) + } + } + } + + Label { + width: parent.width - (app.margins * 2) + wrapMode: Text.WordWrap + horizontalAlignment: Text.AlignHCenter + anchors.centerIn: parent + text: "No actions configured for this switch. You may add some actions for this switch by using the \"Add action\" button at the bottom." + visible: actionListView.count == 0 + } + } + + Button { + Layout.fillWidth: true + Layout.margins: app.margins + text: "Add an action" + onClicked: { + var page = pageStack.push(Qt.resolvedUrl("../magic/SelectActionPage.qml"), {text: "When this switch is pressed..."}); + page.complete.connect(function() { + print("have action:", page.device, page.actionType, page.params) + var rule = {}; + rule["name"] = root.device.name + " pressed" + var events = []; + var event = {}; + event["deviceId"] = root.device.id; + var eventDeviceClass = Engine.deviceManager.deviceClasses.getDeviceClass(root.device.deviceClassId) + event["eventTypeId"] = eventDeviceClass.eventTypes.findByName("pressed").id; + events.push(event); + rule["eventDescriptors"] = events; + var actions = []; + var action = {}; + action["actionTypeId"] = page.actionType.id; + action["deviceId"] = page.device.id; + action["ruleActionParams"] = page.params; + actions.push(action); + rule["actions"] = actions; + Engine.ruleManager.addRule(rule); + pageStack.pop(root) + }) + } + } + } +} diff --git a/guh-control/ui/devicepages/GenericDevicePage.qml b/guh-control/ui/devicepages/GenericDevicePage.qml index 7951efae..c8752de4 100644 --- a/guh-control/ui/devicepages/GenericDevicePage.qml +++ b/guh-control/ui/devicepages/GenericDevicePage.qml @@ -16,7 +16,7 @@ Page { HeaderButton { imageSource: "../images/info.svg" - onClicked: pageStack.push(deviceStateDetailsPage) + onClicked: pageStack.push(Qt.resolvedUrl("GenericDeviceStateDetailsPage.qml"), {device: root.device}) } } @@ -133,38 +133,4 @@ Page { } } } - - Component { - id: deviceStateDetailsPage - Page { - header: GuhHeader { - text: "Details for " + root.device.name - onBackPressed: pageStack.pop() - } - ColumnLayout { - anchors { left: parent.left; top: parent.top; right: parent.right; margins: app.margins } - spacing: app.margins - - Repeater { - model: deviceClass.stateTypes - delegate: RowLayout { - width: parent.width - height: app.largeFont - - Label { - id: stateLabel - Layout.preferredWidth: parent.width / 2 - text: name - } - - Label { - id: valueLable - Layout.fillWidth: true - text: device.states.getState(id).value + " " + deviceClass.stateTypes.getStateType(id).unitString - } - } - } - } - } - } } diff --git a/guh-control/ui/devicepages/GenericDeviceStateDetailsPage.qml b/guh-control/ui/devicepages/GenericDeviceStateDetailsPage.qml new file mode 100644 index 00000000..06dfb6c2 --- /dev/null +++ b/guh-control/ui/devicepages/GenericDeviceStateDetailsPage.qml @@ -0,0 +1,41 @@ +import QtQuick 2.5 +import QtQuick.Controls 2.1 +import QtQuick.Layouts 1.1 +import Guh 1.0 +import "../components" + +Page { + id: root + + property var device + readonly property var deviceClass: Engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId) + + header: GuhHeader { + text: "Details for " + root.device.name + onBackPressed: pageStack.pop() + } + ColumnLayout { + anchors { left: parent.left; top: parent.top; right: parent.right; margins: app.margins } + spacing: app.margins + + Repeater { + model: deviceClass.stateTypes + delegate: RowLayout { + width: parent.width + height: app.largeFont + + Label { + id: stateLabel + Layout.preferredWidth: parent.width / 2 + text: name + } + + Label { + id: valueLable + Layout.fillWidth: true + text: device.states.getState(id).value + " " + deviceClass.stateTypes.getStateType(id).unitString + } + } + } + } +} diff --git a/guh-control/ui/devicepages/MediaDevicePage.qml b/guh-control/ui/devicepages/MediaDevicePage.qml index d265301f..08105fe8 100644 --- a/guh-control/ui/devicepages/MediaDevicePage.qml +++ b/guh-control/ui/devicepages/MediaDevicePage.qml @@ -17,7 +17,7 @@ Page { HeaderButton { imageSource: "../images/info.svg" - onClicked: pageStack.push(deviceStateDetailsPage) + onClicked: pageStack.push(Qt.resolvedUrl("GenericDeviceStateDetailsPage.qml"), {device: root.device}) } } diff --git a/guh-control/ui/images/delete.svg b/guh-control/ui/images/delete.svg new file mode 100644 index 00000000..6d60316b --- /dev/null +++ b/guh-control/ui/images/delete.svg @@ -0,0 +1,166 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/guh-control/ui/images/mediaplayer-app-symbolic.svg b/guh-control/ui/images/mediaplayer-app-symbolic.svg new file mode 100644 index 00000000..1bc6bbfe --- /dev/null +++ b/guh-control/ui/images/mediaplayer-app-symbolic.svg @@ -0,0 +1,20 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/guh-control/ui/images/system-shutdown.svg b/guh-control/ui/images/system-shutdown.svg new file mode 100644 index 00000000..854848e6 --- /dev/null +++ b/guh-control/ui/images/system-shutdown.svg @@ -0,0 +1,18 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/guh-control/ui/magic/SelectActionPage.qml b/guh-control/ui/magic/SelectActionPage.qml new file mode 100644 index 00000000..bbe7ef20 --- /dev/null +++ b/guh-control/ui/magic/SelectActionPage.qml @@ -0,0 +1,180 @@ +import QtQuick 2.5 +import QtQuick.Controls 2.1 +import QtQuick.Layouts 1.1 +import Guh 1.0 +import "../components" +import "../actiondelegates" + +Page { + id: root + + // input + property string text + + // output + property var device: null + property var actionType: null + property var params: [] + signal complete(); + + header: GuhHeader { + text: "Select action" + onBackPressed: pageStack.pop() + } + + ColumnLayout { + anchors { left: parent.left; top: parent.top; right: parent.right; margins: app.margins } + spacing: app.margins + + Label { + text: root.text + Layout.fillWidth: true + } + + Button { + text: "control a certain device" + Layout.fillWidth: true + onClicked: { + pageStack.push(selectDeviceComponent) + } + } + Button { + text: "control a group of devices" + Layout.fillWidth: true + } + } + + Component { + id: selectDeviceComponent + Page { + header: GuhHeader { + text: "Select device" + onBackPressed: pageStack.pop() + } + + ColumnLayout { + anchors.fill: parent + + ListView { + Layout.fillHeight: true + Layout.fillWidth: true + model: Engine.deviceManager.devices + delegate: ItemDelegate { + width: parent.width + Label { + anchors.fill: parent + anchors.margins: app.margins + text: model.name + verticalAlignment: Text.AlignVCenter + } + onClicked: { + root.device = Engine.deviceManager.devices.get(index) + var deviceClass = Engine.deviceManager.deviceClasses.getDeviceClass(model.deviceClassId) + pageStack.push(selectDeviceActionComponent, {deviceClass: deviceClass}) + } + } + } + } + } + } + + Component { + id: selectDeviceActionComponent + Page { + id: page + property var deviceClass + + header: GuhHeader { + text: "Select action" + onBackPressed: pageStack.pop() + } + + ColumnLayout { + anchors.fill: parent + ListView { + Layout.fillHeight: true + Layout.fillWidth: true + model: page.deviceClass.actionTypes + + delegate: ItemDelegate { + width: parent.width + Label { + anchors.fill: parent + anchors.margins: app.margins + text: model.name + verticalAlignment: Text.AlignVCenter + } + + onClicked: { + root.actionType = page.deviceClass.actionTypes.get(index) + if (page.deviceClass.actionTypes.get(index).paramTypes.count == 0) { + // We're all set. + root.complete(); + } else { + // need to fill in params + var actionType = page.deviceClass.actionTypes.get(index) + pageStack.push(selectDeviceActionParamComponent, {actionType: actionType}) + } + } + } + } + } + } + } + + Component { + id: selectDeviceActionParamComponent + Page { + id: page + property var actionType + header: GuhHeader { + text: "params" + onBackPressed: pageStack.pop() + } + + ColumnLayout { + anchors.fill: parent + Repeater { + id: delegateRepeater + model: page.actionType.paramTypes + ItemDelegate { + id: paramDelegate + Layout.fillWidth: true + property var paramType: page.actionType.paramTypes.get(index) + property var value: paramType.defaultValue + RowLayout { + anchors.fill: parent + Label { + Layout.fillWidth: true + text: paramDelegate.paramType.name + } + Switch { + checked: paramDelegate.value + onClicked: paramDelegate.value = checked + } + } + } + } + Item { + Layout.fillWidth: true + Layout.fillHeight: true + } + Button { + text: "OK" + Layout.fillWidth: true + Layout.margins: app.margins + onClicked: { + for (var i = 0; i < delegateRepeater.count; i++) { + var paramDelegate = delegateRepeater.itemAt(i); + var param = {} + param["paramTypeId"] = paramDelegate.paramType.id + param["value"] = paramDelegate.value + root.params.push(param) + } + root.complete() + } + } + } + } + } +} diff --git a/guh-control/ui/main.qml b/guh-control/ui/main.qml index 296239d9..20a0836c 100644 --- a/guh-control/ui/main.qml +++ b/guh-control/ui/main.qml @@ -86,6 +86,8 @@ ApplicationWindow { return "Sensor" case "media": return "Media" + case "button": + return "Switches" } } @@ -94,7 +96,9 @@ ApplicationWindow { case "light": return Qt.resolvedUrl("images/torch-on.svg") case "media": - return Qt.resolvedUrl("images/media-preview-start.svg") + return Qt.resolvedUrl("images/mediaplayer-app-symbolic.svg") + case "button": + return Qt.resolvedUrl("images/system-shutdown.svg") } } diff --git a/libguh-common/libguh-common.pro b/libguh-common/libguh-common.pro index 98009823..c7cc2283 100644 --- a/libguh-common/libguh-common.pro +++ b/libguh-common/libguh-common.pro @@ -29,6 +29,14 @@ HEADERS += types/types.h \ types/statesproxy.h \ types/plugin.h \ types/plugins.h \ + types/rules.h \ + types/rule.h \ + types/eventdescriptor.h \ + types/eventdescriptors.h \ + types/ruleaction.h \ + types/ruleactions.h \ + types/ruleactionparams.h \ + types/ruleactionparam.h SOURCES += types/vendor.cpp \ types/vendors.cpp \ @@ -49,6 +57,14 @@ SOURCES += types/vendor.cpp \ types/statesproxy.cpp \ types/plugin.cpp \ types/plugins.cpp \ + types/rules.cpp \ + types/rule.cpp \ + types/eventdescriptor.cpp \ + types/eventdescriptors.cpp \ + types/ruleaction.cpp \ + types/ruleactions.cpp \ + types/ruleactionparams.cpp \ + types/ruleactionparam.cpp # install header file with relative subdirectory for(header, HEADERS) { diff --git a/libguh-common/types/eventdescriptor.cpp b/libguh-common/types/eventdescriptor.cpp new file mode 100644 index 00000000..b4c48041 --- /dev/null +++ b/libguh-common/types/eventdescriptor.cpp @@ -0,0 +1,26 @@ +#include "eventdescriptor.h" + +EventDescriptor::EventDescriptor(QObject *parent) : QObject(parent) +{ + +} + +QUuid EventDescriptor::deviceId() const +{ + return m_deviceId; +} + +void EventDescriptor::setDeviceId(const QUuid &deviceId) +{ + m_deviceId = deviceId; +} + +QUuid EventDescriptor::eventTypeId() const +{ + return m_eventTypeId; +} + +void EventDescriptor::setEventTypeId(const QUuid &eventTypeId) +{ + m_eventTypeId = eventTypeId; +} diff --git a/libguh-common/types/eventdescriptor.h b/libguh-common/types/eventdescriptor.h new file mode 100644 index 00000000..161b999b --- /dev/null +++ b/libguh-common/types/eventdescriptor.h @@ -0,0 +1,29 @@ +#ifndef EVENTDESCRIPTOR_H +#define EVENTDESCRIPTOR_H + +#include +#include + +class EventDescriptor : public QObject +{ + Q_OBJECT + Q_PROPERTY(QUuid deviceId READ deviceId CONSTANT) + Q_PROPERTY(QUuid eventTypeId READ eventTypeId CONSTANT) + +public: + explicit EventDescriptor(QObject *parent = nullptr); + + QUuid deviceId() const; + void setDeviceId(const QUuid &deviceId); + + QUuid eventTypeId() const; + void setEventTypeId(const QUuid &eventTypeId); + +signals: + +private: + QUuid m_deviceId; + QUuid m_eventTypeId; +}; + +#endif // EVENTDESCRIPTOR_H diff --git a/libguh-common/types/eventdescriptors.cpp b/libguh-common/types/eventdescriptors.cpp new file mode 100644 index 00000000..98e2b211 --- /dev/null +++ b/libguh-common/types/eventdescriptors.cpp @@ -0,0 +1,40 @@ +#include "eventdescriptors.h" +#include "eventdescriptor.h" + +EventDescriptors::EventDescriptors(QObject *parent) : + QAbstractListModel(parent) +{ + +} + +int EventDescriptors::rowCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent) + return m_list.count(); +} + +QVariant EventDescriptors::data(const QModelIndex &index, int role) const +{ + return QVariant(); +} + +QHash EventDescriptors::roleNames() const +{ + QHash roles; + roles.insert(RoleName, "name"); + return roles; +} + +EventDescriptor *EventDescriptors::get(int index) const +{ + return m_list.at(index); +} + +void EventDescriptors::addEventDescriptor(EventDescriptor *eventDescriptor) +{ + eventDescriptor->setParent(this); + beginInsertRows(QModelIndex(), m_list.count(), m_list.count()); + m_list.append(eventDescriptor); + endInsertRows(); + emit countChanged(); +} diff --git a/libguh-common/types/eventdescriptors.h b/libguh-common/types/eventdescriptors.h new file mode 100644 index 00000000..3c9019ce --- /dev/null +++ b/libguh-common/types/eventdescriptors.h @@ -0,0 +1,33 @@ +#ifndef EVENTDESCRIPTORS_H +#define EVENTDESCRIPTORS_H + +#include + +class EventDescriptor; + +class EventDescriptors : public QAbstractListModel +{ + Q_OBJECT + Q_PROPERTY(int count READ rowCount NOTIFY countChanged) +public: + enum Roles { + RoleName + }; + explicit EventDescriptors(QObject *parent = nullptr); + + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant data(const QModelIndex &index, int role) const override; + QHash roleNames() const override; + + EventDescriptor* get(int index) const; + + void addEventDescriptor(EventDescriptor *eventDescriptor); + +signals: + void countChanged(); + +private: + QList m_list; +}; + +#endif // EVENTDESCRIPTORS_H diff --git a/libguh-common/types/eventtypes.cpp b/libguh-common/types/eventtypes.cpp index 2c432639..25a04388 100644 --- a/libguh-common/types/eventtypes.cpp +++ b/libguh-common/types/eventtypes.cpp @@ -89,6 +89,17 @@ void EventTypes::clearModel() endResetModel(); } +EventType *EventTypes::findByName(const QString &name) const +{ + foreach (EventType *eventType, m_eventTypes) { + qDebug() << "have eventtypoe" << eventType->name(); + if (eventType->name() == name) { + return eventType; + } + } + return nullptr; +} + QHash EventTypes::roleNames() const { QHash roles; diff --git a/libguh-common/types/eventtypes.h b/libguh-common/types/eventtypes.h index 66c553b3..4f2197a3 100644 --- a/libguh-common/types/eventtypes.h +++ b/libguh-common/types/eventtypes.h @@ -53,6 +53,8 @@ public: void clearModel(); + Q_INVOKABLE EventType *findByName(const QString &name) const; + protected: QHash roleNames() const; diff --git a/libguh-common/types/rule.cpp b/libguh-common/types/rule.cpp new file mode 100644 index 00000000..8ccc9e5a --- /dev/null +++ b/libguh-common/types/rule.cpp @@ -0,0 +1,54 @@ +#include "rule.h" + +#include "eventdescriptors.h" +#include "ruleactions.h" + +Rule::Rule(const QUuid &id, QObject *parent) : + QObject(parent), + m_id(id), + m_eventDescriptors(new EventDescriptors(this)), + m_ruleActions(new RuleActions(this)) +{ + +} + +QUuid Rule::id() const +{ + return m_id; +} + +QString Rule::name() const +{ + return m_name; +} + +void Rule::setName(const QString &name) +{ + if (m_name != name) { + m_name = name; + emit nameChanged(); + } +} + +bool Rule::enabled() const +{ + return m_enabled; +} + +void Rule::setEnabled(bool enabled) +{ + if (m_enabled != enabled) { + m_enabled = enabled; + emit enabledChanged(); + } +} + +EventDescriptors *Rule::eventDescriptors() const +{ + return m_eventDescriptors; +} + +RuleActions *Rule::ruleActions() const +{ + return m_ruleActions; +} diff --git a/libguh-common/types/rule.h b/libguh-common/types/rule.h new file mode 100644 index 00000000..c1a6fefc --- /dev/null +++ b/libguh-common/types/rule.h @@ -0,0 +1,44 @@ +#ifndef RULE_H +#define RULE_H + +#include +#include + +class EventDescriptors; +class RuleActions; + +class Rule : public QObject +{ + Q_OBJECT + Q_PROPERTY(QUuid id READ id CONSTANT) + Q_PROPERTY(QString name READ name NOTIFY nameChanged) + Q_PROPERTY(bool enabled READ enabled NOTIFY enabledChanged) + Q_PROPERTY(EventDescriptors* eventDescriptors READ eventDescriptors CONSTANT) + Q_PROPERTY(RuleActions* ruleActions READ ruleActions CONSTANT) +public: + explicit Rule(const QUuid &id, QObject *parent = nullptr); + + QUuid id() const; + + QString name() const; + void setName(const QString &name); + + bool enabled() const; + void setEnabled(bool enabled); + + EventDescriptors* eventDescriptors() const; + RuleActions* ruleActions() const; + +signals: + void nameChanged(); + void enabledChanged(); + +private: + QUuid m_id; + QString m_name; + bool m_enabled = false; + EventDescriptors *m_eventDescriptors = nullptr; + RuleActions *m_ruleActions = nullptr; +}; + +#endif // RULE_H diff --git a/libguh-common/types/ruleaction.cpp b/libguh-common/types/ruleaction.cpp new file mode 100644 index 00000000..42167135 --- /dev/null +++ b/libguh-common/types/ruleaction.cpp @@ -0,0 +1,39 @@ +#include "ruleaction.h" + +#include "ruleactionparams.h" + +RuleAction::RuleAction(QObject *parent) : QObject(parent) +{ + m_ruleActionParams = new RuleActionParams(this); +} + +QUuid RuleAction::deviceId() const +{ + return m_deviceId; +} + +void RuleAction::setDeviceId(const QUuid &deviceId) +{ + if (m_deviceId != deviceId) { + m_deviceId = deviceId; + emit deviceIdChanged(); + } +} + +QUuid RuleAction::actionTypeId() const +{ + return m_actionTypeId; +} + +void RuleAction::setActionTypeId(const QUuid &actionTypeId) +{ + if (m_actionTypeId != actionTypeId) { + m_actionTypeId = actionTypeId; + emit actionTypeIdChanged(); + } +} + +RuleActionParams *RuleAction::ruleActionParams() const +{ + return m_ruleActionParams; +} diff --git a/libguh-common/types/ruleaction.h b/libguh-common/types/ruleaction.h new file mode 100644 index 00000000..7a9c0656 --- /dev/null +++ b/libguh-common/types/ruleaction.h @@ -0,0 +1,37 @@ +#ifndef RULEACTION_H +#define RULEACTION_H + +#include +#include + +class RuleActionParams; + +class RuleAction : public QObject +{ + Q_OBJECT + Q_PROPERTY(QUuid deviceId READ deviceId NOTIFY deviceIdChanged) + Q_PROPERTY(QUuid actionTypeId READ actionTypeId NOTIFY actionTypeIdChanged) + Q_PROPERTY(RuleActionParams* ruleActionParams READ ruleActionParams CONSTANT) + +public: + explicit RuleAction(QObject *parent = nullptr); + + QUuid deviceId() const; + void setDeviceId(const QUuid &deviceId); + + QUuid actionTypeId() const; + void setActionTypeId(const QUuid &actionTypeId); + + RuleActionParams* ruleActionParams() const; + +signals: + void deviceIdChanged(); + void actionTypeIdChanged(); + +private: + QUuid m_deviceId; + QUuid m_actionTypeId; + RuleActionParams *m_ruleActionParams; +}; + +#endif // RULEACTION_H diff --git a/libguh-common/types/ruleactionparam.cpp b/libguh-common/types/ruleactionparam.cpp new file mode 100644 index 00000000..a0b97d89 --- /dev/null +++ b/libguh-common/types/ruleactionparam.cpp @@ -0,0 +1,32 @@ +#include "ruleactionparam.h" + +RuleActionParam::RuleActionParam(QObject *parent) : QObject(parent) +{ + +} + +QUuid RuleActionParam::paramTypeId() const +{ + return m_paramTypeId; +} + +void RuleActionParam::setParamTypeId(const QUuid ¶mTypeId) +{ + if (m_paramTypeId != paramTypeId) { + m_paramTypeId = paramTypeId; + emit paramTypeIdChanged(); + } +} + +QVariant RuleActionParam::value() const +{ + return m_value; +} + +void RuleActionParam::setValue(const QVariant &value) +{ + if (m_value != value) { + m_value = value; + emit valueChanged(); + } +} diff --git a/libguh-common/types/ruleactionparam.h b/libguh-common/types/ruleactionparam.h new file mode 100644 index 00000000..19c9e36d --- /dev/null +++ b/libguh-common/types/ruleactionparam.h @@ -0,0 +1,31 @@ +#ifndef RULEACTIONPARAM_H +#define RULEACTIONPARAM_H + +#include +#include +#include + +class RuleActionParam : public QObject +{ + Q_OBJECT + Q_PROPERTY(QUuid paramTypeId READ paramTypeId NOTIFY paramTypeIdChanged) + Q_PROPERTY(QVariant value READ value NOTIFY valueChanged) +public: + explicit RuleActionParam(QObject *parent = nullptr); + + QUuid paramTypeId() const; + void setParamTypeId(const QUuid ¶mTypeId); + + QVariant value() const; + void setValue(const QVariant &value); + +signals: + void paramTypeIdChanged(); + void valueChanged(); + +private: + QUuid m_paramTypeId; + QVariant m_value; +}; + +#endif // RULEACTIONPARAM_H diff --git a/libguh-common/types/ruleactionparams.cpp b/libguh-common/types/ruleactionparams.cpp new file mode 100644 index 00000000..abea6b37 --- /dev/null +++ b/libguh-common/types/ruleactionparams.cpp @@ -0,0 +1,31 @@ +#include "ruleactionparams.h" + +#include "ruleactionparam.h" + +RuleActionParams::RuleActionParams(QObject *parent) : QAbstractListModel(parent) +{ + +} + +int RuleActionParams::rowCount(const QModelIndex &parent) const +{ + return m_list.count(); +} + +QVariant RuleActionParams::data(const QModelIndex &index, int role) const +{ + return QVariant(); +} + +void RuleActionParams::addRuleActionParam(RuleActionParam *ruleActionParam) +{ + ruleActionParam->setParent(this); + beginInsertRows(QModelIndex(), m_list.count(), m_list.count()); + m_list.append(ruleActionParam); + endInsertRows(); +} + +RuleActionParam *RuleActionParams::get(int index) const +{ + return m_list.at(index); +} diff --git a/libguh-common/types/ruleactionparams.h b/libguh-common/types/ruleactionparams.h new file mode 100644 index 00000000..ed2ea198 --- /dev/null +++ b/libguh-common/types/ruleactionparams.h @@ -0,0 +1,29 @@ +#ifndef RULEACTIONPARAMS_H +#define RULEACTIONPARAMS_H + +#include + +class RuleActionParam; + +class RuleActionParams : public QAbstractListModel +{ + Q_OBJECT + Q_PROPERTY(int count READ rowCount NOTIFY countChanged) +public: + explicit RuleActionParams(QObject *parent = nullptr); + + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant data(const QModelIndex &index, int role) const override; + + void addRuleActionParam(RuleActionParam* ruleActionParam); + + Q_INVOKABLE RuleActionParam* get(int index) const; + +signals: + void countChanged(); + +private: + QList m_list; +}; + +#endif // RULEACTIONPARAMS_H diff --git a/libguh-common/types/ruleactions.cpp b/libguh-common/types/ruleactions.cpp new file mode 100644 index 00000000..e3c32182 --- /dev/null +++ b/libguh-common/types/ruleactions.cpp @@ -0,0 +1,30 @@ +#include "ruleactions.h" +#include "ruleaction.h" + +RuleActions::RuleActions(QObject *parent) : QAbstractListModel(parent) +{ + +} + +int RuleActions::rowCount(const QModelIndex &parent) const +{ + return m_list.count(); +} + +QVariant RuleActions::data(const QModelIndex &index, int role) const +{ + return QVariant(); +} + +void RuleActions::addRuleAction(RuleAction *ruleAction) +{ + ruleAction->setParent(this); + beginInsertRows(QModelIndex(), m_list.count(), m_list.count()); + m_list.append(ruleAction); + endInsertRows(); +} + +RuleAction *RuleActions::get(int index) const +{ + return m_list.at(index); +} diff --git a/libguh-common/types/ruleactions.h b/libguh-common/types/ruleactions.h new file mode 100644 index 00000000..4ac49f06 --- /dev/null +++ b/libguh-common/types/ruleactions.h @@ -0,0 +1,29 @@ +#ifndef RULEACTIONS_H +#define RULEACTIONS_H + +#include + +class RuleAction; + +class RuleActions : public QAbstractListModel +{ + Q_OBJECT + Q_PROPERTY(int count READ rowCount NOTIFY countChanged) +public: + explicit RuleActions(QObject *parent = nullptr); + + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant data(const QModelIndex &index, int role) const override; + + void addRuleAction(RuleAction* ruleAction); + + Q_INVOKABLE RuleAction* get(int index) const; + +signals: + void countChanged(); + +private: + QList m_list; +}; + +#endif // RULEACTIONS_H diff --git a/libguh-common/types/rules.cpp b/libguh-common/types/rules.cpp new file mode 100644 index 00000000..c270e00f --- /dev/null +++ b/libguh-common/types/rules.cpp @@ -0,0 +1,72 @@ +#include "rules.h" +#include "rule.h" + +Rules::Rules(QObject *parent) : QAbstractListModel(parent) +{ + +} + +void Rules::clear() +{ + qDeleteAll(m_list); + m_list.clear(); +} + +int Rules::rowCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent) + return m_list.count(); +} + +QVariant Rules::data(const QModelIndex &index, int role) const +{ + switch (role) { + case RoleName: + return m_list.at(index.row())->name(); + } + return QVariant(); +} + +QHash Rules::roleNames() const +{ + QHash roles; + roles.insert(RoleName, "name"); + return roles; +} + +void Rules::insert(Rule *rule) +{ + beginInsertRows(QModelIndex(), m_list.count(), m_list.count()); + m_list.append(rule); + endInsertRows(); +} + +void Rules::remove(const QUuid &ruleId) +{ + for (int i = 0; i < m_list.count(); i++) { + if (m_list.at(i)->id() == ruleId) { + beginRemoveRows(QModelIndex(), i, i); + m_list.takeAt(i)->deleteLater(); + endRemoveRows(); + return; + } + } +} + +Rule *Rules::get(int index) const +{ + if (index < 0 || index >= m_list.count()) { + return nullptr; + } + return m_list.at(index); +} + +Rule *Rules::getRule(const QUuid &ruleId) const +{ + foreach (Rule *rule, m_list) { + if (rule->id() == ruleId) { + return rule; + } + } + return nullptr; +} diff --git a/libguh-common/types/rules.h b/libguh-common/types/rules.h new file mode 100644 index 00000000..bbb54395 --- /dev/null +++ b/libguh-common/types/rules.h @@ -0,0 +1,33 @@ +#ifndef RULES_H +#define RULES_H + +#include + +class Rule; + +class Rules : public QAbstractListModel +{ + Q_OBJECT +public: + enum Roles { + RoleName + }; + explicit Rules(QObject *parent = nullptr); + + void clear(); + + int rowCount(const QModelIndex &parent) const override; + QVariant data(const QModelIndex &index, int role) const override; + QHash roleNames() const override; + + void insert(Rule *rule); + void remove(const QUuid &ruleId); + + Q_INVOKABLE Rule* get(int index) const; + Q_INVOKABLE Rule* getRule(const QUuid &ruleId) const; + +private: + QList m_list; +}; + +#endif // RULES_H