diff --git a/guh-control/jsonrpc/jsontypes.cpp b/guh-control/jsonrpc/jsontypes.cpp index 206f1c83..83953e50 100644 --- a/guh-control/jsonrpc/jsontypes.cpp +++ b/guh-control/jsonrpc/jsontypes.cpp @@ -157,7 +157,7 @@ StateType *JsonTypes::unpackStateType(const QVariantMap &stateTypeMap, QObject * EventType *JsonTypes::unpackEventType(const QVariantMap &eventTypeMap, QObject *parent) { EventType *eventType = new EventType(parent); - eventType->setId(eventTypeMap.value("id").toUuid()); + eventType->setId(eventTypeMap.value("id").toString()); eventType->setName(eventTypeMap.value("name").toString()); eventType->setDisplayName(eventTypeMap.value("displayName").toString()); eventType->setIndex(eventTypeMap.value("index").toInt()); @@ -217,7 +217,9 @@ Device *JsonTypes::unpackDevice(const QVariantMap &deviceMap, QObject *parent) QVariantMap JsonTypes::packRule(Rule *rule) { QVariantMap ret; - ret.insert("ruleId", rule->id()); + if (!rule->id().isNull()) { + ret.insert("ruleId", rule->id()); + } ret.insert("name", rule->name()); ret.insert("enabled", true); @@ -254,6 +256,8 @@ QVariantMap JsonTypes::packRule(Rule *rule) QVariantMap paramDescriptor; paramDescriptor.insert("paramTypeId", rule->eventDescriptors()->get(i)->paramDescriptors()->get(j)->id()); paramDescriptor.insert("value", rule->eventDescriptors()->get(i)->paramDescriptors()->get(j)->value()); + QMetaEnum operatorEnum = QMetaEnum::fromType(); + paramDescriptor.insert("operator", operatorEnum.valueToKey(rule->eventDescriptors()->get(i)->paramDescriptors()->get(j)->operatorType())); paramDescriptors.append(paramDescriptor); } eventDescriptor.insert("paramDescriptors", paramDescriptors); diff --git a/guh-control/resources.qrc b/guh-control/resources.qrc index 6cc21e52..2af4a17b 100644 --- a/guh-control/resources.qrc +++ b/guh-control/resources.qrc @@ -105,7 +105,6 @@ ui/EditDevicesPage.qml ui/devicepages/ConfigureThingPage.qml ui/magic/DeviceRulesPage.qml - ui/magic/SelectEventPage.qml ui/magic/NewThingMagicPage.qml ui/magic/EditRulePage.qml ui/magic/SelectThingPage.qml @@ -115,5 +114,9 @@ ui/magic/SelectRuleActionPage.qml ui/magic/SelectRuleActionParamsPage.qml ui/images/tick.svg + ui/magic/SelectEventDescriptorParamsPage.qml + ui/magic/SelectEventDescriptorPage.qml + ui/paramdelegates/DoubleParamDelegate.qml + ui/paramdescriptordelegates/ParamDescriptorDelegateBase.qml diff --git a/guh-control/rulemanager.cpp b/guh-control/rulemanager.cpp index baef479c..6b990a3b 100644 --- a/guh-control/rulemanager.cpp +++ b/guh-control/rulemanager.cpp @@ -12,6 +12,8 @@ #include "types/stateevaluator.h" #include "types/statedescriptor.h" +#include + RuleManager::RuleManager(JsonRpcClient* jsonClient, QObject *parent) : JsonHandler(parent), m_jsonClient(jsonClient), @@ -66,7 +68,7 @@ void RuleManager::removeRule(const QUuid &ruleId) void RuleManager::editRule(Rule *rule) { QVariantMap params = JsonTypes::packRule(rule); - m_jsonClient->sendCommand("Rules.EditRule", params, this, "editRuleReply"); + m_jsonClient->sendCommand("Rules.EditRule", params, this, "onEditRuleReply"); } @@ -126,6 +128,7 @@ void RuleManager::getRuleDetailsReply(const QVariantMap ¶ms) // qDebug() << "got rule details for rule" << ruleMap; parseEventDescriptors(ruleMap.value("eventDescriptors").toList(), rule); parseRuleActions(ruleMap.value("actions").toList(), rule); + parseStateEvaluator(ruleMap.value("stateEvaluator").toMap()); } void RuleManager::addRuleReply(const QVariantMap ¶ms) @@ -138,9 +141,10 @@ void RuleManager::removeRuleReply(const QVariantMap ¶ms) qDebug() << "Have remove rule reply" << params; } -void RuleManager::editRuleReply(const QVariantMap ¶ms) +void RuleManager::onEditRuleReply(const QVariantMap ¶ms) { - qDebug() << "Edit rule reply:" << params; + qDebug() << "Edit rule reply:" << params.value("params").toMap(); + emit editRuleReply(params.value("params").toMap().value("ruleError").toString()); } void RuleManager::parseEventDescriptors(const QVariantList &eventDescriptorList, Rule *rule) @@ -149,7 +153,12 @@ void RuleManager::parseEventDescriptors(const QVariantList &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()); + foreach (const QVariant ¶mDescriptorVariant, eventDescriptorVariant.toMap().value("paramDescriptors").toList()) { + ParamDescriptor *paramDescriptor = new ParamDescriptor(paramDescriptorVariant.toMap().value("paramTypeId").toString(), paramDescriptorVariant.toMap().value("value")); + QMetaEnum operatorEnum = QMetaEnum::fromType(); + paramDescriptor->setOperatorType((ParamDescriptor::ValueOperator)operatorEnum.keyToValue(paramDescriptorVariant.toMap().value("operator").toString().toLocal8Bit())); + eventDescriptor->paramDescriptors()->addParamDescriptor(paramDescriptor); + } rule->eventDescriptors()->addEventDescriptor(eventDescriptor); } } diff --git a/guh-control/rulemanager.h b/guh-control/rulemanager.h index fa2369b4..93159886 100644 --- a/guh-control/rulemanager.h +++ b/guh-control/rulemanager.h @@ -37,13 +37,16 @@ private slots: void getRuleDetailsReply(const QVariantMap ¶ms); void addRuleReply(const QVariantMap ¶ms); void removeRuleReply(const QVariantMap ¶ms); - void editRuleReply(const QVariantMap ¶ms); + void onEditRuleReply(const QVariantMap ¶ms); private: void parseEventDescriptors(const QVariantList &eventDescriptorList, Rule *rule); StateEvaluator* parseStateEvaluator(const QVariantMap &stateEvaluatorMap); void parseRuleActions(const QVariantList &ruleActions, Rule *rule); +signals: + void editRuleReply(const QString &ruleError); + private: JsonRpcClient *m_jsonClient; Rules* m_rules; diff --git a/guh-control/ui/MagicPage.qml b/guh-control/ui/MagicPage.qml index a0527c02..c813823b 100644 --- a/guh-control/ui/MagicPage.qml +++ b/guh-control/ui/MagicPage.qml @@ -20,11 +20,21 @@ Page { } } + Connections { + target: Engine.ruleManager + onEditRuleReply: { + if (ruleError == "RuleErrorNoError") { + pageStack.pop(); + } + } + } + ListView { anchors.fill: parent model: Engine.ruleManager.rules delegate: SwipeDelegate { + id: ruleDelegate width: parent.width text: model.name @@ -35,26 +45,18 @@ Page { }) } -// swipe.right: ColorIcon { -// name: "delete.svg" -// color: "red" -// } - - swipe.right: Label { - id: deleteLabel - text: qsTr("Delete") - color: "white" - verticalAlignment: Label.AlignVCenter - padding: 12 - height: parent.height - anchors.right: parent.right - - SwipeDelegate.onClicked: Engine.ruleManager.removeRule(model.id) - - background: Rectangle { - color: deleteLabel.SwipeDelegate.pressed ? Qt.darker("tomato", 1.1) : "tomato" - } + swipe.right: Item { + height: ruleDelegate.height + width: height + anchors.right: parent.right + ColorIcon { + anchors.fill: parent + anchors.margins: app.margins + name: "../images/delete.svg" + color: "red" } + SwipeDelegate.onClicked: Engine.ruleManager.removeRule(model.id) + } } } } diff --git a/guh-control/ui/MainPage.qml b/guh-control/ui/MainPage.qml index f0d1d6a3..f651d9eb 100644 --- a/guh-control/ui/MainPage.qml +++ b/guh-control/ui/MainPage.qml @@ -68,6 +68,32 @@ Page { height: parent.view.height shownInterfaces: ["gateway", "button", "notifications"] } + + ListView { + width: parent.view.width + height: parent.view.height + model: Engine.deviceManager.devices + delegate: ItemDelegate { + width: parent.width + contentItem: RowLayout { + spacing: app.margins + ColorIcon { + height: app.iconSize + width: height + name: app.interfaceToIcon(model.interfaces[0]) + color: app.guhAccent + } + + Label { + Layout.fillWidth: true + text: model.name + } + } + onClicked: { + pageStack.push(Qt.resolvedUrl("devicepages/GenericDevicePage.qml"), {device: Engine.deviceManager.devices.get(index)}) + } + } + } } PageIndicator { diff --git a/guh-control/ui/magic/EditRulePage.qml b/guh-control/ui/magic/EditRulePage.qml index c7ba0eb7..592d44ae 100644 --- a/guh-control/ui/magic/EditRulePage.qml +++ b/guh-control/ui/magic/EditRulePage.qml @@ -11,6 +11,8 @@ Page { signal accept(); + onAccept: busyOverlay.opacity = 1 + function addEventDescriptor() { var eventDescriptor = root.rule.eventDescriptors.createNewEventDescriptor(); var page = pageStack.push(Qt.resolvedUrl("SelectThingPage.qml")); @@ -26,7 +28,7 @@ Page { } function selectEventDescriptorData(eventDescriptor) { - var eventPage = pageStack.push(Qt.resolvedUrl("SelectEventPage.qml"), {text: "Select event", eventDescriptor: eventDescriptor}); + var eventPage = pageStack.push(Qt.resolvedUrl("SelectEventDescriptorPage.qml"), {text: "Select event", eventDescriptor: eventDescriptor}); eventPage.onBackPressed.connect(function() {pageStack.pop()}) eventPage.onDone.connect(function() { root.rule.eventDescriptors.addEventDescriptor(eventPage.eventDescriptor); @@ -64,107 +66,193 @@ Page { onBackPressed: pageStack.pop() HeaderButton { imageSource: "../images/tick.svg" + enabled: actionsRepeater.count > 0 && root.rule.name.length > 0 + opacity: enabled ? 1 : .3 onClicked: { root.accept() } } } - ColumnLayout { + Flickable { anchors.fill: parent - Label { - text: "Rule name" - } - TextField { - Layout.fillWidth: true - text: root.rule.name - onTextChanged: { - root.rule.name = text; + contentHeight: contentColumn.implicitHeight + app.margins - } - } - - RowLayout { - Layout.fillWidth: true - RadioButton { - id: whenButton - text: "When" - checked: true - } - RadioButton { - id: whileButton - text: "While" - } - } - - RowLayout { - Layout.fillWidth: true - visible: eventsRepeater.count == 0 - Label { + ColumnLayout { + id: contentColumn + anchors { left: parent.left; top: parent.top; right: parent.right; topMargin: app.margins } + ColumnLayout { Layout.fillWidth: true - text: "Add an event which should trigger the execution of the rule" - } - Button { - text: "+" - onClicked: root.addEventDescriptor(); - } - } + Layout.margins: app.margins + Label { + Layout.fillWidth: true + text: "Rule name" + } + TextField { + Layout.fillWidth: true + text: root.rule.name + onTextChanged: { + root.rule.name = text; - Repeater { - id: eventsRepeater - model: root.rule.eventDescriptors - delegate: ItemDelegate { - id: eventDelegate - property var device: Engine.deviceManager.devices.getDevice(root.rule.eventDescriptors.get(index).deviceId) - property var deviceClass: device ? Engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId) : null - property var eventType: deviceClass ? deviceClass.eventTypes.getEventType(root.rule.eventDescriptors.get(index).eventTypeId) : null - contentItem: ColumnLayout { - Label { - text: eventDelegate.device ? eventDelegate.device.name : "Unknown device" + root.rule.eventDescriptors.get(index).deviceId - Layout.fillWidth: true - } - Label { - text: eventDelegate.eventType ? eventDelegate.eventType.displayName : "Unknown event" + root.rule.eventDescriptors.get(index).eventTypeId } } } - } - Label { - text: "do the following:" + root.rule.ruleActions.count - } + ThinDivider {} - RowLayout { - Layout.fillWidth: true - visible: actionsRepeater.count == 0 Label { Layout.fillWidth: true - text: "Add action which should be executed when the rule is triggered" - wrapMode: Text.WordWrap + Layout.margins: app.margins + font.pixelSize: app.mediumFont + text: "Events triggering this rule" } + + Repeater { + id: eventsRepeater + model: root.rule.eventDescriptors + delegate: SwipeDelegate { + id: eventDelegate + Layout.fillWidth: true + property var device: Engine.deviceManager.devices.getDevice(root.rule.eventDescriptors.get(index).deviceId) + property var deviceClass: device ? Engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId) : null + property var eventType: deviceClass ? deviceClass.eventTypes.getEventType(root.rule.eventDescriptors.get(index).eventTypeId) : null + contentItem: ColumnLayout { + Label { + text: qsTr("%1 - %2").arg(eventDelegate.device.name).arg(eventDelegate.eventType.displayName) + Layout.fillWidth: true + elide: Text.ElideRight + } + RowLayout { + Layout.fillWidth: true + spacing: app.margins + Repeater { + model: root.rule.eventDescriptors.get(index).paramDescriptors + Label { + text: { + var ret = eventDelegate.eventType.paramTypes.getParamType(model.id).displayName + switch (model.operator) { + case ParamDescriptor.ValueOperatorEquals: + ret += " = "; + break; + case ParamDescriptor.ValueOperatorNotEquals: + ret += " != "; + break; + case ParamDescriptor.ValueOperatorGreater: + ret += " > "; + break; + case ParamDescriptor.ValueOperatorGreaterOrEqual: + ret += " >= "; + break; + case ParamDescriptor.ValueOperatorLess: + ret += " < "; + break; + case ParamDescriptor.ValueOperatorLessOrEqual: + ret += " <= "; + break; + default: + ret += " ? "; + } + + ret += model.value + return ret; + } + } + } + + } + + } + swipe.right: Item { + height: eventDelegate.height + width: height + anchors.right: parent.right + ColorIcon { + anchors.fill: parent + anchors.margins: app.margins + name: "../images/delete.svg" + color: "red" + } + SwipeDelegate.onClicked: root.rule.eventDescriptors.removeEventDescriptor(index) + } + } + } + Button { - text: "+" + Layout.fillWidth: true + Layout.margins: app.margins + text: eventsRepeater.count == 0 ? "Add an event..." : "Add another event..." + onClicked: root.addEventDescriptor(); + } + + ThinDivider {} + + Label { + text: "Actions to execute" + font.pixelSize: app.mediumFont + Layout.fillWidth: true + Layout.margins: app.margins + } + + Repeater { + id: actionsRepeater + model: root.rule.ruleActions + delegate: SwipeDelegate { + id: actionDelegate + Layout.fillWidth: true + property var device: Engine.deviceManager.devices.getDevice(root.rule.ruleActions.get(index).deviceId) + property var deviceClass: device ? Engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId) : null + property var actionType: deviceClass ? deviceClass.actionTypes.getActionType(root.rule.ruleActions.get(index).actionTypeId) : null + contentItem: ColumnLayout { + Label { + Layout.fillWidth: true + text: qsTr("%1 - %2").arg(actionDelegate.device.name).arg(actionDelegate.actionType.displayName) + } + + RowLayout { + Layout.fillWidth: true + spacing: app.margins + Repeater { + model: root.rule.ruleActions.get(index).ruleActionParams + Label { + text: actionType.paramTypes.getParamType(model.paramTypeId).displayName + " -> " + model.value + font.pixelSize: app.smallFont + } + } + } + } + swipe.right: Item { + height: actionDelegate.height + width: height + anchors.right: parent.right + ColorIcon { + anchors.fill: parent + anchors.margins: app.margins + name: "../images/delete.svg" + color: "red" + } + SwipeDelegate.onClicked: root.rule.ruleActions.removeRuleAction(index) + } + } + } + + Button { + Layout.fillWidth: true + Layout.margins: app.margins + text: actionsRepeater.count == 0 ? "Add an action..." : "Add another action..." onClicked: root.addRuleAction(); } } + } - Repeater { - id: actionsRepeater - model: root.rule.ruleActions - delegate: ItemDelegate { - id: actionDelegate - property var device: Engine.deviceManager.devices.getDevice(root.rule.ruleActions.get(index).deviceId) - property var deviceClass: device ? Engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId) : null - property var actionType: deviceClass ? deviceClass.actionTypes.getActionType(root.rule.ruleActions.get(index).actionTypeId) : null - contentItem: ColumnLayout { - Label { - text: actionDelegate.device.name - } - Label { - text: actionDelegate.actionType.displayName - } - } - } + Rectangle { + id: busyOverlay + anchors.fill: parent + color: "#55000000" + opacity: 0 + Behavior on opacity { NumberAnimation {duration: 200 } } + BusyIndicator { + anchors.centerIn: parent + running: parent.opacity > 0 } } } diff --git a/guh-control/ui/magic/SelectEventPage.qml b/guh-control/ui/magic/SelectEventDescriptorPage.qml similarity index 77% rename from guh-control/ui/magic/SelectEventPage.qml rename to guh-control/ui/magic/SelectEventDescriptorPage.qml index 76e2b8a6..9e2c0ce6 100644 --- a/guh-control/ui/magic/SelectEventPage.qml +++ b/guh-control/ui/magic/SelectEventDescriptorPage.qml @@ -62,10 +62,8 @@ Page { } } else { if (root.device) { - print("fdsfasdfdsafdas", deviceClass.eventTypes.count) for (var i = 0; i < deviceClass.eventTypes.count; i++) { - print("bla", deviceClass.eventTypes.get(i).name, deviceClass.eventTypes.get(i).displayName) - actualModel.append({text: deviceClass.eventTypes.get(i).displayName}) + actualModel.append({text: deviceClass.eventTypes.get(i).displayName, eventTypeId: deviceClass.eventTypes.get(i).id}) } } } @@ -73,6 +71,7 @@ Page { ListModel { id: actualModel + ListElement { text: ""; eventTypeId: "" } } ListView { @@ -97,7 +96,24 @@ Page { } } } else { - console.warn("FIXME: not implemented yet") + if (root.device) { + var eventType = root.deviceClass.eventTypes.getEventType(model.eventTypeId); + root.eventDescriptor.eventTypeId = model.eventTypeId; + if (eventType.paramTypes.count > 0) { + var paramsPage = pageStack.push(Qt.resolvedUrl("SelectEventDescriptorParamsPage.qml"), {eventDescriptor: root.eventDescriptor}) + paramsPage.onBackPressed.connect(function() {pageStack.pop()}); + paramsPage.onCompleted.connect(function() { + pageStack.pop(); + root.done(); + }) + } else { + root.done(); + } + + print("have type", eventType.id) + } else { + console.warn("FIXME: not implemented yet"); + } } } } diff --git a/guh-control/ui/magic/SelectEventDescriptorParamsPage.qml b/guh-control/ui/magic/SelectEventDescriptorParamsPage.qml new file mode 100644 index 00000000..0f7ee4e5 --- /dev/null +++ b/guh-control/ui/magic/SelectEventDescriptorParamsPage.qml @@ -0,0 +1,53 @@ +import QtQuick 2.8 +import QtQuick.Controls 2.1 +import QtQuick.Layouts 1.2 +import "../components" +import "../paramdescriptordelegates" +import Guh 1.0 + +Page { + id: root + // Needs to be set and filled in with deviceId and eventTypeId + property var eventDescriptor: null + + readonly property var device: eventDescriptor && eventDescriptor.deviceId ? Engine.deviceManager.devices.getDevice(eventDescriptor.deviceId) : null + readonly property var eventType: device ? Engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId).eventTypes.getEventType(eventDescriptor.eventTypeId) : null + + signal backPressed(); + signal completed(); + + header: GuhHeader { + text: "params" + onBackPressed: root.backPressed(); + } + + ColumnLayout { + anchors.fill: parent + Repeater { + id: delegateRepeater + model: root.eventType.paramTypes + delegate: ParamDescriptorDelegateBase { + Layout.fillWidth: true + paramType: root.eventType.paramTypes.get(index) + value: paramType.defaultValue + } + } + Item { + Layout.fillWidth: true + Layout.fillHeight: true + } + Button { + text: "OK" + Layout.fillWidth: true + Layout.margins: app.margins + onClicked: { + var params = []; + for (var i = 0; i < delegateRepeater.count; i++) { + var paramDelegate = delegateRepeater.itemAt(i); + root.eventDescriptor.paramDescriptors.setParamDescriptor(paramDelegate.paramType.id, paramDelegate.value, paramDelegate.operatorType) + } + root.completed() + } + } + } +} diff --git a/guh-control/ui/magic/SelectRuleActionPage.qml b/guh-control/ui/magic/SelectRuleActionPage.qml index 7a4b1882..82494d08 100644 --- a/guh-control/ui/magic/SelectRuleActionPage.qml +++ b/guh-control/ui/magic/SelectRuleActionPage.qml @@ -107,6 +107,7 @@ Page { root.ruleAction.actionTypeId = actionType.id; if (actionType.paramTypes.count > 0) { var paramsPage = pageStack.push(Qt.resolvedUrl("SelectRuleActionParamsPage.qml"), {ruleAction: root.ruleAction}) + paramsPage.onBackPressed.connect(function() { pageStack.pop(); }); paramsPage.onCompleted.connect(function() { pageStack.pop(); root.done(); diff --git a/guh-control/ui/paramdelegates/DoubleParamDelegate.qml b/guh-control/ui/paramdelegates/DoubleParamDelegate.qml new file mode 100644 index 00000000..43b745b0 --- /dev/null +++ b/guh-control/ui/paramdelegates/DoubleParamDelegate.qml @@ -0,0 +1,24 @@ +import QtQuick 2.8 +import QtQuick.Layouts 1.2 +import QtQuick.Controls 2.1 + +ParamDelegateBase { + id: root + + contentItem: RowLayout { + width: parent.width + + Label { + id: label + text: root.paramType.name + } + TextField { + id: textField + Layout.fillWidth: true + text: root.value ? root.value : root.paramType.defaultValue + onTextChanged: { + root.value = text; + } + } + } +} diff --git a/guh-control/ui/paramdelegates/ParamDelegate.qml b/guh-control/ui/paramdelegates/ParamDelegate.qml index e6277dc5..d4551ed4 100644 --- a/guh-control/ui/paramdelegates/ParamDelegate.qml +++ b/guh-control/ui/paramdelegates/ParamDelegate.qml @@ -19,6 +19,9 @@ Loader { case "Int": comp = "Int"; break; + case "Double": + comp = "Double"; + break; default: print("unhandled param type:", paramType.type) } diff --git a/guh-control/ui/paramdescriptordelegates/ParamDescriptorDelegateBase.qml b/guh-control/ui/paramdescriptordelegates/ParamDescriptorDelegateBase.qml new file mode 100644 index 00000000..f8cb1a17 --- /dev/null +++ b/guh-control/ui/paramdescriptordelegates/ParamDescriptorDelegateBase.qml @@ -0,0 +1,107 @@ +import QtQuick 2.4 +import QtQuick.Controls 2.1 +import QtQuick.Layouts 1.2 +import Guh 1.0 + +ItemDelegate { + id: root + + property var paramType: null + property var value: null + property int operatorType: ParamDescriptors.ValueOperatorEquals + + RowLayout { + anchors.fill: parent + anchors.margins: app.margins + spacing: app.margins + Label { + text: paramType.displayName + } + ComboBox { + model: { + switch (paramType.type) { + case "Bool": + case "String": + return ["is", "is not"]; + case "Int": + case "Double": + return ["is", "is not", "is greater", "is smaller", "is greater or equal", "is smaller or equal"] + } + } + onCurrentTextChanged: { + switch (currentText) { + case "is": + root.operatorType = ParamDescriptor.ValueOperatorEquals; + break; + case "is not": + root.operatorType = ParamDescriptor.ValueOperatorNotEquals; + break; + case "is greater": + root.operatorType = ParamDescriptor.ValueOperatorGreater; + break; + case "is smaller": + root.operatorType = ParamDescriptor.ValueOperatorLess; + break; + case "is greater of equal": + root.operatorType = ParamDescriptor.ValueOperatorGreaterOrEqual; + break; + case "is smaller or equal": + root.operatorType = ParamDescriptor.ValueOperatorLessOrEqual; + break; + } + } + } + + Loader { + id: placeHolder + Layout.fillWidth: true + sourceComponent: { + print("Datatye is:", paramType.type, paramType.minValue, paramType.maxValue) + switch (paramType.type) { + case "Bool": + return boolComponent; + case "Int": + case "Double": + if (paramType.minValue !== undefined && paramType.maxValue !== undefined) { + return sliderComponent; + } + return textFieldComponent; + } + console.warn("ParamDescriptorDelegate: Type delegate not implemented", paramType.type) + return null; + } + } + + } + + Component { + id: textFieldComponent + TextField { + text: "" + } + } + + Component { + id: sliderComponent + Slider { + from: paramType.minValue + to: paramType.maxValue + onMoved: { + root.value = value; + } + } + } + + Component { + id: boolComponent + ComboBox { + model: ListModel { + ListElement { modelData: "true"; value: true } + ListElement { modelData: "false"; value: false } + } + onCurrentIndexChanged: { + root.value = model.get(currentIndex).value + } + } + } +} diff --git a/libguh-common/types/eventdescriptor.cpp b/libguh-common/types/eventdescriptor.cpp index a1820972..23ee0443 100644 --- a/libguh-common/types/eventdescriptor.cpp +++ b/libguh-common/types/eventdescriptor.cpp @@ -58,3 +58,16 @@ ParamDescriptors *EventDescriptor::paramDescriptors() const { return m_paramDescriptors; } + +EventDescriptor *EventDescriptor::clone() const +{ + EventDescriptor *ret = new EventDescriptor(); + ret->setDeviceId(this->deviceId()); + ret->setEventTypeId(this->eventTypeId()); + ret->setInterfaceName(this->interfaceName()); + ret->setInterfaceEvent(this->interfaceEvent()); + for (int i = 0; i < this->paramDescriptors()->rowCount(); i++) { + ret->paramDescriptors()->addParamDescriptor(this->paramDescriptors()->get(i)->clone()); + } + return ret; +} diff --git a/libguh-common/types/eventdescriptor.h b/libguh-common/types/eventdescriptor.h index e9dc2c34..f07440d2 100644 --- a/libguh-common/types/eventdescriptor.h +++ b/libguh-common/types/eventdescriptor.h @@ -34,6 +34,8 @@ public: ParamDescriptors* paramDescriptors() const; + EventDescriptor* clone() const; + signals: void deviceIdChanged(); void eventTypeIdChanged(); diff --git a/libguh-common/types/eventdescriptors.cpp b/libguh-common/types/eventdescriptors.cpp index 69b394f1..28b34cf5 100644 --- a/libguh-common/types/eventdescriptors.cpp +++ b/libguh-common/types/eventdescriptors.cpp @@ -34,7 +34,10 @@ QHash EventDescriptors::roleNames() const EventDescriptor *EventDescriptors::get(int index) const { - return m_list.at(index); + if (index >= 0 && index < m_list.count()) { + return m_list.at(index); + } + return nullptr; } EventDescriptor *EventDescriptors::createNewEventDescriptor() @@ -50,3 +53,11 @@ void EventDescriptors::addEventDescriptor(EventDescriptor *eventDescriptor) endInsertRows(); emit countChanged(); } + +void EventDescriptors::removeEventDescriptor(int index) +{ + beginRemoveRows(QModelIndex(), index, index); + m_list.takeAt(index)->deleteLater(); + endRemoveRows(); + emit countChanged(); +} diff --git a/libguh-common/types/eventdescriptors.h b/libguh-common/types/eventdescriptors.h index 7da92170..87b661d1 100644 --- a/libguh-common/types/eventdescriptors.h +++ b/libguh-common/types/eventdescriptors.h @@ -24,6 +24,7 @@ public: Q_INVOKABLE EventDescriptor* createNewEventDescriptor(); Q_INVOKABLE void addEventDescriptor(EventDescriptor *eventDescriptor); + Q_INVOKABLE void removeEventDescriptor(int index); signals: void countChanged(); diff --git a/libguh-common/types/eventtype.cpp b/libguh-common/types/eventtype.cpp index 8d42633d..4cc70826 100644 --- a/libguh-common/types/eventtype.cpp +++ b/libguh-common/types/eventtype.cpp @@ -27,12 +27,12 @@ EventType::EventType(QObject *parent) : { } -QUuid EventType::id() const +QString EventType::id() const { return m_id; } -void EventType::setId(const QUuid &id) +void EventType::setId(const QString &id) { m_id = id; } diff --git a/libguh-common/types/eventtype.h b/libguh-common/types/eventtype.h index 2f148188..a5ed6dbc 100644 --- a/libguh-common/types/eventtype.h +++ b/libguh-common/types/eventtype.h @@ -31,7 +31,7 @@ class EventType : public QObject { Q_OBJECT - Q_PROPERTY(QUuid id READ id CONSTANT) + Q_PROPERTY(QString id READ id CONSTANT) Q_PROPERTY(QString name READ name CONSTANT) Q_PROPERTY(QString displayName READ displayName CONSTANT) Q_PROPERTY(int index READ index CONSTANT) @@ -40,8 +40,8 @@ class EventType : public QObject public: explicit EventType(QObject *parent = 0); - QUuid id() const; - void setId(const QUuid &id); + QString id() const; + void setId(const QString &id); QString name() const; void setName(const QString &name); @@ -56,7 +56,7 @@ public: void setParamTypes(ParamTypes *paramTypes); private: - QUuid m_id; + QString m_id; QString m_name; QString m_displayName; int m_index; diff --git a/libguh-common/types/eventtypes.cpp b/libguh-common/types/eventtypes.cpp index b3801df7..9f1245ec 100644 --- a/libguh-common/types/eventtypes.cpp +++ b/libguh-common/types/eventtypes.cpp @@ -39,7 +39,7 @@ EventType *EventTypes::get(int index) const return m_eventTypes.at(index); } -EventType *EventTypes::getEventType(const QUuid &eventTypeId) const +EventType *EventTypes::getEventType(const QString &eventTypeId) const { foreach (EventType *eventType, m_eventTypes) { if (eventType->id() == eventTypeId) { @@ -64,7 +64,7 @@ QVariant EventTypes::data(const QModelIndex &index, int role) const if (role == NameRole) { return eventType->name(); } else if (role == IdRole) { - return eventType->id().toString(); + return eventType->id(); } return QVariant(); } diff --git a/libguh-common/types/eventtypes.h b/libguh-common/types/eventtypes.h index 66854cdf..08f97718 100644 --- a/libguh-common/types/eventtypes.h +++ b/libguh-common/types/eventtypes.h @@ -44,7 +44,7 @@ public: QList eventTypes(); Q_INVOKABLE EventType *get(int index) const; - Q_INVOKABLE EventType *getEventType(const QUuid &eventTypeId) const; + Q_INVOKABLE EventType *getEventType(const QString &eventTypeId) const; int rowCount(const QModelIndex & parent = QModelIndex()) const; QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const; diff --git a/libguh-common/types/paramdescriptor.cpp b/libguh-common/types/paramdescriptor.cpp index b4c03166..31c846c2 100644 --- a/libguh-common/types/paramdescriptor.cpp +++ b/libguh-common/types/paramdescriptor.cpp @@ -17,3 +17,10 @@ void ParamDescriptor::setOperatorType(ParamDescriptor::ValueOperator operatorTyp emit operatorTypeChanged(); } } + +ParamDescriptor *ParamDescriptor::clone() const +{ + ParamDescriptor *ret = new ParamDescriptor(this->id(), this->value()); + ret->setOperatorType(this->operatorType()); + return ret; +} diff --git a/libguh-common/types/paramdescriptor.h b/libguh-common/types/paramdescriptor.h index f65f3ba6..1521f227 100644 --- a/libguh-common/types/paramdescriptor.h +++ b/libguh-common/types/paramdescriptor.h @@ -23,6 +23,7 @@ public: ValueOperator operatorType() const; void setOperatorType(ValueOperator operatorType); + ParamDescriptor* clone() const; signals: void operatorTypeChanged(); diff --git a/libguh-common/types/paramdescriptors.cpp b/libguh-common/types/paramdescriptors.cpp index 5c60cf89..9475e269 100644 --- a/libguh-common/types/paramdescriptors.cpp +++ b/libguh-common/types/paramdescriptors.cpp @@ -14,9 +14,26 @@ int ParamDescriptors::rowCount(const QModelIndex &parent) const QVariant ParamDescriptors::data(const QModelIndex &index, int role) const { + switch (role) { + case RoleId: + return m_list.at(index.row())->id(); + case RoleValue: + return m_list.at(index.row())->value(); + case RoleOperator: + return m_list.at(index.row())->operatorType(); + } return QVariant(); } +QHash ParamDescriptors::roleNames() const +{ + QHash roles; + roles.insert(RoleId, "id"); + roles.insert(RoleValue, "value"); + roles.insert(RoleOperator, "operator"); + return roles; +} + ParamDescriptor *ParamDescriptors::get(int index) const { return m_list.at(index); diff --git a/libguh-common/types/paramdescriptors.h b/libguh-common/types/paramdescriptors.h index ec063ea5..bfc9c68b 100644 --- a/libguh-common/types/paramdescriptors.h +++ b/libguh-common/types/paramdescriptors.h @@ -20,10 +20,18 @@ public: }; Q_ENUM(ValueOperator) + enum Roles { + RoleId, + RoleValue, + RoleOperator + }; + Q_ENUM(Roles) + explicit ParamDescriptors(QObject *parent = nullptr); int rowCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role) const override; + QHash roleNames() const override; ParamDescriptor* get(int index) const; diff --git a/libguh-common/types/rule.cpp b/libguh-common/types/rule.cpp index 7a3e8243..bb9b828f 100644 --- a/libguh-common/types/rule.cpp +++ b/libguh-common/types/rule.cpp @@ -1,8 +1,11 @@ #include "rule.h" +#include "eventdescriptor.h" #include "eventdescriptors.h" -#include "ruleactions.h" #include "stateevaluator.h" +#include "stateevaluators.h" +#include "ruleaction.h" +#include "ruleactions.h" Rule::Rule(const QUuid &id, QObject *parent) : QObject(parent), @@ -59,3 +62,22 @@ RuleActions *Rule::ruleActions() const { return m_ruleActions; } + +Rule *Rule::clone() const +{ + Rule *ret = new Rule(this->id()); + ret->setName(this->name()); + ret->setEnabled(this->enabled()); + for (int i = 0; i < this->eventDescriptors()->rowCount(); i++) { + ret->eventDescriptors()->addEventDescriptor(this->eventDescriptors()->get(i)->clone()); + } +// ret->stateEvaluator()->setStateDescriptor(this->stateEvaluator()->stateDescriptor()->clone()); +// ret->stateEvaluator()->setStateOperator(this->stateEvaluator()->stateOperator()); +// for (int i = 0; i < this->stateEvaluator()->childEvaluators()->rowCount(); i++) { +// ret->stateEvaluator()->childEvaluators()-> +// } + for (int i = 0; i < this->ruleActions()->rowCount(); i++) { + ret->ruleActions()->addRuleAction(this->ruleActions()->get(i)->clone()); + } + return ret; +} diff --git a/libguh-common/types/rule.h b/libguh-common/types/rule.h index 86d1034d..9bc84c4e 100644 --- a/libguh-common/types/rule.h +++ b/libguh-common/types/rule.h @@ -32,6 +32,8 @@ public: StateEvaluator *stateEvaluator() const; RuleActions* ruleActions() const; + Rule *clone() const; + signals: void nameChanged(); void enabledChanged(); diff --git a/libguh-common/types/ruleaction.cpp b/libguh-common/types/ruleaction.cpp index 42167135..97d9fbbe 100644 --- a/libguh-common/types/ruleaction.cpp +++ b/libguh-common/types/ruleaction.cpp @@ -1,5 +1,6 @@ #include "ruleaction.h" +#include "ruleactionparam.h" #include "ruleactionparams.h" RuleAction::RuleAction(QObject *parent) : QObject(parent) @@ -37,3 +38,14 @@ RuleActionParams *RuleAction::ruleActionParams() const { return m_ruleActionParams; } + +RuleAction *RuleAction::clone() const +{ + RuleAction *ret = new RuleAction(); + ret->setActionTypeId(actionTypeId()); + ret->setDeviceId(deviceId()); + for (int i = 0; i < ruleActionParams()->rowCount(); i++) { + ret->ruleActionParams()->addRuleActionParam(ruleActionParams()->get(i)->clone()); + } + return ret; +} diff --git a/libguh-common/types/ruleaction.h b/libguh-common/types/ruleaction.h index 31e44471..d2717652 100644 --- a/libguh-common/types/ruleaction.h +++ b/libguh-common/types/ruleaction.h @@ -24,6 +24,8 @@ public: RuleActionParams* ruleActionParams() const; + RuleAction *clone() const; + signals: void deviceIdChanged(); void actionTypeIdChanged(); diff --git a/libguh-common/types/ruleactionparam.cpp b/libguh-common/types/ruleactionparam.cpp index a0b97d89..85ad3db3 100644 --- a/libguh-common/types/ruleactionparam.cpp +++ b/libguh-common/types/ruleactionparam.cpp @@ -28,5 +28,13 @@ void RuleActionParam::setValue(const QVariant &value) if (m_value != value) { m_value = value; emit valueChanged(); - } + } +} + +RuleActionParam *RuleActionParam::clone() const +{ + RuleActionParam *ret = new RuleActionParam(); + ret->setParamTypeId(paramTypeId()); + ret->setValue(value()); + return ret; } diff --git a/libguh-common/types/ruleactionparam.h b/libguh-common/types/ruleactionparam.h index 19c9e36d..be9a9a18 100644 --- a/libguh-common/types/ruleactionparam.h +++ b/libguh-common/types/ruleactionparam.h @@ -19,6 +19,7 @@ public: QVariant value() const; void setValue(const QVariant &value); + RuleActionParam* clone() const; signals: void paramTypeIdChanged(); void valueChanged(); diff --git a/libguh-common/types/ruleactionparams.cpp b/libguh-common/types/ruleactionparams.cpp index 8fba61ff..d557b1ad 100644 --- a/libguh-common/types/ruleactionparams.cpp +++ b/libguh-common/types/ruleactionparams.cpp @@ -15,9 +15,23 @@ int RuleActionParams::rowCount(const QModelIndex &parent) const QVariant RuleActionParams::data(const QModelIndex &index, int role) const { + switch (role) { + case RoleParamTypeId: + return m_list.at(index.row())->paramTypeId(); + case RoleValue: + return m_list.at(index.row())->value(); + } return QVariant(); } +QHash RuleActionParams::roleNames() const +{ + QHash roles; + roles.insert(RoleParamTypeId, "paramTypeId"); + roles.insert(RoleValue, "value"); + return roles; +} + void RuleActionParams::addRuleActionParam(RuleActionParam *ruleActionParam) { ruleActionParam->setParent(this); diff --git a/libguh-common/types/ruleactionparams.h b/libguh-common/types/ruleactionparams.h index 79fb5db4..fea79989 100644 --- a/libguh-common/types/ruleactionparams.h +++ b/libguh-common/types/ruleactionparams.h @@ -10,10 +10,17 @@ class RuleActionParams : public QAbstractListModel Q_OBJECT Q_PROPERTY(int count READ rowCount NOTIFY countChanged) public: + enum Roles { + RoleParamTypeId, + RoleValue + }; + Q_ENUM(Roles) + explicit RuleActionParams(QObject *parent = nullptr); int rowCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role) const override; + QHash roleNames() const override; void addRuleActionParam(RuleActionParam* ruleActionParam); diff --git a/libguh-common/types/ruleactions.cpp b/libguh-common/types/ruleactions.cpp index 54c18e84..845c03ee 100644 --- a/libguh-common/types/ruleactions.cpp +++ b/libguh-common/types/ruleactions.cpp @@ -8,6 +8,7 @@ RuleActions::RuleActions(QObject *parent) : QAbstractListModel(parent) int RuleActions::rowCount(const QModelIndex &parent) const { + Q_UNUSED(parent) return m_list.count(); } @@ -22,11 +23,23 @@ void RuleActions::addRuleAction(RuleAction *ruleAction) beginInsertRows(QModelIndex(), m_list.count(), m_list.count()); m_list.append(ruleAction); endInsertRows(); + emit countChanged(); +} + +void RuleActions::removeRuleAction(int index) +{ + beginRemoveRows(QModelIndex(), index, index); + m_list.takeAt(index)->deleteLater(); + endRemoveRows(); + emit countChanged(); } RuleAction *RuleActions::get(int index) const { - return m_list.at(index); + if (index >= 0 && index < m_list.count()) { + return m_list.at(index); + } + return nullptr; } RuleAction *RuleActions::createNewRuleAction() const diff --git a/libguh-common/types/ruleactions.h b/libguh-common/types/ruleactions.h index d6d7dda1..c052d3f2 100644 --- a/libguh-common/types/ruleactions.h +++ b/libguh-common/types/ruleactions.h @@ -16,6 +16,7 @@ public: QVariant data(const QModelIndex &index, int role) const override; Q_INVOKABLE void addRuleAction(RuleAction* ruleAction); + Q_INVOKABLE void removeRuleAction(int index); Q_INVOKABLE RuleAction* get(int index) const; Q_INVOKABLE RuleAction* createNewRuleAction() const; diff --git a/libguh-common/types/statedescriptor.cpp b/libguh-common/types/statedescriptor.cpp index 04557459..7e60ab3f 100644 --- a/libguh-common/types/statedescriptor.cpp +++ b/libguh-common/types/statedescriptor.cpp @@ -29,3 +29,9 @@ QVariant StateDescriptor::value() const { return m_value; } + +StateDescriptor *StateDescriptor::clone() const +{ + StateDescriptor *ret = new StateDescriptor(deviceId(), valueOperator(), stateTypeId(), value()); + return ret; +} diff --git a/libguh-common/types/statedescriptor.h b/libguh-common/types/statedescriptor.h index 7cbb0963..7527b686 100644 --- a/libguh-common/types/statedescriptor.h +++ b/libguh-common/types/statedescriptor.h @@ -31,6 +31,7 @@ public: QUuid stateTypeId() const; QVariant value() const; + StateDescriptor* clone() const; private: QUuid m_deviceId; ValueOperator m_operator = ValueOperatorEquals; diff --git a/libguh-common/types/stateevaluators.cpp b/libguh-common/types/stateevaluators.cpp index d6608cab..9cf83052 100644 --- a/libguh-common/types/stateevaluators.cpp +++ b/libguh-common/types/stateevaluators.cpp @@ -7,6 +7,7 @@ StateEvaluators::StateEvaluators(QObject *parent) : QAbstractListModel(parent) int StateEvaluators::rowCount(const QModelIndex &parent) const { + Q_UNUSED(parent) return m_list.count(); }