Add support for localized and dynamic possibleValues of states
This commit is contained in:
parent
8a8083c2a6
commit
9717825c16
@ -129,7 +129,6 @@ void ThingManager::notificationReceived(const QVariantMap &data)
|
||||
}
|
||||
QUuid stateTypeId = params.value("stateTypeId").toUuid();
|
||||
QVariant value = params.value("value");
|
||||
// qDebug() << "Thing state changed for:" << dev->name() << "State name:" << dev->thingClass()->stateTypes()->getStateType(stateTypeId) << "value:" << value;
|
||||
State *state = thing->state(stateTypeId);
|
||||
state->setValue(value);
|
||||
if (params.contains("minValue")) {
|
||||
@ -138,6 +137,9 @@ void ThingManager::notificationReceived(const QVariantMap &data)
|
||||
if (params.contains("maxValue")) {
|
||||
state->setMaxValue(params.value("maxValue"));
|
||||
}
|
||||
if (params.contains("possibleValues")) {
|
||||
state->setPossibleValues(params.value("possibleValues").toList());
|
||||
}
|
||||
emit thingStateChanged(thing->id(), stateTypeId, value);
|
||||
} else if (notification == "Integrations.ThingAdded") {
|
||||
Thing *thing = unpackThing(this, data.value("params").toMap().value("thing").toMap(), m_thingClasses);
|
||||
@ -851,7 +853,14 @@ StateType *ThingManager::unpackStateType(const QVariantMap &stateTypeMap, QObjec
|
||||
stateType->setDisplayName(stateTypeMap.value("displayName").toString());
|
||||
stateType->setIndex(stateTypeMap.value("index").toInt());
|
||||
stateType->setDefaultValue(stateTypeMap.value("defaultValue"));
|
||||
stateType->setAllowedValues(stateTypeMap.value("possibleValues").toList());
|
||||
QVariantList possibleValuesList = stateTypeMap.value("possibleValues").toList();
|
||||
QVariantList possibleValuesNamesList = stateTypeMap.value("possibleValuesDisplayNames").toList();
|
||||
QStringList possibleValuesDisplayNames;
|
||||
for (int i = 0; i < possibleValuesList.count(); i++) {
|
||||
QVariant possibleValue = possibleValuesList.at(i);
|
||||
possibleValuesDisplayNames.append(possibleValuesNamesList.count() > i ? possibleValuesNamesList.at(i).toString() : possibleValue.toString());
|
||||
}
|
||||
stateType->setPossibleValues(stateTypeMap.value("possibleValues").toList(), possibleValuesDisplayNames);
|
||||
stateType->setType(stateTypeMap.value("type").toString());
|
||||
stateType->setMinValue(stateTypeMap.value("minValue"));
|
||||
stateType->setMaxValue(stateTypeMap.value("maxValue"));
|
||||
@ -861,6 +870,7 @@ StateType *ThingManager::unpackStateType(const QVariantMap &stateTypeMap, QObjec
|
||||
Types::IOType ioType = static_cast<Types::IOType>(metaEnum.keyToValue(stateTypeMap.value("ioType").toByteArray()));
|
||||
stateType->setIOType(ioType);
|
||||
|
||||
qCritical() << "*** possible vals" << stateType->name() << possibleValuesDisplayNames << stateTypeMap.value("possibleValuesDisplayNames").toList();
|
||||
return stateType;
|
||||
}
|
||||
|
||||
@ -981,6 +991,11 @@ Thing* ThingManager::unpackThing(ThingManager *thingManager, const QVariantMap &
|
||||
} else {
|
||||
state->setMaxValue(stateType->maxValue());
|
||||
}
|
||||
if (stateMap.contains("possibleValues")) {
|
||||
state->setPossibleValues(stateMap.value("possibleValues").toList());
|
||||
} else {
|
||||
state->setPossibleValues(stateType->possibleValues());
|
||||
}
|
||||
}
|
||||
thing->setStates(states);
|
||||
|
||||
|
||||
@ -87,3 +87,16 @@ void State::setMaxValue(const QVariant &maxValue)
|
||||
emit maxValueChanged();
|
||||
}
|
||||
}
|
||||
|
||||
QVariantList State::possibleValues() const
|
||||
{
|
||||
return m_possibleValues;
|
||||
}
|
||||
|
||||
void State::setPossibleValues(const QVariantList &possibleValues)
|
||||
{
|
||||
if (m_possibleValues != possibleValues) {
|
||||
m_possibleValues = possibleValues;
|
||||
emit possibleValuesChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@ -43,6 +43,7 @@ class State : public QObject
|
||||
Q_PROPERTY(QVariant value READ value NOTIFY valueChanged)
|
||||
Q_PROPERTY(QVariant minValue READ minValue NOTIFY minValueChanged)
|
||||
Q_PROPERTY(QVariant maxValue READ maxValue NOTIFY maxValueChanged)
|
||||
Q_PROPERTY(QVariantList possibleValues READ possibleValues NOTIFY possibleValuesChanged)
|
||||
|
||||
public:
|
||||
explicit State(const QUuid &thingId, const QUuid &stateTypeId, const QVariant &value, QObject *parent = nullptr);
|
||||
@ -59,18 +60,22 @@ public:
|
||||
QVariant maxValue() const;
|
||||
void setMaxValue(const QVariant &maxValue);
|
||||
|
||||
QVariantList possibleValues() const;
|
||||
void setPossibleValues(const QVariantList &possibleValues);
|
||||
|
||||
private:
|
||||
QUuid m_thingId;
|
||||
QUuid m_stateTypeId;
|
||||
QVariant m_value;
|
||||
QVariant m_minValue;
|
||||
QVariant m_maxValue;
|
||||
QVariantList m_possibleValues;
|
||||
|
||||
signals:
|
||||
void valueChanged();
|
||||
void minValueChanged();
|
||||
void maxValueChanged();
|
||||
|
||||
void possibleValuesChanged();
|
||||
};
|
||||
|
||||
#endif // STATE_H
|
||||
|
||||
@ -100,14 +100,27 @@ void StateType::setDefaultValue(const QVariant &defaultValue)
|
||||
m_defaultValue = defaultValue;
|
||||
}
|
||||
|
||||
QVariantList StateType::allowedValues() const
|
||||
QVariantList StateType::possibleValues() const
|
||||
{
|
||||
return m_allowedValues;
|
||||
return m_possibleValues;
|
||||
}
|
||||
|
||||
void StateType::setAllowedValues(const QVariantList &allowedValues)
|
||||
void StateType::setPossibleValues(const QVariantList &values, const QStringList &displayNames)
|
||||
{
|
||||
m_allowedValues = allowedValues;
|
||||
Q_ASSERT_X(values.count() == displayNames.count(), "StateType", "Display names list length does not match values list length");
|
||||
m_possibleValues = values;
|
||||
m_possibleValuesDisplayNames = displayNames;
|
||||
}
|
||||
|
||||
QStringList StateType::possibleValuesDisplayNames() const
|
||||
{
|
||||
return m_possibleValuesDisplayNames;
|
||||
}
|
||||
|
||||
QString StateType::localizedValue(const QVariant &value) const
|
||||
{
|
||||
int idx = m_possibleValues.indexOf(value);
|
||||
return m_possibleValuesDisplayNames.at(idx);
|
||||
}
|
||||
|
||||
Types::Unit StateType::unit() const
|
||||
|
||||
@ -46,7 +46,9 @@ class StateType : public QObject
|
||||
Q_PROPERTY(QString type READ type CONSTANT)
|
||||
Q_PROPERTY(int index READ index CONSTANT)
|
||||
Q_PROPERTY(QVariant defaultValue READ defaultValue CONSTANT)
|
||||
Q_PROPERTY(QVariantList allowedValues READ allowedValues CONSTANT)
|
||||
Q_PROPERTY(QVariantList allowedValues READ possibleValues CONSTANT) // Deprecated
|
||||
Q_PROPERTY(QVariantList possibleValues READ possibleValues CONSTANT)
|
||||
Q_PROPERTY(QStringList possibleValuesDisplayNames READ possibleValuesDisplayNames CONSTANT)
|
||||
Q_PROPERTY(Types::Unit unit READ unit CONSTANT)
|
||||
Q_PROPERTY(Types::IOType ioType READ ioType CONSTANT)
|
||||
Q_PROPERTY(QVariant minValue READ minValue CONSTANT)
|
||||
@ -74,8 +76,10 @@ public:
|
||||
QVariant defaultValue() const;
|
||||
void setDefaultValue(const QVariant &defaultValue);
|
||||
|
||||
QVariantList allowedValues() const;
|
||||
void setAllowedValues(const QVariantList &allowedValues);
|
||||
QVariantList possibleValues() const;
|
||||
QStringList possibleValuesDisplayNames() const;
|
||||
void setPossibleValues(const QVariantList &values, const QStringList &displayNames);
|
||||
Q_INVOKABLE QString localizedValue(const QVariant &value) const;
|
||||
|
||||
Types::Unit unit() const;
|
||||
void setUnit(const Types::Unit &unit);
|
||||
@ -96,7 +100,8 @@ private:
|
||||
QString m_type;
|
||||
int m_index;
|
||||
QVariant m_defaultValue;
|
||||
QVariantList m_allowedValues;
|
||||
QVariantList m_possibleValues;
|
||||
QStringList m_possibleValuesDisplayNames;
|
||||
Types::Unit m_unit = Types::UnitNone;
|
||||
Types::IOType m_ioType = Types::IOTypeNone;
|
||||
QVariant m_minValue;
|
||||
|
||||
@ -54,6 +54,8 @@ ItemDelegate {
|
||||
contentItem: ColumnLayout {
|
||||
id: contentItemColumn
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: Style.margins
|
||||
anchors.rightMargin: Style.margins
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: Style.margins
|
||||
|
||||
@ -36,12 +36,35 @@ import Nymea 1.0
|
||||
import "../../components"
|
||||
|
||||
ComboBox {
|
||||
id: root
|
||||
property var value
|
||||
property var possibleValues
|
||||
property var possibleValuesDisplayNames
|
||||
|
||||
signal changed(var value)
|
||||
model: possibleValues
|
||||
currentIndex: possibleValues.indexOf(value)
|
||||
onActivated: changed(model[index])
|
||||
Component.onCompleted: print("completed. values", possibleValues, "value", value)
|
||||
|
||||
function update() {
|
||||
print("possible:", root.possibleValues, root.possibleValuesDisplayNames)
|
||||
listModel.clear();
|
||||
for (var i = 0; i < root.possibleValues.length; i++) {
|
||||
var value = root.possibleValues[i]
|
||||
var label = root.possibleValuesDisplayNames.length > i ? root.possibleValuesDisplayNames[i] : root.possibleValues[i]
|
||||
listModel.append({value: value, label: label})
|
||||
}
|
||||
currentIndex = possibleValues.indexOf(root.value)
|
||||
}
|
||||
|
||||
model: ListModel {
|
||||
id: listModel
|
||||
}
|
||||
onActivated: changed(model.get(index).value)
|
||||
textRole: "label"
|
||||
Component.onCompleted: {
|
||||
print("completed. values", possibleValues, "value", root.value)
|
||||
update();
|
||||
}
|
||||
onPossibleValuesChanged: {
|
||||
print("Possible values changed:", possibleValues)
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
@ -79,6 +79,7 @@ ThingsListPageBase {
|
||||
property bool isConsumer: itemDelegate.thing.thingClass.interfaces.indexOf("smartmeterconsumer") >= 0
|
||||
property bool isProduction: currentPowerState.value < 0
|
||||
property bool isConsumption: currentPowerState.value > 0
|
||||
property bool isIdling: currentPowerState.value === 0
|
||||
property double absValue: Math.abs(currentPowerState.value)
|
||||
property double cleanVale: (absValue / (absValue > 1000 ? 1000 : 1)).toFixed(1)
|
||||
property string unit: absValue > 1000 ? "kW" : "W"
|
||||
@ -105,9 +106,11 @@ ThingsListPageBase {
|
||||
if (dataGrid.isProduction) {
|
||||
//: e.g. Discharging at 5kW
|
||||
return qsTr("Discharging at %1").arg(dataGrid.cleanVale + " " + dataGrid.unit)
|
||||
} else {
|
||||
} else if (dataGrid.isConsumption){
|
||||
//: e.g. Charging at 5kW
|
||||
return qsTr("Charging at %1").arg(dataGrid.cleanVale + " " + dataGrid.unit)
|
||||
} else {
|
||||
return qsTr("Idling")
|
||||
}
|
||||
|
||||
} else if (dataGrid.isProducer && !dataGrid.isConsumer) {
|
||||
|
||||
@ -199,7 +199,7 @@ ThingPageBase {
|
||||
switch (stateDelegate.stateType.type.toLowerCase()) {
|
||||
case "string":
|
||||
if (isWritable) {
|
||||
if (stateDelegate.stateType.allowedValues.length > 0) {
|
||||
if (stateDelegate.stateType.possibleValues.length > 0) {
|
||||
sourceComp = "ComboBoxDelegate.qml"
|
||||
} else {
|
||||
sourceComp = "TextFieldDelegate.qml";
|
||||
@ -252,12 +252,12 @@ ThingPageBase {
|
||||
var maxValue = stateDelegate.stateType.maxValue !== undefined
|
||||
? stateDelegate.stateType.maxValue
|
||||
: 2000000000;
|
||||
print(stateDelegate.stateType.minValue)
|
||||
print("pushing delegate for", stateDelegate.stateType.name, "from:", minValue, "to:", maxValue)
|
||||
print("pushing delegate for", stateDelegate.stateType.name, "from:", minValue, "to:", maxValue, "possible:", stateDelegate.stateType.possibleValuesDisplayNames)
|
||||
stateDelegateLoader.setSource("../delegates/statedelegates/" + sourceComp,
|
||||
{
|
||||
// value: root.thing.states.getState(stateType.id).value,
|
||||
possibleValues: stateDelegate.stateType.allowedValues,
|
||||
value: root.thing.states.getState(stateType.id).value,
|
||||
possibleValues: stateDelegate.stateType.possibleValues,
|
||||
possibleValuesDisplayNames: stateDelegate.stateType.possibleValuesDisplayNames,
|
||||
from: minValue,
|
||||
to: maxValue,
|
||||
unit: stateDelegate.stateType.unit,
|
||||
@ -306,6 +306,30 @@ ThingPageBase {
|
||||
property: "to"
|
||||
value: stateDelegate.thingState.maxValue
|
||||
}
|
||||
Binding {
|
||||
target: stateDelegateLoader.item.hasOwnProperty("possibleValues") ? stateDelegateLoader.item : null
|
||||
property: "possibleValues"
|
||||
value: stateDelegate.thingState.possibleValues
|
||||
}
|
||||
Binding {
|
||||
target: stateDelegateLoader.item.hasOwnProperty("possibleValuesDisplayNames") ? stateDelegateLoader.item : null
|
||||
property: "possibleValuesDisplayNames"
|
||||
value: {
|
||||
print("updating displayNames", stateDelegate.thingState.possibleValues)
|
||||
var ret = []
|
||||
for (var i = 0; i < stateDelegate.thingState.possibleValues.length; i++) {
|
||||
var possibleValue = stateDelegate.thingState.possibleValues[i]
|
||||
var idx = stateDelegate.stateType.possibleValues.indexOf(possibleValue)
|
||||
print("value:", possibleValue, idx)
|
||||
if (idx >= 0) {
|
||||
ret.push(stateDelegate.stateType.possibleValuesDisplayNames[idx])
|
||||
} else {
|
||||
ret.push(possibleValue)
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
}
|
||||
Binding {
|
||||
target: stateDelegateLoader.item.hasOwnProperty("unit") ? stateDelegateLoader.item : null
|
||||
property: "unit"
|
||||
@ -315,6 +339,7 @@ ThingPageBase {
|
||||
Connections {
|
||||
target: stateDelegateLoader.item && stateDelegateLoader.item.hasOwnProperty("changed") ? stateDelegateLoader.item : null
|
||||
onChanged: {
|
||||
print("Value changed:", value)
|
||||
stateDelegate.enqueueSetValue(value)
|
||||
}
|
||||
}
|
||||
|
||||
@ -240,11 +240,13 @@ ThingPageBase {
|
||||
? qsTr("Total production: %1 kWh").arg('<span style="font-size:' + Style.bigFont.pixelSize + 'px">' + root.totalEnergyProducedState.value.toFixed(2) + "</span>")
|
||||
: root.isEnergyMeter
|
||||
? qsTr("Total acquisition: %1 kWh").arg('<span style="font-size:' + Style.bigFont.pixelSize + 'px">' + root.totalEnergyConsumedState.value.toFixed(2) + "</span>") + "<br>" + qsTr("Total return: %1 kWh").arg('<span style="font-size:' + Style.bigFont.pixelSize + 'px">' + root.totalEnergyProducedState.value.toFixed(2) + "</span>")
|
||||
: root.isBattery && isCharging
|
||||
? qsTr("At the current rate, the battery will be fully charged at %1.").arg('<span style="font-size:' + Style.bigFont.pixelSize + 'px">' + endTime.toLocaleTimeString(Locale.ShortFormat) + "</span>")
|
||||
: root.isBattery && isDischarging
|
||||
? qsTr("At the current rate, the battery will last until %1.").arg('<span style="font-size:' + Style.bigFont.pixelSize + 'px">' + endTime.toLocaleTimeString(Locale.ShortFormat) + "</span>")
|
||||
: ""
|
||||
: root.isBattery && root.batteryLevelState.value === 0
|
||||
? qsTr("The battery is empty")
|
||||
: root.isBattery && root.isCharging
|
||||
? qsTr("At the current rate, the battery will be fully charged at %1.").arg('<span style="font-size:' + Style.bigFont.pixelSize + 'px">' + endTime.toLocaleTimeString(Locale.ShortFormat) + "</span>")
|
||||
: root.isBattery && root.isDischarging
|
||||
? qsTr("At the current rate, the battery will last until %1.").arg('<span style="font-size:' + Style.bigFont.pixelSize + 'px">' + endTime.toLocaleTimeString(Locale.ShortFormat) + "</span>")
|
||||
: ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user