Merge PR #177: State based ruleactionparams

This commit is contained in:
Jenkins 2019-04-16 01:33:09 +02:00
commit 40c436bbfe
14 changed files with 285 additions and 60 deletions

View File

@ -372,7 +372,11 @@ void NymeaConnection::onDisconnected()
// Try to reconnect, only if we're not waiting for SSL certs to be trusted.
if (m_connectionStatus != ConnectionStatusSslUntrusted) {
connectInternal(m_currentHost);
QTimer::singleShot(1000, this, [this](){
if (m_currentHost) {
connectInternal(m_currentHost);
}
});
}
}

View File

@ -318,14 +318,8 @@ void JsonRpcClient::onInterfaceConnectedChanged(bool connected)
emit connectedChanged(false);
}
} else {
QVariantMap request;
request.insert("id", 0);
qDebug() << "Connected. Starting JSONRPC Handshake";
request.insert("method", "JSONRPC.Hello");
QVariantMap params;
params.insert("locale", QLocale().name());
request.insert("params", params);
// sendRequest(request);
sendCommand("JSONRPC.Hello", params, this, "helloReply");
}
}

View File

@ -304,11 +304,14 @@ QVariantList JsonTypes::packRuleActions(RuleActions *ruleActions)
} else {
ruleActionParam.insert("paramName", rap->paramName());
}
if (!rap->eventTypeId().isEmpty() && !rap->eventParamTypeId().isEmpty()) {
if (rap->isValueBased()) {
ruleActionParam.insert("value", rap->value());
} else if (rap->isEventParamBased()) {
ruleActionParam.insert("eventTypeId", rap->eventTypeId());
ruleActionParam.insert("eventParamTypeId", rap->eventParamTypeId());
} else {
ruleActionParam.insert("value", rap->value());
ruleActionParam.insert("stateDeviceId", rap->stateDeviceId());
ruleActionParam.insert("stateTypeId", rap->stateTypeId());
}
ruleActionParams.append(ruleActionParam);
}

View File

@ -297,6 +297,8 @@ RuleAction *RuleManager::parseRuleAction(const QVariantMap &ruleAction)
param->setValue(ruleActionParamVariant.toMap().value("value"));
param->setEventTypeId(ruleActionParamVariant.toMap().value("eventTypeId").toString());
param->setEventParamTypeId(ruleActionParamVariant.toMap().value("eventParamTypeId").toString());
param->setStateDeviceId(ruleActionParamVariant.toMap().value("stateDeviceId").toString());
param->setStateTypeId(ruleActionParamVariant.toMap().value("stateTypeId").toString());
ret->ruleActionParams()->addRuleActionParam(param);
}
return ret;

View File

@ -7,6 +7,8 @@ RuleActionParam::RuleActionParam(const QString &paramName, const QVariant &value
m_paramName(paramName)
{
setValue(value);
connect(this, &Param::valueChanged, this, &RuleActionParam::isValueBasedChanged);
}
RuleActionParam::RuleActionParam(QObject *parent) : Param(parent)
@ -37,6 +39,7 @@ void RuleActionParam::setEventTypeId(const QString &eventTypeId)
if (m_eventTypeId != eventTypeId) {
m_eventTypeId = eventTypeId;
emit eventTypeIdChanged();
emit isEventParamBasedChanged();
}
}
@ -50,9 +53,53 @@ void RuleActionParam::setEventParamTypeId(const QString &eventParamTypeId)
if (m_eventParamTypeId != eventParamTypeId) {
m_eventParamTypeId = eventParamTypeId;
emit eventParamTypeIdChanged();
emit isEventParamBasedChanged();
}
}
QString RuleActionParam::stateDeviceId() const
{
return m_stateDeviceId;
}
void RuleActionParam::setStateDeviceId(const QString &stateDeviceId)
{
if (m_stateDeviceId != stateDeviceId) {
m_stateDeviceId = stateDeviceId;
emit stateDeviceIdChanged();
emit isStateValueBasedChanged();
}
}
QString RuleActionParam::stateTypeId() const
{
return m_stateTypeId;
}
void RuleActionParam::setStateTypeId(const QString &stateTypeId)
{
if (m_stateTypeId != stateTypeId) {
m_stateTypeId = stateTypeId;
emit stateTypeIdChanged();
emit isStateValueBasedChanged();
}
}
bool RuleActionParam::isValueBased() const
{
return !m_value.isNull();
}
bool RuleActionParam::isEventParamBased() const
{
return !m_eventTypeId.isNull() && !m_eventParamTypeId.isNull();
}
bool RuleActionParam::isStateValueBased() const
{
return !m_stateDeviceId.isNull() && !m_stateTypeId.isNull();
}
RuleActionParam *RuleActionParam::clone() const
{
RuleActionParam *ret = new RuleActionParam();
@ -61,6 +108,8 @@ RuleActionParam *RuleActionParam::clone() const
ret->setValue(value());
ret->setEventTypeId(eventTypeId());
ret->setEventParamTypeId(eventParamTypeId());
ret->setStateDeviceId(stateDeviceId());
ret->setStateTypeId(stateTypeId());
return ret;
}
@ -72,6 +121,8 @@ bool RuleActionParam::operator==(RuleActionParam *other) const
COMPARE(m_paramName, other->paramName());
COMPARE(m_eventTypeId, other->eventTypeId());
COMPARE(m_eventParamTypeId, other->eventParamTypeId());
COMPARE(m_stateDeviceId, other->stateDeviceId());
COMPARE(m_stateTypeId, other->stateTypeId());
COMPARE(m_value, other->value());
return true;
}

