add support for creating basic rules

pull/1/head
Michael Zanetti 2017-10-26 01:08:59 +02:00
parent 47298be52c
commit 6de33ca718
43 changed files with 1518 additions and 54 deletions

View File

@ -117,7 +117,7 @@ void DeviceManager::getSupportedDevicesResponse(const QVariantMap &params)
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);
}
}

View File

@ -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();
}
}
}

View File

@ -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();
};

View File

@ -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" <<dc->name() << "has interfaces" << dc->interfaces();
foreach (const QString &interface, dc->interfaces()) {
if (!m_shownInterfaces.contains(interface)) {

View File

@ -52,7 +52,7 @@ void JsonRpcClient::registerNotificationHandler(JsonHandler *handler, const QStr
m_notificationHandlers.insert(handler->nameSpace(), qMakePair<JsonHandler*, QString>(handler, method));
}
JsonRpcReply *JsonRpcClient::sendCommand(const QString &method, const QVariantMap &params, QObject *caller, const QString &callbackMethod)
void JsonRpcClient::sendCommand(const QString &method, const QVariantMap &params, 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);
}

View File

@ -45,8 +45,8 @@ public:
void registerNotificationHandler(JsonHandler *handler, const QString &method);
JsonRpcReply* sendCommand(const QString &method, const QVariantMap &params, 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 &params, 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;

View File

@ -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<DeviceClassesProxy>(uri, 1, 0, "DeviceClassesProxy");
qmlRegisterType<DeviceDiscovery>(uri, 1, 0, "DeviceDiscovery");
qmlRegisterUncreatableType<RuleManager>(uri, 1, 0, "RuleManager", "Get it from the Engine");
qmlRegisterUncreatableType<Rules>(uri, 1, 0, "Rules", "Get it from RuleManager");
qmlRegisterUncreatableType<Rule>(uri, 1, 0, "Rule", "Get it from Rules");
qmlRegisterUncreatableType<RuleActions>(uri, 1, 0, "RuleActions", "Get them from the rule");
qmlRegisterUncreatableType<RuleAction>(uri, 1, 0, "RuleAction", "Get it from RuleActions");
qmlRegisterUncreatableType<RuleActionParams>(uri, 1, 0, "RuleActionParams", "Get it from RuleActions");
qmlRegisterUncreatableType<RuleActionParam>(uri, 1, 0, "RuleActionParam", "Get it from RuleActionParams");
qmlRegisterType<RulesFilterModel>(uri, 1, 0, "RulesFilterModel");
qmlRegisterUncreatableType<Plugin>(uri, 1, 0, "Plugin", "Can't create this in QML. Get it from the Plugins.");
qmlRegisterUncreatableType<Plugins>(uri, 1, 0, "Plugins", "Can't create this in QML. Get it from the DeviceManager.");
qmlRegisterType<PluginsProxy>(uri, 1, 0, "PluginsProxy");

View File

@ -0,0 +1,66 @@
#include "rulesfiltermodel.h"
#include "types/rules.h"
#include "types/rule.h"
#include "types/eventdescriptors.h"
#include "types/eventdescriptor.h"
#include <QDebug>
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;
}

View File

@ -0,0 +1,39 @@
#ifndef RULESFILTERMODEL_H
#define RULESFILTERMODEL_H
#include <QSortFilterProxyModel>
#include <QUuid>
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

View File

@ -52,5 +52,11 @@
<file>ui/images/media-preview-start.svg</file>
<file>ui/MagicPage.qml</file>
<file>ui/magic/NewRulePage.qml</file>
<file>ui/images/mediaplayer-app-symbolic.svg</file>
<file>ui/images/system-shutdown.svg</file>
<file>ui/devicepages/ButtonDevicePage.qml</file>
<file>ui/magic/SelectActionPage.qml</file>
<file>ui/devicepages/GenericDeviceStateDetailsPage.qml</file>
<file>ui/images/delete.svg</file>
</qresource>
</RCC>

142
guh-control/rulemanager.cpp Normal file
View File

@ -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 &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();
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 &params)
{
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 &params)
{
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 &params)
{
qDebug() << "Add rule reply" << params;
}
void RuleManager::removeRuleReply(const QVariantMap &params)
{
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);
}
}

