diff --git a/guh-control/devicemanager.cpp b/guh-control/devicemanager.cpp index b326ae75..b70dd780 100644 --- a/guh-control/devicemanager.cpp +++ b/guh-control/devicemanager.cpp @@ -162,7 +162,7 @@ void DeviceManager::getPluginsResponse(const QVariantMap ¶ms) void DeviceManager::getPluginConfigResponse(const QVariantMap ¶ms) { - qDebug() << "plugin config response" << params; +// qDebug() << "plugin config response" << params; Plugin *p = m_plugins->get(m_currentGetConfigIndex); if (!p) { qDebug() << "Received a plugin config for a plugin we don't know"; diff --git a/guh-control/jsonrpc/jsontypes.cpp b/guh-control/jsonrpc/jsontypes.cpp index cb2d3277..6db62f77 100644 --- a/guh-control/jsonrpc/jsontypes.cpp +++ b/guh-control/jsonrpc/jsontypes.cpp @@ -221,7 +221,7 @@ QVariantMap JsonTypes::packRule(Rule *rule) ret.insert("ruleId", rule->id()); } ret.insert("name", rule->name()); - ret.insert("enabled", true); + ret.insert("enabled", rule->enabled()); if (rule->ruleActions()->rowCount() > 0) { QVariantList actions; diff --git a/guh-control/main.cpp b/guh-control/main.cpp index 50d5cdf1..13a39019 100644 --- a/guh-control/main.cpp +++ b/guh-control/main.cpp @@ -42,6 +42,8 @@ #include "types/eventdescriptors.h" #include "types/eventdescriptor.h" #include "types/rule.h" +#include "types/interfaces.h" +#include "types/interface.h" #include "models/logsmodel.h" #include "models/valuelogsproxymodel.h" #include "basicconfiguration.h" @@ -122,6 +124,9 @@ int main(int argc, char *argv[]) qmlRegisterUncreatableType(uri, 1, 0, "ParamDescriptor", "Uncreatable"); qmlRegisterUncreatableType(uri, 1, 0, "ParamDescriptors", "Uncreatable"); + qmlRegisterUncreatableType(uri, 1, 0, "Interface", "Uncreatable"); + qmlRegisterType(uri, 1, 0, "Interfaces"); + qmlRegisterUncreatableType(uri, 1, 0, "Plugin", "Can't create this in QML. Get it from the Plugins."); qmlRegisterUncreatableType(uri, 1, 0, "Plugins", "Can't create this in QML. Get it from the DeviceManager."); qmlRegisterType(uri, 1, 0, "PluginsProxy"); diff --git a/guh-control/resources.qrc b/guh-control/resources.qrc index a76d7821..3267a72d 100644 --- a/guh-control/resources.qrc +++ b/guh-control/resources.qrc @@ -133,5 +133,6 @@ ui/fonts/Ubuntu-MI.ttf ui/fonts/Ubuntu-R.ttf ui/fonts/Ubuntu-RI.ttf + ui/components/InterfacesModels.qml diff --git a/guh-control/rulemanager.cpp b/guh-control/rulemanager.cpp index 3dbf7f13..79427180 100644 --- a/guh-control/rulemanager.cpp +++ b/guh-control/rulemanager.cpp @@ -77,23 +77,27 @@ void RuleManager::handleRulesNotification(const QVariantMap ¶ms) // 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(); - bool active = ruleMap.value("active").toBool(); - Rule* rule = new Rule(ruleId, m_rules); - rule->setName(name); - rule->setEnabled(enabled); - rule->setActive(active); - parseEventDescriptors(ruleMap.value("eventDescriptors").toList(), rule); - StateEvaluator* stateEvaluator = parseStateEvaluator(ruleMap.value("stateEvaluator").toMap()); - stateEvaluator->setParent(rule); - - parseRuleActions(ruleMap.value("actions").toList(), rule); - m_rules->insert(rule); + m_rules->insert(parseRule(ruleMap)); } else if (params.value("notification").toString() == "Rules.RuleRemoved") { QUuid ruleId = params.value("params").toMap().value("ruleId").toUuid(); m_rules->remove(ruleId); + } else if (params.value("notification").toString() == "Rules.RuleConfigurationChanged") { + QVariantMap ruleMap = params.value("params").toMap().value("rule").toMap(); + QUuid ruleId = ruleMap.value("id").toUuid(); + int idx = -1; + for (int i = 0; i < m_rules->rowCount(); i++) { + if (m_rules->get(i)->id() == ruleId) { + idx = i; + break; + } + } + if (idx == -1) { + qWarning() << "Got a rule update notification for a rule we don't know" << ruleId; + return; + } + m_rules->remove(ruleId); + m_rules->insert(parseRule(ruleMap)); + } else { qWarning() << "Unhandled rule notification" << params; } @@ -132,7 +136,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()); + parseStateEvaluator(ruleMap.value("stateEvaluator").toMap()); } void RuleManager::onAddRuleReply(const QVariantMap ¶ms) @@ -152,6 +156,23 @@ void RuleManager::onEditRuleReply(const QVariantMap ¶ms) emit editRuleReply(params.value("params").toMap().value("ruleError").toString()); } +Rule *RuleManager::parseRule(const QVariantMap &ruleMap) +{ + QUuid ruleId = ruleMap.value("id").toUuid(); + QString name = ruleMap.value("name").toString(); + bool enabled = ruleMap.value("enabled").toBool(); + bool active = ruleMap.value("active").toBool(); + Rule* rule = new Rule(ruleId); + rule->setName(name); + rule->setEnabled(enabled); + rule->setActive(active); + parseEventDescriptors(ruleMap.value("eventDescriptors").toList(), rule); + StateEvaluator* stateEvaluator = parseStateEvaluator(ruleMap.value("stateEvaluator").toMap()); + stateEvaluator->setParent(rule); + parseRuleActions(ruleMap.value("actions").toList(), rule); + return rule; +} + void RuleManager::parseEventDescriptors(const QVariantList &eventDescriptorList, Rule *rule) { foreach (const QVariant &eventDescriptorVariant, eventDescriptorList) { diff --git a/guh-control/rulemanager.h b/guh-control/rulemanager.h index a50a0946..c4a61eb4 100644 --- a/guh-control/rulemanager.h +++ b/guh-control/rulemanager.h @@ -40,6 +40,7 @@ private slots: void onEditRuleReply(const QVariantMap ¶ms); private: + Rule *parseRule(const QVariantMap &ruleMap); void parseEventDescriptors(const QVariantList &eventDescriptorList, Rule *rule); StateEvaluator* parseStateEvaluator(const QVariantMap &stateEvaluatorMap); void parseRuleActions(const QVariantList &ruleActions, Rule *rule); diff --git a/guh-control/ui/MagicPage.qml b/guh-control/ui/MagicPage.qml index f2ec9b95..0af393f6 100644 --- a/guh-control/ui/MagicPage.qml +++ b/guh-control/ui/MagicPage.qml @@ -26,13 +26,16 @@ Page { onAddRuleReply: { if (ruleError == "RuleErrorNoError") { pageStack.pop(); + } else { + errorDialog.createComponent(root, {text: ruleError }) } } onEditRuleReply: { - print("have add rule reply") if (ruleError == "RuleErrorNoError") { pageStack.pop(); + } else { + errorDialog.createComponent(root, {text: ruleError }) } } } diff --git a/guh-control/ui/MainPage.qml b/guh-control/ui/MainPage.qml index 6152fb70..43cce5de 100644 --- a/guh-control/ui/MainPage.qml +++ b/guh-control/ui/MainPage.qml @@ -57,7 +57,7 @@ Page { Layout.fillWidth: true Layout.fillHeight: true currentIndex: pageIndicator.currentIndex - clip: true +// clip: true DevicesPage { width: parent.view.width diff --git a/guh-control/ui/components/InterfacesModels.qml b/guh-control/ui/components/InterfacesModels.qml new file mode 100644 index 00000000..4ed7b794 --- /dev/null +++ b/guh-control/ui/components/InterfacesModels.qml @@ -0,0 +1,8 @@ +import QtQuick 2.0 + +Item { + property ListModel eventTemplateModel: ListModel { + ListElement { interfaceName: "battery"; stateName: "batteryLevel"; stateDisplayName: "Battery level"; eventDisplayName: "Battery level changed" } + ListElement { interfaceName: "battery"; stateName: "batteryCritical"; stateDisplayName: "Battery critical"; eventDisplayName: "Battery critical changed" } + } +} diff --git a/guh-control/ui/magic/EditRulePage.qml b/guh-control/ui/magic/EditRulePage.qml index 592d44ae..0a9b5723 100644 --- a/guh-control/ui/magic/EditRulePage.qml +++ b/guh-control/ui/magic/EditRulePage.qml @@ -96,6 +96,19 @@ Page { } } + RowLayout { + Layout.fillWidth: true + Label { + Layout.fillWidth: true + text: qsTr("This rule is enabled") + } + CheckBox { + checked: root.rule.enabled + onClicked: { + root.rule.enabled = checked + } + } + } } ThinDivider {} diff --git a/guh-control/ui/magic/SelectEventDescriptorPage.qml b/guh-control/ui/magic/SelectEventDescriptorPage.qml index 03499629..cf9a6fe5 100644 --- a/guh-control/ui/magic/SelectEventDescriptorPage.qml +++ b/guh-control/ui/magic/SelectEventDescriptorPage.qml @@ -23,11 +23,12 @@ Page { id: header onBackPressed: root.backPressed(); - property bool interfacesMode: false + property bool interfacesMode: root.eventDescriptor.interfaceName !== "" onInterfacesModeChanged: root.buildInterface() HeaderButton { imageSource: header.interfacesMode ? "../images/view-expand.svg" : "../images/view-collapse.svg" + visible: root.eventDescriptor.interfaceName === "" onClicked: header.interfacesMode = !header.interfacesMode } } @@ -39,48 +40,39 @@ Page { ListElement { interfaceName: "weather"; text: "When it starts raining..."; event: "rain" } } - function buildInterface() { - actualModel.clear() + Interfaces { + id: interfacesModel + } + function buildInterface() { if (header.interfacesMode) { if (root.device) { print("device supports interfaces", deviceClass.interfaces) - for (var i = 0; i < eventTemplateModel.count; i++) { - print("event is for interface", eventTemplateModel.get(i).interfaceName) - if (deviceClass.interfaces.indexOf(eventTemplateModel.get(i).interfaceName) >= 0) { - actualModel.append(eventTemplateModel.get(i)) + for (var i = 0; i < interfacesModel.count; i++) { + print("event is for interface", interfacesModel.get(i).name) + if (deviceClass.interfaces.indexOf(interfacesModel.get(i).name) >= 0) { + actualModel.append(interfacesModel.get(i)) } } } else if (root.eventDescriptor.interfaceName !== "") { - for (var i = 0; i < eventTemplateModel.count; i++) { - if (eventTemplateModel.get(i).interfaceName === root.eventDescriptor.interfaceName) { - actualModel.append(eventTemplateModel.get(i)) - } - } + listView.model = interfacesModel.findByName(root.eventDescriptor.interfaceName).eventTypes } else { console.warn("You need to set device or interfaceName"); } } else { if (root.device) { - for (var i = 0; i < deviceClass.eventTypes.count; i++) { - actualModel.append({text: deviceClass.eventTypes.get(i).displayName, eventTypeId: deviceClass.eventTypes.get(i).id}) - } + listView.model = deviceClass.eventTypes; } } } - ListModel { - id: actualModel - ListElement { text: ""; eventTypeId: "" } - } - ListView { + id: listView anchors.fill: parent - model: actualModel delegate: ItemDelegate { width: parent.width - text: model.text + text: model.displayName onClicked: { if (header.interfacesMode) { if (root.device) { @@ -98,8 +90,8 @@ Page { } } else { if (root.device) { - var eventType = root.deviceClass.eventTypes.getEventType(model.eventTypeId); - root.eventDescriptor.eventTypeId = model.eventTypeId; + var eventType = root.deviceClass.eventTypes.getEventType(model.id); + root.eventDescriptor.eventTypeId = model.id; if (eventType.paramTypes.count > 0) { var paramsPage = pageStack.push(Qt.resolvedUrl("SelectEventDescriptorParamsPage.qml"), {eventDescriptor: root.eventDescriptor}) paramsPage.onBackPressed.connect(function() {pageStack.pop()}); diff --git a/guh-control/ui/magic/SelectThingPage.qml b/guh-control/ui/magic/SelectThingPage.qml index eefa5193..072c24fe 100644 --- a/guh-control/ui/magic/SelectThingPage.qml +++ b/guh-control/ui/magic/SelectThingPage.qml @@ -31,26 +31,23 @@ Page { } } - ListModel { - id: supportedInterfacesModel - ListElement { interfaceName: "battery"; name: "Battery powered devices" } - ListElement { interfaceName: "temperatureSensor"; name: "Temperature sensors" } - ListElement { interfaceName: "light"; name: "Lights" } + Interfaces { + id: interfacesModel } ListView { Layout.fillWidth: true Layout.fillHeight: true - model: thingButton.checked ? Engine.deviceManager.devices : supportedInterfacesModel + model: thingButton.checked ? Engine.deviceManager.devices : interfacesModel clip: true delegate: ItemDelegate { - text: model.name + text: thingButton.checked ? model.name : model.displayName width: parent.width onClicked: { if (thingButton.checked) { root.thingSelected(Engine.deviceManager.devices.get(index)) } else { - root.interfaceSelected(supportedInterfacesModel.get(index).interfaceName) + root.interfaceSelected(interfacesModel.get(index).name) } } } diff --git a/libguh-common/libguh-common.pro b/libguh-common/libguh-common.pro index cfa5a301..9d18748a 100644 --- a/libguh-common/libguh-common.pro +++ b/libguh-common/libguh-common.pro @@ -42,7 +42,9 @@ HEADERS += types/types.h \ types/stateevaluator.h \ types/statedescriptor.h \ types/paramdescriptor.h \ - types/paramdescriptors.h + types/paramdescriptors.h \ + types/interface.h \ + types/interfaces.h SOURCES += types/vendor.cpp \ types/vendors.cpp \ @@ -76,7 +78,9 @@ SOURCES += types/vendor.cpp \ types/stateevaluator.cpp \ types/statedescriptor.cpp \ types/paramdescriptor.cpp \ - types/paramdescriptors.cpp + types/paramdescriptors.cpp \ + types/interface.cpp \ + types/interfaces.cpp # install header file with relative subdirectory for(header, HEADERS) { diff --git a/libguh-common/types/eventtypes.cpp b/libguh-common/types/eventtypes.cpp index 9f1245ec..dff06f12 100644 --- a/libguh-common/types/eventtypes.cpp +++ b/libguh-common/types/eventtypes.cpp @@ -57,14 +57,14 @@ int EventTypes::rowCount(const QModelIndex &parent) const QVariant EventTypes::data(const QModelIndex &index, int role) const { - if (index.row() < 0 || index.row() >= m_eventTypes.count()) - return QVariant(); - EventType *eventType = m_eventTypes.at(index.row()); - if (role == NameRole) { - return eventType->name(); - } else if (role == IdRole) { + switch (role) { + case RoleId: return eventType->id(); + case RoleName: + return eventType->name(); + case RoleDisplayName: + return eventType->displayName(); } return QVariant(); } @@ -99,8 +99,9 @@ EventType *EventTypes::findByName(const QString &name) const QHash EventTypes::roleNames() const { QHash roles; - roles[NameRole] = "name"; - roles[IdRole] = "id"; + roles.insert(RoleId, "id"); + roles.insert(RoleName, "name"); + roles.insert(RoleDisplayName, "displayName"); return roles; } diff --git a/libguh-common/types/eventtypes.h b/libguh-common/types/eventtypes.h index 08f97718..627fd408 100644 --- a/libguh-common/types/eventtypes.h +++ b/libguh-common/types/eventtypes.h @@ -34,9 +34,10 @@ class EventTypes : public QAbstractListModel Q_PROPERTY(int count READ rowCount NOTIFY countChanged) public: - enum EventTypeRole { - NameRole = Qt::DisplayRole, - IdRole + enum Roles { + RoleId, + RoleName, + RoleDisplayName }; EventTypes(QObject *parent = 0); diff --git a/libguh-common/types/interface.cpp b/libguh-common/types/interface.cpp new file mode 100644 index 00000000..c6cbe3b4 --- /dev/null +++ b/libguh-common/types/interface.cpp @@ -0,0 +1,41 @@ +#include "interface.h" + +#include "eventtypes.h" +#include "statetypes.h" +#include "actiontypes.h" + +Interface::Interface(const QString &name, const QString &displayName, QObject *parent) : + QObject(parent), + m_name(name), + m_displayName(displayName), + m_eventTypes(new EventTypes(this)), + m_stateTypes(new StateTypes(this)), + m_actionTypes(new ActionTypes(this)) +{ + +} + +QString Interface::name() const +{ + return m_name; +} + +QString Interface::displayName() const +{ + return m_displayName; +} + +EventTypes* Interface::eventTypes() const +{ + return m_eventTypes; +} + +StateTypes* Interface::stateTypes() const +{ + return m_stateTypes; +} + +ActionTypes* Interface::actionTypes() const +{ + return m_actionTypes; +} diff --git a/libguh-common/types/interface.h b/libguh-common/types/interface.h new file mode 100644 index 00000000..55c4ddcf --- /dev/null +++ b/libguh-common/types/interface.h @@ -0,0 +1,36 @@ +#ifndef INTERFACE_H +#define INTERFACE_H + +#include + +class EventTypes; +class StateTypes; +class ActionTypes; + +class Interface : public QObject +{ + Q_OBJECT + Q_PROPERTY(QString name READ name CONSTANT) + Q_PROPERTY(QString displayName READ displayName CONSTANT) + Q_PROPERTY(EventTypes* eventTypes READ eventTypes CONSTANT) + Q_PROPERTY(StateTypes* stateTypes READ stateTypes CONSTANT) + Q_PROPERTY(ActionTypes* actionTypes READ actionTypes CONSTANT) + +public: + explicit Interface(const QString &name, const QString &displayName, QObject *parent = nullptr); + + QString name() const; + QString displayName() const; + EventTypes* eventTypes() const; + StateTypes* stateTypes() const; + ActionTypes* actionTypes() const; + +private: + QString m_name; + QString m_displayName; + EventTypes* m_eventTypes = nullptr; + StateTypes* m_stateTypes = nullptr; + ActionTypes* m_actionTypes = nullptr; +}; + +#endif // INTERFACE_H diff --git a/libguh-common/types/interfaces.cpp b/libguh-common/types/interfaces.cpp new file mode 100644 index 00000000..f7625990 --- /dev/null +++ b/libguh-common/types/interfaces.cpp @@ -0,0 +1,78 @@ +#include "interfaces.h" +#include "interface.h" + +#include "eventtypes.h" +#include "eventtype.h" + +Interfaces::Interfaces(QObject *parent) : QAbstractListModel(parent) +{ + + Interface* iface = nullptr; + EventType* ev = nullptr; + ParamType* pt = nullptr; + ParamTypes *pts = nullptr; + + iface = new Interface("battery", "Battery powered devices"); + ev = new EventType(); + pts = new ParamTypes(ev); + ev->setParamTypes(pts); + + ev->setName("batteryLevel"); + ev->setDisplayName("Battery level changed"); + pt = new ParamType("batteryLevel", QVariant::Int, 50); + pt->setMinValue(0); + pt->setMaxValue(100); + ev->paramTypes()->addParamType(pt); + iface->eventTypes()->addEventType(ev); + + ev = new EventType(); + pts = new ParamTypes(ev); + ev->setParamTypes(pts); + ev->setName("batteryCritical"); + ev->setDisplayName("Battery level critical"); + pt = new ParamType("batteryCritical", QVariant::Bool, true); + ev->paramTypes()->addParamType(pt); + iface->eventTypes()->addEventType(ev); + + m_list.append(iface); +} + +int Interfaces::rowCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent) + return m_list.count(); +} + +QVariant Interfaces::data(const QModelIndex &index, int role) const +{ + switch (role) { + case RoleName: + return m_list.at(index.row())->name(); + case RoleDisplayName: + return m_list.at(index.row())->displayName(); + } + return QVariant(); +} + +QHash Interfaces::roleNames() const +{ + QHash roles; + roles.insert(RoleName, "name"); + roles.insert(RoleDisplayName, "displayName"); + return roles; +} + +Interface *Interfaces::get(int index) const +{ + return m_list.at(index); +} + +Interface *Interfaces::findByName(const QString &name) const +{ + foreach (Interface* iface, m_list) { + if (iface->name() == name) { + return iface; + } + } + return nullptr; +} diff --git a/libguh-common/types/interfaces.h b/libguh-common/types/interfaces.h new file mode 100644 index 00000000..328043e8 --- /dev/null +++ b/libguh-common/types/interfaces.h @@ -0,0 +1,31 @@ +#ifndef INTERFACES_H +#define INTERFACES_H + +#include + +class Interface; + +class Interfaces : public QAbstractListModel +{ + Q_OBJECT + Q_PROPERTY(int count READ rowCount CONSTANT) + +public: + enum Roles { + RoleName, + RoleDisplayName + }; + explicit Interfaces(QObject *parent = nullptr); + + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant data(const QModelIndex &index, int role) const override; + QHash roleNames() const override; + + Q_INVOKABLE Interface* get(int index) const; + Q_INVOKABLE Interface* findByName(const QString &name) const; + +private: + QList m_list; +}; + +#endif // INTERFACES_H diff --git a/libguh-common/types/rule.h b/libguh-common/types/rule.h index a71fbd88..759650a4 100644 --- a/libguh-common/types/rule.h +++ b/libguh-common/types/rule.h @@ -13,7 +13,7 @@ class Rule : public QObject Q_OBJECT Q_PROPERTY(QUuid id READ id CONSTANT) Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) - Q_PROPERTY(bool enabled READ enabled NOTIFY enabledChanged) + Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged) Q_PROPERTY(bool active READ active NOTIFY activeChanged) Q_PROPERTY(EventDescriptors* eventDescriptors READ eventDescriptors CONSTANT) Q_PROPERTY(StateEvaluator* stateEvaluator READ stateEvaluator CONSTANT) @@ -46,7 +46,7 @@ signals: private: QUuid m_id; QString m_name; - bool m_enabled = false; + bool m_enabled = true; bool m_active = false; EventDescriptors *m_eventDescriptors = nullptr; StateEvaluator *m_stateEvaluator = nullptr; diff --git a/libguh-common/types/rules.cpp b/libguh-common/types/rules.cpp index 6884abda..149f3793 100644 --- a/libguh-common/types/rules.cpp +++ b/libguh-common/types/rules.cpp @@ -8,8 +8,11 @@ Rules::Rules(QObject *parent) : QAbstractListModel(parent) void Rules::clear() { + beginResetModel(); qDeleteAll(m_list); m_list.clear(); + endResetModel(); + emit countChanged(); } int Rules::rowCount(const QModelIndex &parent) const @@ -45,9 +48,11 @@ QHash Rules::roleNames() const void Rules::insert(Rule *rule) { + rule->setParent(this); beginInsertRows(QModelIndex(), m_list.count(), m_list.count()); m_list.append(rule); endInsertRows(); + emit countChanged(); } void Rules::remove(const QUuid &ruleId) @@ -57,6 +62,7 @@ void Rules::remove(const QUuid &ruleId) beginRemoveRows(QModelIndex(), i, i); m_list.takeAt(i)->deleteLater(); endRemoveRows(); + emit countChanged(); return; } } diff --git a/libguh-common/types/rules.h b/libguh-common/types/rules.h index 62347a15..693d2b60 100644 --- a/libguh-common/types/rules.h +++ b/libguh-common/types/rules.h @@ -8,6 +8,7 @@ class Rule; class Rules : public QAbstractListModel { Q_OBJECT + Q_PROPERTY(int count READ rowCount NOTIFY countChanged) public: enum Roles { RoleName, @@ -19,7 +20,7 @@ public: void clear(); - int rowCount(const QModelIndex &parent) const override; + int rowCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role) const override; QHash roleNames() const override; @@ -29,6 +30,9 @@ public: Q_INVOKABLE Rule* get(int index) const; Q_INVOKABLE Rule* getRule(const QUuid &ruleId) const; +signals: + void countChanged(); + private: QList m_list; };