View File

@ -13,6 +13,13 @@ class RuleActionParam : public Param
Q_PROPERTY(QString paramName READ paramName WRITE setParamName NOTIFY paramNameChanged)
Q_PROPERTY(QString eventTypeId READ eventTypeId WRITE setEventTypeId NOTIFY eventTypeIdChanged)
Q_PROPERTY(QString eventParamTypeId READ eventParamTypeId WRITE setEventParamTypeId NOTIFY eventParamTypeIdChanged)
Q_PROPERTY(QString stateDeviceId READ stateDeviceId WRITE setStateDeviceId NOTIFY stateDeviceIdChanged)
Q_PROPERTY(QString stateTypeId READ stateTypeId WRITE setStateTypeId NOTIFY stateTypeIdChanged)
Q_PROPERTY(bool isValueBased READ isValueBased NOTIFY isValueBasedChanged)
Q_PROPERTY(bool isEventParamBased READ isEventParamBased NOTIFY isEventParamBasedChanged)
Q_PROPERTY(bool isStateValueBased READ isStateValueBased NOTIFY isStateValueBasedChanged)
public:
explicit RuleActionParam(const QString &paramName, const QVariant &value, QObject *parent = nullptr);
explicit RuleActionParam(QObject *parent = nullptr);
@ -26,17 +33,35 @@ public:
QString eventParamTypeId() const;
void setEventParamTypeId(const QString &eventParamTypeId);
QString stateDeviceId() const;
void setStateDeviceId(const QString &stateDeviceId);
QString stateTypeId() const;
void setStateTypeId(const QString &stateTypeId);
bool isValueBased() const;
bool isEventParamBased() const;
bool isStateValueBased() const;
RuleActionParam* clone() const;
bool operator==(RuleActionParam *other) const;
signals:
void paramNameChanged();
void eventTypeIdChanged();
void eventParamTypeIdChanged();
void stateDeviceIdChanged();
void stateTypeIdChanged();
void isValueBasedChanged();
void isEventParamBasedChanged();
void isStateValueBasedChanged();
protected:
QString m_paramName;
QString m_eventTypeId;
QString m_eventParamTypeId;
QString m_stateDeviceId;
QString m_stateTypeId;
};
#endif // RULEACTIONPARAM_H

View File