45
guh-control/rulemanager.h Normal file
View File

@ -0,0 +1,45 @@
#ifndef RULEMANAGER_H
#define RULEMANAGER_H
#include <QObject>
#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 &params);
void getRulesReply(const QVariantMap &params);
void getRuleDetailsReply(const QVariantMap &params);
void addRuleReply(const QVariantMap &params);
void removeRuleReply(const QVariantMap &params);
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

View File

@ -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: {

View File

@ -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
}
}
}
}

View File

@ -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)})
}
}
}

View File

@ -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)
})
}
}
}
}

View File

@ -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
}
}
}
}
}
}
}

View File

@ -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
}
}
}
}
}

View File

@ -17,7 +17,7 @@ Page {
HeaderButton {
imageSource: "../images/info.svg"
onClicked: pageStack.push(deviceStateDetailsPage)
onClicked: pageStack.push(Qt.resolvedUrl("GenericDeviceStateDetailsPage.qml"), {device: root.device})
}
}

View File

@ -0,0 +1,166 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="96"
height="96"
id="svg4874"
version="1.1"
inkscape:version="0.91+devel r"
viewBox="0 0 96 96.000001"
sodipodi:docname="edit-delete01.svg">
<defs
id="defs4876" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="10.976561"
inkscape:cx="41.561283"
inkscape:cy="53.1906"
inkscape:document-units="px"
inkscape:current-layer="g4780"
showgrid="true"
showborder="true"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:snap-bbox="true"
inkscape:bbox-paths="true"
inkscape:bbox-nodes="true"
inkscape:snap-bbox-edge-midpoints="true"
inkscape:snap-bbox-midpoints="true"
inkscape:object-paths="true"
inkscape:snap-intersection-paths="true"
inkscape:object-nodes="true"
inkscape:snap-smooth-nodes="true"
inkscape:snap-midpoints="true"
inkscape:snap-object-midpoints="true"
inkscape:snap-center="true"
showguides="true"
inkscape:guide-bbox="true"
inkscape:snap-global="true">
<inkscape:grid
type="xygrid"
id="grid5451"
empspacing="8" />
<sodipodi:guide
orientation="1,0"
position="8,-8.0000001"
id="guide4063" />
<sodipodi:guide
orientation="1,0"
position="4,-8.0000001"
id="guide4065" />
<sodipodi:guide
orientation="0,1"
position="-8,88.000001"
id="guide4067" />
<sodipodi:guide
orientation="0,1"
position="-8,92.000001"
id="guide4069" />
<sodipodi:guide
orientation="0,1"
position="104,4"
id="guide4071" />
<sodipodi:guide
orientation="0,1"
position="-5,8.0000001"
id="guide4073" />
<sodipodi:guide
orientation="1,0"
position="92,-8.0000001"
id="guide4075" />
<sodipodi:guide
orientation="1,0"
position="88,-8.0000001"
id="guide4077" />
<sodipodi:guide
orientation="0,1"
position="-8,84.000001"
id="guide4074" />
<sodipodi:guide
orientation="1,0"
position="12,-8.0000001"
id="guide4076" />
<sodipodi:guide
orientation="0,1"
position="-5,12"
id="guide4078" />
<sodipodi:guide
orientation="1,0"
position="84,-9.0000001"
id="guide4080" />
<sodipodi:guide
position="48,-8.0000001"
orientation="1,0"
id="guide4170" />
<sodipodi:guide
position="-8,48"
orientation="0,1"
id="guide4172" />
</sodipodi:namedview>
<metadata
id="metadata4879">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(67.857146,-78.50504)">
<g
transform="matrix(0,-1,-1,0,373.50506,516.50504)"
id="g4845"
style="display:inline">
<g
inkscape:export-ydpi="90"
inkscape:export-xdpi="90"
inkscape:export-filename="next01.png"
transform="matrix(-0.9996045,0,0,1,575.94296,-611.00001)"
id="g4778"
inkscape:label="Layer 1">
<g
transform="matrix(-1,0,0,1,575.99999,611)"
id="g4780"
style="display:inline">
<rect
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:none;stroke:none;stroke-width:4;marker:none;enable-background:accumulate"
id="rect4782"
width="96.037987"
height="96"
x="-438.00244"
y="345.36221"
transform="scale(-1,1)" />
<path
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;line-height:125%;font-family:Ubuntu;-inkscape-font-specification:Ubuntu;text-align:center;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#808080;fill-opacity:1;stroke:none;stroke-width:0.99980223"
d="M 48,4 C 44.00014,4 39.99211,4.7461162 36,6.1503906 l 0,6.7109374 C 29.327124,13.810409 22.655558,15.52986 16,17.957031 L 16,24 l -4,0 0,4 2,0 1.998047,0 L 20,28 31.998047,28 36,28 45.998047,28 50,28 59.998047,28 64,28 75.998047,28 80,28 l 4,0 0,-4 -4,0 0,-6.042969 C 73.332931,15.582208 66.666543,13.849013 60,12.882812 L 60,6.1503906 C 55.99972,4.7760144 51.99985,4 48,4 Z m 0,4 c 2.66654,0 5.33317,0.5173461 8,1.4335938 l 0,2.9628902 C 53.333392,12.134797 50.666623,12 48,12 c -2.665975,0 -5.332361,0.129657 -8,0.384766 L 40,9.4335938 C 42.66138,8.497414 45.33345,8 48,8 Z m -32.001953,18 0,54 c 0,2.633248 0.244566,4.726438 0.910156,6.488281 0.66558,1.761843 1.859171,3.170898 3.369141,4.009766 C 23.297284,92.175793 27,92 32,92 l 16,0 15.998047,0 c 5,0 8.702716,0.175793 11.722656,-1.501953 1.50996,-0.838868 2.701608,-2.247923 3.367188,-4.009766 C 79.753481,84.726438 80,82.633248 80,80 l 0,-46 -4.001953,0 0,46 c 0,2.366744 -0.255434,4.023564 -0.652344,5.074219 -0.39692,1.050654 -0.828329,1.516607 -1.568359,1.927734 C 72.297284,87.824208 68.998047,88 63.998047,88 L 48,88 47.998047,88 32,88 c -5,0 -8.299237,-0.175792 -9.779297,-0.998047 -0.74004,-0.411127 -1.171449,-0.87708 -1.568359,-1.927734 C 20.255424,84.023564 20,82.366744 20,80 l 0,-54 z m 16,8 0,36 L 36,70 36,34 Z m 14,0 0,36 L 50,70 50,34 Z m 14,0 0,36 L 64,70 64,34 Z m 13.560547,41.115234 0.111328,0.144532 c -0.0213,-0.02629 -0.03163,-0.05945 -0.05273,-0.08594 -0.017,-0.02229 -0.04169,-0.0361 -0.05859,-0.05859 z m -51.16211,0.01367 c -0.0169,0.02239 -0.04159,0.03816 -0.05859,0.06055 -0.021,0.02639 -0.03143,0.05965 -0.05273,0.08594 z"
transform="matrix(0,-1,-1.0003957,0,438.00245,441.36222)"
id="path4157"
inkscape:connector-curvature="0"
sodipodi:nodetypes="scccccccccccccccccccccccssccsccscsssscssssccssssccssssccccccccccccccccccccccccc" />
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.6 KiB

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg id="svg4874" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="96" viewBox="0 0 96 96.000001" width="96" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
<metadata id="metadata4879">
<rdf:RDF>
<cc:Work rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
<dc:title/>
</cc:Work>
</rdf:RDF>
</metadata>
<g id="layer1" transform="translate(67.857 -78.505)">
<rect id="rect4782" style="color:#000000;fill:none" transform="rotate(90)" height="96" width="96" y="-28.143" x="78.505"/>
<path id="path4179" style="color-rendering:auto;text-decoration-color:#000000;color:#000000;font-variant-numeric:normal;shape-rendering:auto;solid-color:#000000;text-decoration-line:none;fill:#808080;font-variant-position:normal;mix-blend-mode:normal;block-progression:tb;font-feature-settings:normal;shape-padding:0;font-variant-alternates:normal;text-indent:0;font-variant-caps:normal;image-rendering:auto;white-space:normal;text-decoration-style:solid;font-variant-ligatures:none;isolation:auto;text-transform:none" d="m-47.881 90.506c-5.0328 0.05818-8.7136-0.12028-11.725 1.541-1.5055 0.83064-2.6968 2.2356-3.3555 3.9902-0.65866 1.7547-0.89648 3.8383-0.89648 6.4688v52c0 2.6304 0.23782 4.7121 0.89648 6.4668 0.65866 1.7546 1.85 3.1596 3.3555 3.9902 3.011 1.6613 6.6918 1.4848 11.725 1.543h0.01172 56.023 0.011719c5.0328-0.0582 8.7136 0.11832 11.725-1.543 1.5055-0.83064 2.6968-2.2356 3.3555-3.9902 0.65866-1.7547 0.89648-3.8364 0.89648-6.4668v-52c0-2.6304-0.23782-4.7141-0.89648-6.4688-0.66-1.759-1.851-3.163-3.356-3.994-3.011-1.661-6.692-1.483-11.725-1.541h-0.011719-56.023-0.01172zm0.02344 4h56c5.0383 0.05877 8.3519 0.23688 9.8164 1.0449 0.73364 0.40478 1.1527 0.85295 1.543 1.8926 0.39025 1.0396 0.64062 2.6929 0.64062 5.0625v52c0 2.3696-0.25037 4.0229-0.64062 5.0625s-0.80933 1.4878-1.543 1.8926c-1.4645 0.80804-4.7782 0.98616-9.8164 1.0449h-55.977-0.02344c-5.0383-0.0588-8.3519-0.23688-9.8164-1.0449-0.73364-0.40478-1.1508-0.85296-1.541-1.8926-0.39025-1.0396-0.64258-2.6929-0.64258-5.0625v-52c0-2.3696 0.25232-4.0229 0.64258-5.0625 0.39025-1.0396 0.80738-1.4878 1.541-1.8926 1.4645-0.80804 4.7782-0.98616 9.8164-1.0449z"/>
<path id="path4360" style="color:#000000;fill:#808080" d="m-33.736 107.51v38s18.073-7.7896 33.878-19.012c0-0.003-0.001842-0.006-0.003991-0.0106-0.001842-0.004-0.004171-0.008-0.007125-0.0124-0.003038-0.004-0.005961-0.008-0.008004-0.0125-0.002329-0.004-0.003991-0.008-0.003991-0.012-16.672-11.58-33.855-18.94-33.855-18.94z"/>
<path id="rect4199" style="color:#000000;fill:#808080" d="m12 20v4h8v-4h-8zm0 8v4h8v-4h-8zm0 8v4h8v-4h-8zm0 8v4h8v-4h-8zm0 8v4h8v-4h-8zm0 8v4h8v-4h-8zm0 8v4h8v-4h-8zm0 8v4h8v-4h-8z" transform="translate(-67.857 78.505)"/>
<path id="path4216" style="color:#000000;fill:#808080" d="m8.1429 98.505v4h8v-4h-8zm0 8v4h8v-4h-8zm0 8v4h8v-4h-8zm0 8v4h8v-4h-8zm0 8v4h8v-4h-8zm0 8v4h8v-4h-8zm0 8v4h8v-4h-8zm0 8v4h8v-4h-8z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg id="svg4874" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="96" viewBox="0 0 96 96.000001" width="96" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
<metadata id="metadata4879">
<rdf:RDF>
<cc:Work rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
<dc:title/>
</cc:Work>
</rdf:RDF>
</metadata>
<g id="layer1" transform="translate(67.857 -78.505)">
<rect id="rect4782" style="color:#000000;fill:none" transform="rotate(90)" height="96" width="96" y="-28.143" x="78.505"/>
<path id="rect4747-4" d="m-21.857 84.505 4-1v35h-4z" style="color:#000000;fill:#808080"/>
<path id="path4145" style="color-rendering:auto;text-decoration-color:#000000;color:#000000;font-variant-numeric:normal;shape-rendering:auto;solid-color:#000000;text-decoration-line:none;fill:#808080;font-variant-position:normal;mix-blend-mode:normal;block-progression:tb;font-feature-settings:normal;shape-padding:0;font-variant-alternates:normal;text-indent:0;font-variant-caps:normal;image-rendering:auto;white-space:normal;text-decoration-style:solid;font-variant-ligatures:none;isolation:auto;text-transform:none" d="m-37.852 95.303c-14.099 8.1442-20.983 24.771-16.77 40.504 4.2132 15.732 18.484 26.688 34.764 26.688s30.55-10.955 34.764-26.688c4.2132-15.732-2.669-32.36-16.768-40.504l-2.002 3.4629c12.548 7.244 18.657 22.004 14.907 36.004-3.7501 14.003-16.412 23.723-30.9 23.723s-27.148-9.7195-30.898-23.723c-3.7501-14.003 2.3571-28.758 14.904-36.006l-2-3.4629z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -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()
}
}
}
}
}
}

