more work on interface based rules

pull/1/head
Michael Zanetti 2018-02-26 00:51:23 +01:00
parent b910166d91
commit af2e2fcda8
11 changed files with 116 additions and 88 deletions

View File

@ -23,7 +23,6 @@ GridView {
Pane {
anchors.fill: parent
anchors.margins: app.margins
// color: "#22000000"
Material.elevation: 1
Column {
anchors.centerIn: parent

View File

@ -50,14 +50,13 @@ Page {
ColumnLayout {
anchors.fill: parent
anchors.margins: app.margins
SwipeView {
id: swipeView
Layout.fillWidth: true
Layout.fillHeight: true
currentIndex: pageIndicator.currentIndex
// clip: true
clip: true
DevicesPage {
width: parent.view.width

View File

@ -142,10 +142,9 @@ Page {
Layout.fillWidth: true
spacing: app.margins
Repeater {
model: root.rule.eventDescriptors.get(index).paramDescriptors
model: eventDelegate.eventDescriptor.paramDescriptors
Label {
text: {
print("***", eventDelegate.iface, eventDelegate.eventDescriptor.interfaceName, Interfaces.findByName(eventDelegate.eventDescriptor.interfaceName), eventDescriptor.interfaceName ? Interfaces.findByName(eventDescriptor.interfaceName) : null)
var ret = eventDelegate.eventType.paramTypes.getParamType(model.id).displayName
switch (model.operator) {
case ParamDescriptor.ValueOperatorEquals:
@ -216,22 +215,25 @@ Page {
delegate: SwipeDelegate {
id: actionDelegate
Layout.fillWidth: true
property var device: Engine.deviceManager.devices.getDevice(root.rule.ruleActions.get(index).deviceId)
property var ruleAction: root.rule.ruleActions.get(index)
property var device: ruleAction.deviceId ? Engine.deviceManager.devices.getDevice(ruleAction.deviceId) : null
property var iface: ruleAction.interfaceName ? Interfaces.findByName(ruleAction.interfaceName) : null
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
property var actionType: deviceClass ? deviceClass.actionTypes.getActionType(ruleAction.actionTypeId)
: iface ? iface.actionTypes.findByName(ruleAction.interfaceAction) : null
contentItem: ColumnLayout {
Label {
Layout.fillWidth: true
text: qsTr("%1 - %2").arg(actionDelegate.device.name).arg(actionDelegate.actionType.displayName)
text: qsTr("%1 - %2").arg(actionDelegate.device ? actionDelegate.device.name : actionDelegate.iface.displayName).arg(actionDelegate.actionType.displayName)
}
RowLayout {
Layout.fillWidth: true
spacing: app.margins
Repeater {
model: root.rule.ruleActions.get(index).ruleActionParams
model: actionDelegate.ruleAction.ruleActionParams
Label {
text: actionType.paramTypes.getParamType(model.paramTypeId).displayName + " -> " + model.value
text: actionDelegate.actionType.paramTypes.getParamType(model.paramTypeId).displayName + " -> " + model.value
font.pixelSize: app.smallFont
}
}

View File

@ -43,9 +43,7 @@ Page {
function buildInterface() {
if (header.interfacesMode) {
if (root.device) {
print("device supports interfaces", deviceClass.interfaces)
for (var i = 0; i < Interfaces.count; i++) {
print("event is for interface", Interfaces.get(i).name)
if (deviceClass.interfaces.indexOf(Interfaces.get(i).name) >= 0) {
actualModel.append(Interfaces.get(i))
}

View File

@ -23,71 +23,55 @@ Page {
id: header
onBackPressed: root.backPressed();
property bool interfacesMode: false
property bool interfacesMode: root.ruleAction.interfaceName !== ""
onInterfacesModeChanged: root.buildInterface()
HeaderButton {
imageSource: header.interfacesMode ? "../images/view-expand.svg" : "../images/view-collapse.svg"
visible: root.ruleAction.interfaceName === ""
onClicked: header.interfacesMode = !header.interfacesMode
}
}
ListModel {
id: actionTemplateModel
ListElement { interfaceName: "light"; text: "Switch light"; identifier: "switchLight"}
ListElement { interfaceName: "dimmablelight"; text: "Dim light"; identifier: "dimLight"}
ListElement { interfaceName: "colorlight"; text: "Set light color"; identifier: "colorLight" }
ListElement { interfaceName: "mediacontroller"; text: "Pause playback"; identifier: "pausePlayback" }
ListElement { interfaceName: "mediacontroller"; text: "Resume playback"; identifier: "resumePlayback" }
ListElement { interfaceName: "extendedvolumecontroller"; text: "Set volume"; identifier: "setVolume" }
ListElement { interfaceName: "extendedvolumecontroller"; text: "Mute"; identifier: "mute" }
ListElement { interfaceName: "extendedvolumecontroller"; text: "Unmute"; identifier: "unmute" }
ListElement { interfaceName: "notifications"; text: "Notify me"; identifier: "notify" }
}
// ListModel {
// id: actionTemplateModel
// ListElement { interfaceName: "light"; text: "Switch light"; identifier: "switchLight"}
// ListElement { interfaceName: "dimmablelight"; text: "Dim light"; identifier: "dimLight"}
// ListElement { interfaceName: "colorlight"; text: "Set light color"; identifier: "colorLight" }
// ListElement { interfaceName: "mediacontroller"; text: "Pause playback"; identifier: "pausePlayback" }
// ListElement { interfaceName: "mediacontroller"; text: "Resume playback"; identifier: "resumePlayback" }
// ListElement { interfaceName: "extendedvolumecontroller"; text: "Set volume"; identifier: "setVolume" }
// ListElement { interfaceName: "extendedvolumecontroller"; text: "Mute"; identifier: "mute" }
// ListElement { interfaceName: "extendedvolumecontroller"; text: "Unmute"; identifier: "unmute" }
// ListElement { interfaceName: "notifications"; text: "Notify me"; identifier: "notify" }
// }
function buildInterface() {
actualModel.clear()
if (header.interfacesMode) {
if (root.device) {
print("device supports interfaces", deviceClass.interfaces)
for (var i = 0; i < actionTemplateModel.count; i++) {
print("action is for interface", actionTemplateModel.get(i).interfaceName)
for (var i = 0; i < Interfaces.count; i++) {
if (deviceClass.interfaces.indexOf(actionTemplateModel.get(i).interfaceName) >= 0) {
actualModel.append(actionTemplateModel.get(i))
}
}
} else if (root.ruleAction.interfaceName !== "") {
for (var i = 0; i < actionTemplateModel.count; i++) {
if (actionTemplateModel.get(i).interfaceName === root.ruleAction.interfaceName) {
actualModel.append(actionTemplateModel.get(i))
}
}
listView.model = Interfaces.findByName(root.ruleAction.interfaceName).actionTypes
} else {
console.warn("You need to set device or interfaceName");
}
} else {
if (root.device) {
print("fdsfasdfdsafdas", deviceClass.actionTypes.count)
for (var i = 0; i < deviceClass.actionTypes.count; i++) {
print("bla", deviceClass.actionTypes.get(i).name, deviceClass.actionTypes.get(i).displayName, deviceClass.actionTypes.get(i).id)
actualModel.append({text: deviceClass.actionTypes.get(i).displayName, actionTypeId: deviceClass.actionTypes.get(i).id})
}
listView.model = deviceClass.actionTypes
}
}
}
ListModel {
id: actualModel
ListElement { text: ""; actionTypeId: "" }
}
ListView {
id: listView
anchors.fill: parent
model: actualModel
delegate: ItemDelegate {
text: model.text
text: model.displayName
width: parent.width
onClicked: {
if (header.interfacesMode) {
@ -100,10 +84,24 @@ Page {
default:
console.warn("FIXME: Unhandled interface action");
}
} else if (root.ruleAction.interfaceName != "") {
root.ruleAction.interfaceAction = model.name;
if (listView.model.get(index).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();
})
} else {
root.done();
}
} else {
console.warn("Neither deviceId not interfaceName set. Cannot continue...");
}
} else {
if (root.device) {
var actionType = root.deviceClass.actionTypes.getActionType(model.actionTypeId);
var actionType = root.deviceClass.actionTypes.getActionType(model.id);
console.log("ActionType", actionType.id, "selected. Has", actionType.paramTypes.count, "params");
root.ruleAction.actionTypeId = actionType.id;
if (actionType.paramTypes.count > 0) {

View File

@ -11,7 +11,9 @@ Page {
property var ruleAction
readonly property var device: ruleAction && ruleAction.deviceId ? Engine.deviceManager.devices.getDevice(ruleAction.deviceId) : null
readonly property var actionType: device ? Engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId).actionTypes.getActionType(ruleAction.actionTypeId) : null
readonly property var iface: ruleAction && ruleAction.interfaceName ? Interfaces.findByName(ruleAction.interfaceName) : null
readonly property var actionType: device ? Engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId).actionTypes.getActionType(ruleAction.actionTypeId)
: iface ? iface.actionTypes.findByName(ruleAction.interfaceAction) : null
signal backPressed();
signal completed();

View File

@ -32,17 +32,18 @@ ItemDelegate {
return stringComponent;
}
switch (root.paramType.type) {
case "Bool":
switch (root.paramType.type.toLowerCase()) {
case "bool":
return boolComponent;
case "Int":
case "int":
return stringComponent;
case "String":
case "string":
case "qstring":
if (root.paramType.allowedValues.length > 0) {
return comboBoxComponent;
}
return textFieldComponent;
case "Color":
case "color":
return colorPreviewComponent;
}
console.warn("Param Delegate: Fallback to stringComponent", root.paramType.name, root.paramType.type)
@ -53,14 +54,14 @@ ItemDelegate {
Loader {
Layout.fillWidth: true
sourceComponent: {
switch (root.paramType.type) {
case "Int":
case "Double":
switch (root.paramType.type.toLowerCase()) {
case "int":
case "double":
if (root.paramType.minValue != undefined && root.paramType.maxValue != undefined) {
return sliderComponent
}
break;
case "Color":
case "color":
return colorPickerComponent
}
return null;
@ -72,8 +73,8 @@ ItemDelegate {
id: stringComponent
Label {
text: {
switch (root.paramType.type) {
case "Int":
switch (root.paramType.type.toLowerCase()) {
case "int":
return Math.round(root.param.value);
}
return root.param.value;

View File

@ -23,6 +23,7 @@ ItemDelegate {
switch (paramType.type.toLowerCase()) {
case "bool":
case "string":
case "qstring":
return ["is", "is not"];
case "int":
case "double":
@ -71,6 +72,7 @@ ItemDelegate {
}
return textFieldComponent;
case "string":
case "qstring":
if (paramType.allowedValues.length > 0) {
return comboBoxComponent
}
@ -85,9 +87,9 @@ ItemDelegate {
Loader {
Layout.fillWidth: true
sourceComponent: {
switch (paramType.type) {
case "Int":
case "Double":
switch (paramType.type.toLowerCase()) {
case "int":
case "double":
if (paramType.minValue !== undefined && paramType.maxValue !== undefined) {
return sliderComponent
}
@ -102,8 +104,8 @@ ItemDelegate {
id: labelComponent
Label {
text: {
switch (root.paramType.type) {
case "Int":
switch (root.paramType.type.toLowerCase()) {
case "int":
return Math.round(root.value)
}
return root.value

View File

@ -60,10 +60,13 @@ QVariant ActionTypes::data(const QModelIndex &index, int role) const
return QVariant();
ActionType *actionType = m_actionTypes.at(index.row());
if (role == NameRole) {
return actionType->name();
} else if (role == IdRole) {
switch (role) {
case RoleId:
return actionType->id();
case RoleName:
return actionType->name();
case RoleDisplayName:
return actionType->displayName();
}
return QVariant();
}
@ -98,7 +101,8 @@ void ActionTypes::clearModel()
QHash<int, QByteArray> ActionTypes::roleNames() const
{
QHash<int, QByteArray> roles;
roles[NameRole] = "name";
roles[IdRole] = "id";
roles.insert(RoleId, "id");
roles.insert(RoleName, "name");
roles.insert(RoleDisplayName, "displayName");
return roles;
}

View File

@ -33,9 +33,10 @@ class ActionTypes : public QAbstractListModel
Q_OBJECT
Q_PROPERTY(int count READ rowCount NOTIFY countChanged)
public:
enum ActionTypeRole {
NameRole = Qt::DisplayRole,
IdRole
enum Roles {
RoleId,
RoleName,
RoleDisplayName
};
ActionTypes(QObject *parent = 0);

View File

@ -3,41 +3,63 @@
#include "eventtypes.h"
#include "eventtype.h"
#include "actiontypes.h"
#include "actiontype.h"
Interfaces::Interfaces(QObject *parent) : QAbstractListModel(parent)
{
Interface* iface = nullptr;
EventType* ev = nullptr;
EventType* et = nullptr;
ActionType* at = nullptr;
ParamType* pt = nullptr;
ParamTypes *pts = nullptr;
iface = new Interface("battery", "Battery powered devices");
ev = new EventType();
pts = new ParamTypes(ev);
ev->setParamTypes(pts);
et = new EventType();
pts = new ParamTypes(et);
et->setParamTypes(pts);
ev->setName("batteryLevel");
ev->setDisplayName("Battery level changed");
et->setName("batteryLevel");
et->setDisplayName("Battery level changed");
pt = new ParamType("batteryLevel", QVariant::Int, 50);
pt->setDisplayName("Battery Level");
qDebug() << "added param" << pt->type();
pt->setMinValue(0);
pt->setMaxValue(100);
ev->paramTypes()->addParamType(pt);
iface->eventTypes()->addEventType(ev);
et->paramTypes()->addParamType(pt);
iface->eventTypes()->addEventType(et);
ev = new EventType();
pts = new ParamTypes(ev);
ev->setParamTypes(pts);
ev->setName("batteryCritical");
ev->setDisplayName("Battery level critical");
et = new EventType();
pts = new ParamTypes(et);
et->setParamTypes(pts);
et->setName("batteryCritical");
et->setDisplayName("Battery level critical");
pt = new ParamType("batteryCritical", QVariant::Bool, true);
pt->setDisplayName("Battery critical");
ev->paramTypes()->addParamType(pt);
iface->eventTypes()->addEventType(ev);
et->paramTypes()->addParamType(pt);
iface->eventTypes()->addEventType(et);
m_list.append(iface);
iface = new Interface("notification", "Notification services");
at = new ActionType();
pts = new ParamTypes(at);
at->setParamTypes(pts);
at->setName("notify");
at->setDisplayName("Send notification");
pt = new ParamType("title", QVariant::String);
pt->setDisplayName("Title");
at->paramTypes()->addParamType(pt);
pt = new ParamType("body", QVariant::String);
pt->setDisplayName("Message body");
at->paramTypes()->addParamType(pt);
iface->actionTypes()->addActionType(at);
m_list.append(iface);
}
int Interfaces::rowCount(const QModelIndex &parent) const