@ -94,6 +94,22 @@ void RuleActionParams::setRuleActionParamEvent(const QString &paramTypeId, const
addRuleActionParam(rap);
}
void RuleActionParams::setRuleActionParamState(const QString &paramTypeId, const QString &stateDeviceId, const QString &stateTypeId)
{
foreach (RuleActionParam *rap, m_list) {
if (rap->paramTypeId() == paramTypeId) {
rap->setStateDeviceId(stateDeviceId);
rap->setStateTypeId(stateTypeId);
return;
}
}
RuleActionParam *rap = new RuleActionParam(this);
rap->setParamTypeId(paramTypeId);
rap->setStateDeviceId(stateDeviceId);
rap->setStateTypeId(stateTypeId);
addRuleActionParam(rap);
}
RuleActionParam *RuleActionParams::get(int index) const
{
return m_list.at(index);

View File

@ -29,6 +29,8 @@ public:
Q_INVOKABLE void setRuleActionParam(const QString &paramTypeId, const QVariant &value);
Q_INVOKABLE void setRuleActionParamByName(const QString &paramName, const QVariant &value);
Q_INVOKABLE void setRuleActionParamEvent(const QString &paramTypeId, const QString &eventTypeId, const QString &eventParamTypeId);
Q_INVOKABLE void setRuleActionParamState(const QString &paramTypeId, const QString &stateDeviceId, const QString &stateTypeId);
Q_INVOKABLE RuleActionParam* get(int index) const;
bool operator==(RuleActionParams *other) const;

View File

@ -179,5 +179,6 @@
<file>ui/components/Imprint.qml</file>
<file>ui/appsettings/LookAndFeelSettingsPage.qml</file>
<file>ui/appsettings/AppLogPage.qml</file>
<file>ui/magic/SelectStatePage.qml</file>
</qresource>
</RCC>

View File

@ -38,27 +38,32 @@ Dialog {
}
ThinDivider {}
Button {
text: qsTr("Remove all those rules")
MeaListItemDelegate {
Layout.fillWidth: true
text: qsTr("Remove all those rules")
progressive: false
onClicked: {
engine.deviceManager.removeDevice(root.device.id, DeviceManager.RemovePolicyCascade)
root.close()
root.destroy();
}
}
Button {
MeaListItemDelegate {
text: qsTr("Update rules, removing this thing")
Layout.fillWidth: true
progressive: false
onClicked: {
engine.deviceManager.removeDevice(root.device.id, DeviceManager.RemovePolicyUpdate)
root.close()
root.destroy();
}
}
Button {
MeaListItemDelegate {
text: qsTr("Don't remove this thing")
Layout.fillWidth: true
progressive: false
onClicked: {
root.close()
root.destroy();

View File

@ -16,6 +16,8 @@ ItemDelegate {
value: paramType.defaultValue
}
property bool writable: true
property alias nameVisible: nameLabel.visible
property string placeholderText: ""
topPadding: 0
bottomPadding: 0
@ -23,6 +25,7 @@ ItemDelegate {
id: contentItemColumn
RowLayout {
Label {
id: nameLabel
Layout.fillWidth: true
Layout.minimumWidth: parent.width / 2
text: root.paramType.displayName
@ -90,7 +93,6 @@ ItemDelegate {
}
return root.param.value;
}
}
}
Component {
@ -188,6 +190,7 @@ ItemDelegate {
root.param.value = text;
}
}
placeholderText: root.placeholderText
}
}

View File

@ -28,10 +28,20 @@ MeaListItemDelegate {
var ret = [];
for (var i = 0; i < root.ruleAction.ruleActionParams.count; i++) {
var ruleActionParam = root.ruleAction.ruleActionParams.get(i)
print("populating subtext:", ruleActionParam.eventTypeId, ruleActionParam.eventParamTypeId)
var paramString = qsTr("%1: %2")
.arg(root.actionType.paramTypes.getParamType(ruleActionParam.paramTypeId).displayName)
.arg(ruleActionParam.eventParamTypeId.length > 0 ? qsTr("value from event") : ruleActionParam.value)
print("populating subtext:", ruleActionParam.eventTypeId, ruleActionParam.eventParamTypeId, ruleActionParam.stateDeviceId, ruleActionParam.stateTypeId, ruleActionParam.isValueBased, ruleActionParam.isEventParamBased, ruleActionParam.isStateValueBased)
var paramString = qsTr("%1: %2").arg(root.actionType.paramTypes.getParamType(ruleActionParam.paramTypeId).displayName)
if (ruleActionParam.isValueBased) {
paramString = paramString.arg(ruleActionParam.value)
} else if (ruleActionParam.isEventParamBased) {
paramString = paramString.arg(qsTr("value from event"))
} else if (ruleActionParam.isStateValueBased) {
var stateDevice = engine.deviceManager.devices.getDevice(ruleActionParam.stateDeviceId)
var stateType = stateDevice.deviceClass.stateTypes.getStateType(ruleActionParam.stateTypeId)
print("have state value based param:", stateDevice.name)
paramString = paramString.arg("{" + stateDevice.name + " - " + stateType.displayName + "}")
}
ret.push(paramString)
}
return ret.join(', ')

View File

@ -22,7 +22,7 @@ Page {
signal completed();
header: GuhHeader {
text: "params"
text: actionType.displayName
onBackPressed: root.backPressed();
}
@ -46,6 +46,9 @@ Page {
if (eventParamRadioButton.checked) {
return "event"
}
if (stateValueRadioButton.checked) {
return "state"
}
return ""
}
@ -53,54 +56,122 @@ Page {
property alias value: paramDelegate.value
property alias eventType: eventParamsComboBox.eventType
property alias eventParamTypeId: eventParamsComboBox.currentParamTypeId
property alias stateDeviceId: statePickerDelegate.deviceId
property alias stateTypeId: statePickerDelegate.stateTypeId
RadioButton {
id: staticParamRadioButton
text: qsTr("Use static value as parameter")
checked: true
}
ParamDelegate {
id: paramDelegate
Layout.fillWidth: true
paramType: root.actionType.paramTypes.get(index)
enabled: staticParamRadioButton.checked
}
RadioButton {
id: eventParamRadioButton
text: qsTr("Use event parameter")
visible: eventParamsComboBox.count > 0
}
ComboBox {
id: eventParamsComboBox
GroupBox {
Layout.fillWidth: true
Layout.margins: app.margins
enabled: eventParamRadioButton.checked
visible: count > 0
Component.onCompleted: currentIndex = 0;
property var eventDescriptor: root.rule.eventDescriptors.count === 1 ? root.rule.eventDescriptors.get(0) : null
property var device: eventDescriptor ? engine.deviceManager.devices.getDevice(eventDescriptor.deviceId) : null
property var deviceClass: device ? engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId) : null
property var eventType: deviceClass ? deviceClass.eventTypes.getEventType(eventDescriptor.eventTypeId) : null
property var currentParamDescriptor: eventType.paramTypes.get(eventParamsComboBox.currentIndex)
property var currentParamTypeId: currentParamDescriptor.id
model: eventType.paramTypes
delegate: ItemDelegate {
width: parent.width
text: eventParamsComboBox.device.name + " - " + eventParamsComboBox.eventType.displayName + " - " + eventParamsComboBox.eventType.paramTypes.getParamType(model.id).displayName
}
contentItem: Label {
id: eventParamsComboBoxContentItem
title: paramType.displayName
ColumnLayout {
anchors.fill: parent
anchors.margins: app.margins
text: eventParamsComboBox.device.name + " - " + eventParamsComboBox.eventType.displayName + " - " + eventParamsComboBox.currentParamDescriptor.displayName
elide: Text.ElideRight
RadioButton {
id: staticParamRadioButton
text: qsTr("Use static value as parameter")
checked: true
font.pixelSize: app.smallFont
visible: eventParamRadioButton.visible || stateValueRadioButton.visible
}
RadioButton {
id: eventParamRadioButton
text: qsTr("Use event parameter")
visible: eventParamsComboBox.count > 0
font.pixelSize: app.smallFont
}
RadioButton {
id: stateValueRadioButton
text: qsTr("Use a thing's state value")
font.pixelSize: app.smallFont
visible: engine.jsonRpcClient.ensureServerVersion("2.0")
}
ThinDivider {
visible: staticParamRadioButton.visible
}
ParamDelegate {
id: paramDelegate
Layout.fillWidth: true
paramType: root.actionType.paramTypes.get(index)
enabled: staticParamRadioButton.checked
nameVisible: false
visible: staticParamRadioButton.checked
placeholderText: qsTr("Insert value here")
}
ComboBox {
id: eventParamsComboBox
Layout.fillWidth: true
visible: eventParamRadioButton.checked && count > 0
Component.onCompleted: currentIndex = 0;
property var eventDescriptor: root.rule.eventDescriptors.count === 1 ? root.rule.eventDescriptors.get(0) : null
property var device: eventDescriptor ? engine.deviceManager.devices.getDevice(eventDescriptor.deviceId) : null
property var deviceClass: device ? engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId) : null
property var eventType: deviceClass ? deviceClass.eventTypes.getEventType(eventDescriptor.eventTypeId) : null
property var currentParamDescriptor: eventType.paramTypes.get(eventParamsComboBox.currentIndex)
property var currentParamTypeId: currentParamDescriptor.id
model: eventType.paramTypes
delegate: ItemDelegate {
width: parent.width
text: eventParamsComboBox.device.name + " - " + eventParamsComboBox.eventType.displayName + " - " + eventParamsComboBox.eventType.paramTypes.getParamType(model.id).displayName
}
contentItem: Label {
id: eventParamsComboBoxContentItem
anchors.fill: parent
anchors.margins: app.margins
text: eventParamsComboBox.device.name + " - " + eventParamsComboBox.eventType.displayName + " - " + eventParamsComboBox.currentParamDescriptor.displayName
elide: Text.ElideRight
}
}
MeaListItemDelegate {
id: statePickerDelegate
Layout.fillWidth: true
text: deviceId === null || stateTypeId === null
? qsTr("Select a state")
: dev.name + " - " + dev.deviceClass.stateTypes.getStateType(stateTypeId).displayName
visible: stateValueRadioButton.checked
property var deviceId: null
property var stateTypeId: null
readonly property Device dev: engine.deviceManager.devices.getDevice(deviceId)
onClicked: {
var page = pageStack.push(Qt.resolvedUrl("SelectThingPage.qml"), {showStates: true, showEvents: false, showActions: false });
page.thingSelected.connect(function(device) {
print("Thing selected", device.name);
statePickerDelegate.deviceId = device.id
var selectStatePage = pageStack.replace(Qt.resolvedUrl("SelectStatePage.qml"), {device: device})
selectStatePage.stateSelected.connect(function(stateTypeId) {
print("State selected", stateTypeId)
pageStack.pop();
statePickerDelegate.stateTypeId = stateTypeId;
})
})
page.backPressed.connect(function() {
pageStack.pop();
})
}
}
}
}
ThinDivider {}
// Label {
// id: paramNameLabel
// Layout.fillWidth: true
// Layout.leftMargin: app.margins
// Layout.rightMargin: app.margins
// Layout.topMargin: app.margins
// elide: Text.ElideRight
// text: paramType.displayName
// font.pixelSize: app.largeFont
// }
// ThinDivider {}
}
}
Item {
@ -124,6 +195,9 @@ Page {
} else if (paramDelegate.type === "event") {
print("adding event based rule action param", paramDelegate.paramType.id, paramDelegate.eventType.id, paramDelegate.eventParamTypeId)
root.ruleAction.ruleActionParams.setRuleActionParamEvent(paramDelegate.paramType.id, paramDelegate.eventType.id, paramDelegate.eventParamTypeId)
} else if (paramDelegate.type === "state") {
print("adding state value based rule action param", paramDelegate.paramType.id, paramDelegate.stateDeviceId, paramDelegate.stateTypeId)
root.ruleAction.ruleActionParams.setRuleActionParamState(paramDelegate.paramType.id, paramDelegate.stateDeviceId, paramDelegate.stateTypeId)
}
}
root.completed()

View File

@ -0,0 +1,35 @@
import QtQuick 2.8
import QtQuick.Controls 2.1
import QtQuick.Layouts 1.2
import "../components"
import "../delegates"
import Nymea 1.0
Page {
id: root
header: GuhHeader {
text: qsTr("Select state")
onBackPressed: pageStack.pop()
}
property Device device: null
signal stateSelected(var stateTypeId);
ListView {
anchors.fill: parent
model: device.deviceClass.stateTypes
delegate: MeaListItemDelegate {
width: parent.width
iconName: "../images/state.svg"
text: model.displayName
subText: root.device.states.getState(model.id).value
prominentSubText: false
onClicked: {
root.stateSelected(model.id)
}
}
}
}