View File

@ -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")
}
}

View File

@ -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) {

View File

@ -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;
}

View File

@ -0,0 +1,29 @@
#ifndef EVENTDESCRIPTOR_H
#define EVENTDESCRIPTOR_H
#include <QObject>
#include <QUuid>
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

View File

@ -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<int, QByteArray> EventDescriptors::roleNames() const
{
QHash<int, QByteArray> 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();
}

View File

@ -0,0 +1,33 @@
#ifndef EVENTDESCRIPTORS_H
#define EVENTDESCRIPTORS_H
#include <QAbstractListModel>
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<int, QByteArray> roleNames() const override;
EventDescriptor* get(int index) const;
void addEventDescriptor(EventDescriptor *eventDescriptor);
signals:
void countChanged();
private:
QList<EventDescriptor*> m_list;
};
#endif // EVENTDESCRIPTORS_H

View File

@ -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<int, QByteArray> EventTypes::roleNames() const
{
QHash<int, QByteArray> roles;

View File

@ -53,6 +53,8 @@ public:
void clearModel();
Q_INVOKABLE EventType *findByName(const QString &name) const;
protected:
QHash<int, QByteArray> roleNames() const;

View File

@ -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;
}

View File

@ -0,0 +1,44 @@
#ifndef RULE_H
#define RULE_H
#include <QObject>
#include <QUuid>
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

View File

@ -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;
}

View File

@ -0,0 +1,37 @@
#ifndef RULEACTION_H
#define RULEACTION_H
#include <QObject>
#include <QUuid>
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

View File

@ -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 &paramTypeId)
{
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();
}
}

View File

@ -0,0 +1,31 @@
#ifndef RULEACTIONPARAM_H
#define RULEACTIONPARAM_H
#include <QObject>
#include <QUuid>
#include <QVariant>
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 &paramTypeId);
QVariant value() const;
void setValue(const QVariant &value);
signals:
void paramTypeIdChanged();
void valueChanged();
private:
QUuid m_paramTypeId;
QVariant m_value;
};
#endif // RULEACTIONPARAM_H

View File

@ -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);
}

View File

@ -0,0 +1,29 @@
#ifndef RULEACTIONPARAMS_H
#define RULEACTIONPARAMS_H
#include <QAbstractListModel>
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<RuleActionParam*> m_list;
};
#endif // RULEACTIONPARAMS_H

View File

@ -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);
}

View File

@ -0,0 +1,29 @@
#ifndef RULEACTIONS_H
#define RULEACTIONS_H
#include <QAbstractListModel>
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<RuleAction*> m_list;
};
#endif // RULEACTIONS_H

View File

@ -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<int, QByteArray> Rules::roleNames() const
{
QHash<int, QByteArray> 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;
}

View File

@ -0,0 +1,33 @@
#ifndef RULES_H
#define RULES_H
#include <QAbstractListModel>
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<int, QByteArray> 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<Rule*> m_list;
};
#endif // RULES_H