initial stab on grouping things
This commit is contained in:
parent
1ab384428b
commit
37397e2c65
@ -23,6 +23,7 @@
|
|||||||
#include "devicesproxy.h"
|
#include "devicesproxy.h"
|
||||||
#include "engine.h"
|
#include "engine.h"
|
||||||
#include "tagsmanager.h"
|
#include "tagsmanager.h"
|
||||||
|
#include "types/tag.h"
|
||||||
|
|
||||||
DevicesProxy::DevicesProxy(QObject *parent) :
|
DevicesProxy::DevicesProxy(QObject *parent) :
|
||||||
QSortFilterProxyModel(parent)
|
QSortFilterProxyModel(parent)
|
||||||
@ -93,7 +94,7 @@ QString DevicesProxy::filterTagId() const
|
|||||||
|
|
||||||
void DevicesProxy::setFilterTagId(const QString &filterTag)
|
void DevicesProxy::setFilterTagId(const QString &filterTag)
|
||||||
{
|
{
|
||||||
if (m_filterTagId != filterTagId()) {
|
if (m_filterTagId != filterTag) {
|
||||||
m_filterTagId = filterTag;
|
m_filterTagId = filterTag;
|
||||||
emit filterTagIdChanged();
|
emit filterTagIdChanged();
|
||||||
invalidateFilter();
|
invalidateFilter();
|
||||||
@ -101,6 +102,21 @@ void DevicesProxy::setFilterTagId(const QString &filterTag)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString DevicesProxy::filterTagValue() const
|
||||||
|
{
|
||||||
|
return m_filterTagValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DevicesProxy::setFilterTagValue(const QString &tagValue)
|
||||||
|
{
|
||||||
|
if (m_filterTagValue != tagValue) {
|
||||||
|
m_filterTagValue = tagValue;
|
||||||
|
emit filterTagValueChanged();
|
||||||
|
invalidateFilter();
|
||||||
|
emit countChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QString DevicesProxy::filterDeviceClassId() const
|
QString DevicesProxy::filterDeviceClassId() const
|
||||||
{
|
{
|
||||||
return m_filterDeviceClassId;
|
return m_filterDeviceClassId;
|
||||||
@ -112,6 +128,22 @@ void DevicesProxy::setFilterDeviceClassId(const QString &filterDeviceClassId)
|
|||||||
m_filterDeviceClassId = filterDeviceClassId;
|
m_filterDeviceClassId = filterDeviceClassId;
|
||||||
emit filterDeviceClassIdChanged();
|
emit filterDeviceClassIdChanged();
|
||||||
invalidateFilter();
|
invalidateFilter();
|
||||||
|
emit countChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString DevicesProxy::filterDeviceId() const
|
||||||
|
{
|
||||||
|
return m_filterDeviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DevicesProxy::setFilterDeviceId(const QString &filterDeviceId)
|
||||||
|
{
|
||||||
|
if (m_filterDeviceId != filterDeviceId) {
|
||||||
|
m_filterDeviceId = filterDeviceId;
|
||||||
|
emit filterDeviceIdChanged();
|
||||||
|
invalidateFilter();
|
||||||
|
emit countChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,7 +188,7 @@ void DevicesProxy::setNameFilter(const QString &nameFilter)
|
|||||||
m_nameFilter = nameFilter;
|
m_nameFilter = nameFilter;
|
||||||
emit nameFilterChanged();
|
emit nameFilterChanged();
|
||||||
invalidateFilter();
|
invalidateFilter();
|
||||||
countChanged();
|
emit countChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,6 +233,7 @@ void DevicesProxy::setGroupByInterface(bool groupByInterface)
|
|||||||
m_groupByInterface = groupByInterface;
|
m_groupByInterface = groupByInterface;
|
||||||
emit groupByInterfaceChanged();
|
emit groupByInterfaceChanged();
|
||||||
invalidate();
|
invalidate();
|
||||||
|
emit countChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -254,12 +287,21 @@ bool DevicesProxy::filterAcceptsRow(int source_row, const QModelIndex &source_pa
|
|||||||
{
|
{
|
||||||
Device *device = getInternal(source_row);
|
Device *device = getInternal(source_row);
|
||||||
if (!m_filterTagId.isEmpty()) {
|
if (!m_filterTagId.isEmpty()) {
|
||||||
if (!m_engine->tagsManager()->tags()->findDeviceTag(device->id().toString(), m_filterTagId)) {
|
Tag *tag = m_engine->tagsManager()->tags()->findDeviceTag(device->id().toString(), m_filterTagId);
|
||||||
|
if (!tag) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!m_filterTagValue.isEmpty() && tag->value() != m_filterTagValue) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!m_filterDeviceClassId.isEmpty()) {
|
if (!m_filterDeviceClassId.isEmpty()) {
|
||||||
if (device->deviceClassId() != m_filterDeviceClassId) {
|
if (device->deviceClassId() != QUuid(m_filterDeviceClassId)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!m_filterDeviceId.isEmpty()) {
|
||||||
|
if (device->id() != QUuid(m_filterDeviceId)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -38,7 +38,9 @@ class DevicesProxy : public QSortFilterProxyModel
|
|||||||
Q_PROPERTY(Engine* engine READ engine WRITE setEngine NOTIFY engineChanged)
|
Q_PROPERTY(Engine* engine READ engine WRITE setEngine NOTIFY engineChanged)
|
||||||
Q_PROPERTY(DevicesProxy *parentProxy READ parentProxy WRITE setParentProxy NOTIFY parentProxyChanged)
|
Q_PROPERTY(DevicesProxy *parentProxy READ parentProxy WRITE setParentProxy NOTIFY parentProxyChanged)
|
||||||
Q_PROPERTY(QString filterTagId READ filterTagId WRITE setFilterTagId NOTIFY filterTagIdChanged)
|
Q_PROPERTY(QString filterTagId READ filterTagId WRITE setFilterTagId NOTIFY filterTagIdChanged)
|
||||||
|
Q_PROPERTY(QString filterTagValue READ filterTagValue WRITE setFilterTagValue NOTIFY filterTagValueChanged)
|
||||||
Q_PROPERTY(QString filterDeviceClassId READ filterDeviceClassId WRITE setFilterDeviceClassId NOTIFY filterDeviceClassIdChanged)
|
Q_PROPERTY(QString filterDeviceClassId READ filterDeviceClassId WRITE setFilterDeviceClassId NOTIFY filterDeviceClassIdChanged)
|
||||||
|
Q_PROPERTY(QString filterDeviceId READ filterDeviceId WRITE setFilterDeviceId NOTIFY filterDeviceIdChanged)
|
||||||
Q_PROPERTY(QStringList shownInterfaces READ shownInterfaces WRITE setShownInterfaces NOTIFY shownInterfacesChanged)
|
Q_PROPERTY(QStringList shownInterfaces READ shownInterfaces WRITE setShownInterfaces NOTIFY shownInterfacesChanged)
|
||||||
Q_PROPERTY(QStringList hiddenInterfaces READ hiddenInterfaces WRITE setHiddenInterfaces NOTIFY hiddenInterfacesChanged)
|
Q_PROPERTY(QStringList hiddenInterfaces READ hiddenInterfaces WRITE setHiddenInterfaces NOTIFY hiddenInterfacesChanged)
|
||||||
Q_PROPERTY(QString nameFilter READ nameFilter WRITE setNameFilter NOTIFY nameFilterChanged)
|
Q_PROPERTY(QString nameFilter READ nameFilter WRITE setNameFilter NOTIFY nameFilterChanged)
|
||||||
@ -63,9 +65,15 @@ public:
|
|||||||
QString filterTagId() const;
|
QString filterTagId() const;
|
||||||
void setFilterTagId(const QString &filterTag);
|
void setFilterTagId(const QString &filterTag);
|
||||||
|
|
||||||
|
QString filterTagValue() const;
|
||||||
|
void setFilterTagValue(const QString &tagValue);
|
||||||
|
|
||||||
QString filterDeviceClassId() const;
|
QString filterDeviceClassId() const;
|
||||||
void setFilterDeviceClassId(const QString &filterDeviceClassId);
|
void setFilterDeviceClassId(const QString &filterDeviceClassId);
|
||||||
|
|
||||||
|
QString filterDeviceId() const;
|
||||||
|
void setFilterDeviceId(const QString &filterDeviceId);
|
||||||
|
|
||||||
QStringList shownInterfaces() const;
|
QStringList shownInterfaces() const;
|
||||||
void setShownInterfaces(const QStringList &shownInterfaces);
|
void setShownInterfaces(const QStringList &shownInterfaces);
|
||||||
|
|
||||||
@ -91,7 +99,9 @@ signals:
|
|||||||
void engineChanged();
|
void engineChanged();
|
||||||
void parentProxyChanged();
|
void parentProxyChanged();
|
||||||
void filterTagIdChanged();
|
void filterTagIdChanged();
|
||||||
|
void filterTagValueChanged();
|
||||||
void filterDeviceClassIdChanged();
|
void filterDeviceClassIdChanged();
|
||||||
|
void filterDeviceIdChanged();
|
||||||
void shownInterfacesChanged();
|
void shownInterfacesChanged();
|
||||||
void hiddenInterfacesChanged();
|
void hiddenInterfacesChanged();
|
||||||
void nameFilterChanged();
|
void nameFilterChanged();
|
||||||
@ -106,7 +116,9 @@ private:
|
|||||||
Engine *m_engine = nullptr;
|
Engine *m_engine = nullptr;
|
||||||
DevicesProxy *m_parentProxy = nullptr;
|
DevicesProxy *m_parentProxy = nullptr;
|
||||||
QString m_filterTagId;
|
QString m_filterTagId;
|
||||||
|
QString m_filterTagValue;
|
||||||
QString m_filterDeviceClassId;
|
QString m_filterDeviceClassId;
|
||||||
|
QString m_filterDeviceId;
|
||||||
QStringList m_shownInterfaces;
|
QStringList m_shownInterfaces;
|
||||||
QStringList m_hiddenInterfaces;
|
QStringList m_hiddenInterfaces;
|
||||||
QString m_nameFilter;
|
QString m_nameFilter;
|
||||||
|
|||||||
@ -48,6 +48,7 @@
|
|||||||
#include "models/wirelessaccesspointsproxy.h"
|
#include "models/wirelessaccesspointsproxy.h"
|
||||||
#include "tagsmanager.h"
|
#include "tagsmanager.h"
|
||||||
#include "models/tagsproxymodel.h"
|
#include "models/tagsproxymodel.h"
|
||||||
|
#include "models/taglistmodel.h"
|
||||||
#include "types/tag.h"
|
#include "types/tag.h"
|
||||||
#include "ruletemplates/ruletemplates.h"
|
#include "ruletemplates/ruletemplates.h"
|
||||||
#include "ruletemplates/ruletemplate.h"
|
#include "ruletemplates/ruletemplate.h"
|
||||||
@ -189,6 +190,7 @@ void registerQmlTypes() {
|
|||||||
qmlRegisterUncreatableType<Tags>(uri, 1, 0, "Tags", "Get it from TagsManager");
|
qmlRegisterUncreatableType<Tags>(uri, 1, 0, "Tags", "Get it from TagsManager");
|
||||||
qmlRegisterUncreatableType<Tag>(uri, 1, 0, "Tag", "Get it from Tags");
|
qmlRegisterUncreatableType<Tag>(uri, 1, 0, "Tag", "Get it from Tags");
|
||||||
qmlRegisterType<TagsProxyModel>(uri, 1, 0, "TagsProxyModel");
|
qmlRegisterType<TagsProxyModel>(uri, 1, 0, "TagsProxyModel");
|
||||||
|
qmlRegisterType<TagListModel>(uri, 1, 0, "TagListModel");
|
||||||
|
|
||||||
qmlRegisterType<NetworkManagerController>(uri, 1, 0, "NetworkManagerController");
|
qmlRegisterType<NetworkManagerController>(uri, 1, 0, "NetworkManagerController");
|
||||||
qmlRegisterType<BluetoothDiscovery>(uri, 1, 0, "BluetoothDiscovery");
|
qmlRegisterType<BluetoothDiscovery>(uri, 1, 0, "BluetoothDiscovery");
|
||||||
|
|||||||
@ -47,6 +47,7 @@ SOURCES += \
|
|||||||
deviceclassesproxy.cpp \
|
deviceclassesproxy.cpp \
|
||||||
devicediscovery.cpp \
|
devicediscovery.cpp \
|
||||||
models/packagesfiltermodel.cpp \
|
models/packagesfiltermodel.cpp \
|
||||||
|
models/taglistmodel.cpp \
|
||||||
vendorsproxy.cpp \
|
vendorsproxy.cpp \
|
||||||
pluginsproxy.cpp \
|
pluginsproxy.cpp \
|
||||||
interfacesmodel.cpp \
|
interfacesmodel.cpp \
|
||||||
@ -109,6 +110,7 @@ HEADERS += \
|
|||||||
deviceclassesproxy.h \
|
deviceclassesproxy.h \
|
||||||
devicediscovery.h \
|
devicediscovery.h \
|
||||||
models/packagesfiltermodel.h \
|
models/packagesfiltermodel.h \
|
||||||
|
models/taglistmodel.h \
|
||||||
vendorsproxy.h \
|
vendorsproxy.h \
|
||||||
pluginsproxy.h \
|
pluginsproxy.h \
|
||||||
interfacesmodel.h \
|
interfacesmodel.h \
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
#include "types/device.h"
|
#include "types/device.h"
|
||||||
|
|
||||||
#include "devices.h"
|
#include "devices.h"
|
||||||
|
#include "devicesproxy.h"
|
||||||
|
|
||||||
InterfacesProxy::InterfacesProxy(QObject *parent): QSortFilterProxyModel(parent)
|
InterfacesProxy::InterfacesProxy(QObject *parent): QSortFilterProxyModel(parent)
|
||||||
{
|
{
|
||||||
@ -23,6 +24,7 @@ void InterfacesProxy::setShowEvents(bool showEvents)
|
|||||||
m_showEvents = showEvents;
|
m_showEvents = showEvents;
|
||||||
emit showEventsChanged();
|
emit showEventsChanged();
|
||||||
invalidateFilter();
|
invalidateFilter();
|
||||||
|
void countChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,6 +39,7 @@ void InterfacesProxy::setShowActions(bool showActions)
|
|||||||
m_showActions = showActions;
|
m_showActions = showActions;
|
||||||
emit showActionsChanged();
|
emit showActionsChanged();
|
||||||
invalidateFilter();
|
invalidateFilter();
|
||||||
|
void countChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,6 +54,7 @@ void InterfacesProxy::setShowStates(bool showStates)
|
|||||||
m_showStates = showStates;
|
m_showStates = showStates;
|
||||||
emit showStatesChanged();
|
emit showStatesChanged();
|
||||||
invalidateFilter();
|
invalidateFilter();
|
||||||
|
void countChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,7 +62,6 @@ bool InterfacesProxy::filterAcceptsRow(int source_row, const QModelIndex &source
|
|||||||
{
|
{
|
||||||
Q_UNUSED(source_parent)
|
Q_UNUSED(source_parent)
|
||||||
QString interfaceName = m_interfaces->get(source_row)->name();
|
QString interfaceName = m_interfaces->get(source_row)->name();
|
||||||
qDebug() << "filterAcceptsRow" << interfaceName << m_shownInterfaces;
|
|
||||||
if (!m_shownInterfaces.isEmpty()) {
|
if (!m_shownInterfaces.isEmpty()) {
|
||||||
if (!m_shownInterfaces.contains(interfaceName)) {
|
if (!m_shownInterfaces.contains(interfaceName)) {
|
||||||
return false;
|
return false;
|
||||||
@ -83,6 +86,24 @@ bool InterfacesProxy::filterAcceptsRow(int source_row, const QModelIndex &source
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (m_devicesProxyFilter != nullptr) {
|
||||||
|
// TODO: This could be improved *a lot* by caching interfaces in the devices model...
|
||||||
|
bool found = false;
|
||||||
|
for (int i = 0; i < m_devicesProxyFilter->rowCount(); i++) {
|
||||||
|
Device *d = m_devicesProxyFilter->get(i);
|
||||||
|
if (!d->deviceClass()) {
|
||||||
|
qWarning() << "Cannot find DeviceClass for device:" << d->id() << d->name();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (d->deviceClass()->interfaces().contains(interfaceName)) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Interface* iface = m_interfaces->get(source_row);
|
Interface* iface = m_interfaces->get(source_row);
|
||||||
if (m_showEvents) {
|
if (m_showEvents) {
|
||||||
|
|||||||
@ -4,15 +4,18 @@
|
|||||||
#include <QSortFilterProxyModel>
|
#include <QSortFilterProxyModel>
|
||||||
|
|
||||||
class Devices;
|
class Devices;
|
||||||
|
class DevicesProxy;
|
||||||
class Interface;
|
class Interface;
|
||||||
class Interfaces;
|
class Interfaces;
|
||||||
|
|
||||||
class InterfacesProxy: public QSortFilterProxyModel
|
class InterfacesProxy: public QSortFilterProxyModel
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(int count READ rowCount NOTIFY countChanged)
|
||||||
|
|
||||||
Q_PROPERTY(QStringList shownInterfaces READ shownInterfaces WRITE setShownInterfaces NOTIFY shownInterfacesChanged)
|
Q_PROPERTY(QStringList shownInterfaces READ shownInterfaces WRITE setShownInterfaces NOTIFY shownInterfacesChanged)
|
||||||
Q_PROPERTY(Devices* devicesFilter READ devicesFilter WRITE setDevicesFilter NOTIFY devicesFilterChanged)
|
Q_PROPERTY(Devices* devicesFilter READ devicesFilter WRITE setDevicesFilter NOTIFY devicesFilterChanged)
|
||||||
|
Q_PROPERTY(DevicesProxy* devicesProxyFilter READ devicesProxyFilter WRITE setDevicesProxyFilter NOTIFY devicesProxyFilterChanged)
|
||||||
Q_PROPERTY(bool showEvents READ showEvents WRITE setShowEvents NOTIFY showEventsChanged)
|
Q_PROPERTY(bool showEvents READ showEvents WRITE setShowEvents NOTIFY showEventsChanged)
|
||||||
Q_PROPERTY(bool showActions READ showActions WRITE setShowActions NOTIFY showActionsChanged)
|
Q_PROPERTY(bool showActions READ showActions WRITE setShowActions NOTIFY showActionsChanged)
|
||||||
Q_PROPERTY(bool showStates READ showStates WRITE setShowStates NOTIFY showStatesChanged)
|
Q_PROPERTY(bool showStates READ showStates WRITE setShowStates NOTIFY showStatesChanged)
|
||||||
@ -26,6 +29,9 @@ public:
|
|||||||
Devices* devicesFilter() const { return m_devicesFilter; }
|
Devices* devicesFilter() const { return m_devicesFilter; }
|
||||||
void setDevicesFilter(Devices *devices) { m_devicesFilter = devices; emit devicesFilterChanged(); invalidateFilter(); }
|
void setDevicesFilter(Devices *devices) { m_devicesFilter = devices; emit devicesFilterChanged(); invalidateFilter(); }
|
||||||
|
|
||||||
|
DevicesProxy* devicesProxyFilter() const { return m_devicesProxyFilter; }
|
||||||
|
void setDevicesProxyFilter(DevicesProxy *devicesProxy) { m_devicesProxyFilter = devicesProxy; emit devicesProxyFilterChanged(); invalidateFilter(); }
|
||||||
|
|
||||||
bool showEvents() const;
|
bool showEvents() const;
|
||||||
void setShowEvents(bool showEvents);
|
void setShowEvents(bool showEvents);
|
||||||
|
|
||||||
@ -42,14 +48,18 @@ public:
|
|||||||
signals:
|
signals:
|
||||||
void shownInterfacesChanged();
|
void shownInterfacesChanged();
|
||||||
void devicesFilterChanged();
|
void devicesFilterChanged();
|
||||||
|
void devicesProxyFilterChanged();
|
||||||
void showEventsChanged();
|
void showEventsChanged();
|
||||||
void showActionsChanged();
|
void showActionsChanged();
|
||||||
void showStatesChanged();
|
void showStatesChanged();
|
||||||
|
|
||||||
|
void countChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Interfaces *m_interfaces = nullptr;
|
Interfaces *m_interfaces = nullptr;
|
||||||
QStringList m_shownInterfaces;
|
QStringList m_shownInterfaces;
|
||||||
Devices* m_devicesFilter = nullptr;
|
Devices* m_devicesFilter = nullptr;
|
||||||
|
DevicesProxy* m_devicesProxyFilter = nullptr;
|
||||||
bool m_showEvents = false;
|
bool m_showEvents = false;
|
||||||
bool m_showActions = false;
|
bool m_showActions = false;
|
||||||
bool m_showStates = false;
|
bool m_showStates = false;
|
||||||
|
|||||||
100
libnymea-app-core/models/taglistmodel.cpp
Normal file
100
libnymea-app-core/models/taglistmodel.cpp
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
#include "taglistmodel.h"
|
||||||
|
#include "tagsproxymodel.h"
|
||||||
|
#include "types/tag.h"
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
TagListModel::TagListModel(QObject *parent) : QAbstractListModel(parent)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
TagsProxyModel *TagListModel::tagsProxy() const
|
||||||
|
{
|
||||||
|
return m_tagsProxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TagListModel::setTagsProxy(TagsProxyModel *tagsProxy)
|
||||||
|
{
|
||||||
|
if (m_tagsProxy != tagsProxy) {
|
||||||
|
m_tagsProxy = tagsProxy;
|
||||||
|
emit tagsProxyChanged();
|
||||||
|
|
||||||
|
connect(tagsProxy, &TagsProxyModel::countChanged, this, &TagListModel::update);
|
||||||
|
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int TagListModel::rowCount(const QModelIndex &parent) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(parent)
|
||||||
|
return m_list.count();
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant TagListModel::data(const QModelIndex &index, int role) const
|
||||||
|
{
|
||||||
|
switch (role) {
|
||||||
|
case RoleTagId:
|
||||||
|
return m_list.at(index.row())->tagId();
|
||||||
|
case RoleValue:
|
||||||
|
return m_list.at(index.row())->value();
|
||||||
|
}
|
||||||
|
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
QHash<int, QByteArray> TagListModel::roleNames() const
|
||||||
|
{
|
||||||
|
QHash<int, QByteArray> roles;
|
||||||
|
roles.insert(RoleTagId, "tagId");
|
||||||
|
roles.insert(RoleValue, "value");
|
||||||
|
return roles;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TagListModel::containsId(const QString &tagId)
|
||||||
|
{
|
||||||
|
foreach (Tag* t, m_list) {
|
||||||
|
if (t->tagId() == tagId) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TagListModel::containsValue(const QString &tagValue)
|
||||||
|
{
|
||||||
|
foreach (Tag* t, m_list) {
|
||||||
|
if (t->value() == tagValue) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TagListModel::update()
|
||||||
|
{
|
||||||
|
beginResetModel();
|
||||||
|
qDeleteAll(m_list);
|
||||||
|
m_list.clear();
|
||||||
|
|
||||||
|
for (int i = 0; i < m_tagsProxy->rowCount(); i++) {
|
||||||
|
Tag *tag = m_tagsProxy->get(i);
|
||||||
|
|
||||||
|
bool found = false;
|
||||||
|
foreach (Tag* existingTag, m_list) {
|
||||||
|
if (tag->tagId() == existingTag->tagId() && tag->value() == existingTag->value()) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
Tag *t = new Tag(tag->tagId(), tag->value(), this);
|
||||||
|
m_list.append(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug() << "Model populated" << m_list.count() << this;
|
||||||
|
endResetModel();
|
||||||
|
emit countChanged();
|
||||||
|
}
|
||||||
44
libnymea-app-core/models/taglistmodel.h
Normal file
44
libnymea-app-core/models/taglistmodel.h
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
#ifndef TAGLISTMODEL_H
|
||||||
|
#define TAGLISTMODEL_H
|
||||||
|
|
||||||
|
#include <QAbstractListModel>
|
||||||
|
|
||||||
|
class TagsProxyModel;
|
||||||
|
class Tag;
|
||||||
|
|
||||||
|
class TagListModel : public QAbstractListModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(int count READ rowCount NOTIFY countChanged)
|
||||||
|
Q_PROPERTY(TagsProxyModel* tagsProxy READ tagsProxy WRITE setTagsProxy NOTIFY tagsProxyChanged)
|
||||||
|
public:
|
||||||
|
enum Roles {
|
||||||
|
RoleTagId,
|
||||||
|
RoleValue
|
||||||
|
};
|
||||||
|
explicit TagListModel(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
TagsProxyModel* tagsProxy() const;
|
||||||
|
void setTagsProxy(TagsProxyModel* tagsProxy);
|
||||||
|
|
||||||
|
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
|
QVariant data(const QModelIndex &index, int role) const override;
|
||||||
|
QHash<int, QByteArray> roleNames() const override;
|
||||||
|
|
||||||
|
Q_INVOKABLE bool containsId(const QString &tagId);
|
||||||
|
Q_INVOKABLE bool containsValue(const QString &tagValue);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void countChanged();
|
||||||
|
void tagsProxyChanged();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void update();
|
||||||
|
|
||||||
|
private:
|
||||||
|
TagsProxyModel *m_tagsProxy = nullptr;
|
||||||
|
|
||||||
|
QList<Tag*> m_list;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // TAGLISTMODEL_H
|
||||||
@ -94,17 +94,18 @@ bool TagsProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_
|
|||||||
Q_UNUSED(source_parent)
|
Q_UNUSED(source_parent)
|
||||||
Tag *tag = m_tags->get(source_row);
|
Tag *tag = m_tags->get(source_row);
|
||||||
if (!m_filterTagId.isEmpty()) {
|
if (!m_filterTagId.isEmpty()) {
|
||||||
if (tag->tagId() != m_filterTagId) {
|
QRegExp exp(m_filterTagId);
|
||||||
|
if (!exp.exactMatch(tag->tagId())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!m_filterDeviceId.isEmpty()) {
|
if (!m_filterDeviceId.isEmpty()) {
|
||||||
if (tag->deviceId() != m_filterDeviceId) {
|
if (QUuid(tag->deviceId()) != QUuid(m_filterDeviceId)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!m_filterRuleId.isEmpty()) {
|
if (!m_filterRuleId.isEmpty()) {
|
||||||
if (tag->ruleId() != m_filterRuleId) {
|
if (QUuid(tag->ruleId()) != QUuid(m_filterRuleId)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -115,7 +116,7 @@ bool TagsProxyModel::lessThan(const QModelIndex &source_left, const QModelIndex
|
|||||||
{
|
{
|
||||||
QString leftValue = m_tags->get(source_left.row())->value();
|
QString leftValue = m_tags->get(source_left.row())->value();
|
||||||
QString rightValue = m_tags->get(source_right.row())->value();
|
QString rightValue = m_tags->get(source_right.row())->value();
|
||||||
bool okLeft, okRight;;
|
bool okLeft, okRight;
|
||||||
qlonglong leftAsNumber = leftValue.toLongLong(&okLeft);
|
qlonglong leftAsNumber = leftValue.toLongLong(&okLeft);
|
||||||
qlonglong rightAsNumber = rightValue.toLongLong(&okRight);
|
qlonglong rightAsNumber = rightValue.toLongLong(&okRight);
|
||||||
if (okLeft && okRight) {
|
if (okLeft && okRight) {
|
||||||
|
|||||||
@ -42,6 +42,7 @@ signals:
|
|||||||
void filterTagIdChanged();
|
void filterTagIdChanged();
|
||||||
void filterDeviceIdChanged();
|
void filterDeviceIdChanged();
|
||||||
void filterRuleIdChanged();
|
void filterRuleIdChanged();
|
||||||
|
void groupSameTagsChanged();
|
||||||
void countChanged();
|
void countChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@ -17,10 +17,17 @@ QString TagsManager::nameSpace() const
|
|||||||
|
|
||||||
void TagsManager::init()
|
void TagsManager::init()
|
||||||
{
|
{
|
||||||
|
m_busy = true;
|
||||||
|
emit busyChanged();
|
||||||
m_tags->clear();
|
m_tags->clear();
|
||||||
m_jsonClient->sendCommand("Tags.GetTags", this, "getTagsReply");
|
m_jsonClient->sendCommand("Tags.GetTags", this, "getTagsReply");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TagsManager::busy() const
|
||||||
|
{
|
||||||
|
return m_busy;
|
||||||
|
}
|
||||||
|
|
||||||
Tags *TagsManager::tags() const
|
Tags *TagsManager::tags() const
|
||||||
{
|
{
|
||||||
return m_tags;
|
return m_tags;
|
||||||
@ -83,13 +90,16 @@ void TagsManager::handleTagsNotification(const QVariantMap ¶ms)
|
|||||||
|
|
||||||
QString notification = params.value("notification").toString();
|
QString notification = params.value("notification").toString();
|
||||||
if (notification == "Tags.TagAdded") {
|
if (notification == "Tags.TagAdded") {
|
||||||
addTagInternal(tagMap);
|
Tag *tag = unpackTag(tagMap);
|
||||||
|
if (tag) {
|
||||||
|
m_tags->addTag(tag);
|
||||||
|
}
|
||||||
|
|
||||||
} else if (notification == "Tags.TagRemoved") {
|
} else if (notification == "Tags.TagRemoved") {
|
||||||
for (int i = 0; i < m_tags->rowCount(); i++) {
|
for (int i = 0; i < m_tags->rowCount(); i++) {
|
||||||
Tag* tag = m_tags->get(i);
|
Tag* tag = m_tags->get(i);
|
||||||
if (tagMap.value("deviceId").toString() == tag->deviceId() &&
|
if (tagMap.value("deviceId").toUuid() == tag->deviceId() &&
|
||||||
tagMap.value("ruleId").toString() == tag->ruleId() &&
|
tagMap.value("ruleId").toUuid() == tag->ruleId() &&
|
||||||
tagMap.value("tagId").toString() == tag->tagId()) {
|
tagMap.value("tagId").toString() == tag->tagId()) {
|
||||||
m_tags->removeTag(tag);
|
m_tags->removeTag(tag);
|
||||||
return;
|
return;
|
||||||
@ -99,8 +109,8 @@ void TagsManager::handleTagsNotification(const QVariantMap ¶ms)
|
|||||||
qDebug() << "tag value changed";
|
qDebug() << "tag value changed";
|
||||||
for (int i = 0; i < m_tags->rowCount(); i++) {
|
for (int i = 0; i < m_tags->rowCount(); i++) {
|
||||||
Tag* tag = m_tags->get(i);
|
Tag* tag = m_tags->get(i);
|
||||||
if (tagMap.value("deviceId").toString() == tag->deviceId() &&
|
if (tagMap.value("deviceId").toUuid() == tag->deviceId() &&
|
||||||
tagMap.value("ruleId").toString() == tag->ruleId() &&
|
tagMap.value("ruleId").toUuid() == tag->ruleId() &&
|
||||||
tagMap.value("tagId").toString() == tag->tagId()) {
|
tagMap.value("tagId").toString() == tag->tagId()) {
|
||||||
qDebug() << "Found tag";
|
qDebug() << "Found tag";
|
||||||
tag->setValue(tagMap.value("value").toString());
|
tag->setValue(tagMap.value("value").toString());
|
||||||
@ -111,10 +121,18 @@ void TagsManager::handleTagsNotification(const QVariantMap ¶ms)
|
|||||||
|
|
||||||
void TagsManager::getTagsReply(const QVariantMap ¶ms)
|
void TagsManager::getTagsReply(const QVariantMap ¶ms)
|
||||||
{
|
{
|
||||||
|
QList<Tag*> tags;
|
||||||
foreach (const QVariant &tagVariant, params.value("params").toMap().value("tags").toList()) {
|
foreach (const QVariant &tagVariant, params.value("params").toMap().value("tags").toList()) {
|
||||||
addTagInternal(tagVariant.toMap());
|
qDebug() << "aDDING TAG";
|
||||||
|
Tag *tag = unpackTag(tagVariant.toMap());
|
||||||
|
if (tag) {
|
||||||
|
tags.append(tag);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
emit tagsChanged();
|
m_tags->addTags(tags);
|
||||||
|
|
||||||
|
m_busy = false;
|
||||||
|
emit busyChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TagsManager::addTagReply(const QVariantMap ¶ms)
|
void TagsManager::addTagReply(const QVariantMap ¶ms)
|
||||||
@ -127,7 +145,7 @@ void TagsManager::removeTagReply(const QVariantMap ¶ms)
|
|||||||
qDebug() << "RemoveTag reply" << params;
|
qDebug() << "RemoveTag reply" << params;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TagsManager::addTagInternal(const QVariantMap &tagMap)
|
Tag* TagsManager::unpackTag(const QVariantMap &tagMap)
|
||||||
{
|
{
|
||||||
QString deviceId = tagMap.value("deviceId").toString();
|
QString deviceId = tagMap.value("deviceId").toString();
|
||||||
QString ruleId = tagMap.value("ruleId").toString();
|
QString ruleId = tagMap.value("ruleId").toString();
|
||||||
@ -143,8 +161,8 @@ void TagsManager::addTagInternal(const QVariantMap &tagMap)
|
|||||||
} else {
|
} else {
|
||||||
qWarning() << "Invalid tag. Neither deviceId nor ruleId are set. Skipping...";
|
qWarning() << "Invalid tag. Neither deviceId nor ruleId are set. Skipping...";
|
||||||
tag->deleteLater();
|
tag->deleteLater();
|
||||||
return;
|
return nullptr;
|
||||||
}
|
}
|
||||||
// qDebug() << "adding tag" << tag->tagId() << tag->value();
|
// qDebug() << "adding tag" << tag->tagId() << tag->value();
|
||||||
m_tags->addTag(tag);
|
return tag;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,13 +9,15 @@
|
|||||||
class TagsManager : public JsonHandler
|
class TagsManager : public JsonHandler
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
Q_PROPERTY(Tags* tags READ tags NOTIFY tagsChanged)
|
Q_PROPERTY(Tags* tags READ tags CONSTANT)
|
||||||
|
Q_PROPERTY(bool busy READ busy NOTIFY busyChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit TagsManager(JsonRpcClient *jsonClient, QObject *parent = nullptr);
|
explicit TagsManager(JsonRpcClient *jsonClient, QObject *parent = nullptr);
|
||||||
QString nameSpace() const override;
|
QString nameSpace() const override;
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
|
bool busy() const;
|
||||||
|
|
||||||
Tags* tags() const;
|
Tags* tags() const;
|
||||||
|
|
||||||
@ -25,7 +27,7 @@ public:
|
|||||||
Q_INVOKABLE void untagRule(const QString &ruleId, const QString &tagId);
|
Q_INVOKABLE void untagRule(const QString &ruleId, const QString &tagId);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void tagsChanged();
|
void busyChanged();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void handleTagsNotification(const QVariantMap ¶ms);
|
void handleTagsNotification(const QVariantMap ¶ms);
|
||||||
@ -34,11 +36,12 @@ private slots:
|
|||||||
void removeTagReply(const QVariantMap ¶ms);
|
void removeTagReply(const QVariantMap ¶ms);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void addTagInternal(const QVariantMap &tagMap);
|
Tag *unpackTag(const QVariantMap &tagMap);
|
||||||
|
|
||||||
JsonRpcClient *m_jsonClient = nullptr;
|
JsonRpcClient *m_jsonClient = nullptr;
|
||||||
|
|
||||||
Tags *m_tags = nullptr;
|
Tags *m_tags = nullptr;
|
||||||
|
bool m_busy = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // TAGSMANAGER_H
|
#endif // TAGSMANAGER_H
|
||||||
|
|||||||
@ -89,6 +89,11 @@ Interfaces::Interfaces(QObject *parent) : QAbstractListModel(parent)
|
|||||||
tr("Daylight"),
|
tr("Daylight"),
|
||||||
tr("Daylight changed"));
|
tr("Daylight changed"));
|
||||||
|
|
||||||
|
addInterface("lightsensor", tr("Light intensity sensors"));
|
||||||
|
addStateType("lightsensor", "lightIntensity", QVariant::Bool, false,
|
||||||
|
tr("Light intensity"),
|
||||||
|
tr("Light intensity changed"));
|
||||||
|
|
||||||
addInterface("evcharger", tr("EV charger"));
|
addInterface("evcharger", tr("EV charger"));
|
||||||
addStateType("evcharger", "power", QVariant::Bool, true,
|
addStateType("evcharger", "power", QVariant::Bool, true,
|
||||||
tr("Charging"),
|
tr("Charging"),
|
||||||
|
|||||||
@ -10,22 +10,22 @@ Tag::Tag(const QString &tagId, const QString &value, QObject *parent):
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Tag::deviceId() const
|
QUuid Tag::deviceId() const
|
||||||
{
|
{
|
||||||
return m_deviceId;
|
return m_deviceId;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tag::setDeviceId(const QString &deviceId)
|
void Tag::setDeviceId(const QUuid &deviceId)
|
||||||
{
|
{
|
||||||
m_deviceId = deviceId;
|
m_deviceId = deviceId;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Tag::ruleId() const
|
QUuid Tag::ruleId() const
|
||||||
{
|
{
|
||||||
return m_ruleId;
|
return m_ruleId;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tag::setRuleId(const QString &ruleId)
|
void Tag::setRuleId(const QUuid &ruleId)
|
||||||
{
|
{
|
||||||
m_ruleId = ruleId;
|
m_ruleId = ruleId;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,23 +2,24 @@
|
|||||||
#define TAG_H
|
#define TAG_H
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
#include <QUuid>
|
||||||
|
|
||||||
class Tag : public QObject
|
class Tag : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
Q_PROPERTY(QString deviceId READ deviceId CONSTANT)
|
Q_PROPERTY(QUuid deviceId READ deviceId CONSTANT)
|
||||||
Q_PROPERTY(QString ruleId READ ruleId CONSTANT)
|
Q_PROPERTY(QUuid ruleId READ ruleId CONSTANT)
|
||||||
Q_PROPERTY(QString tagId READ tagId CONSTANT)
|
Q_PROPERTY(QString tagId READ tagId CONSTANT)
|
||||||
Q_PROPERTY(QString value READ value NOTIFY valueChanged)
|
Q_PROPERTY(QString value READ value NOTIFY valueChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit Tag(const QString &tagId, const QString &value, QObject *parent = nullptr);
|
explicit Tag(const QString &tagId, const QString &value, QObject *parent = nullptr);
|
||||||
|
|
||||||
QString deviceId() const;
|
QUuid deviceId() const;
|
||||||
void setDeviceId(const QString &deviceId);
|
void setDeviceId(const QUuid &deviceId);
|
||||||
|
|
||||||
QString ruleId() const;
|
QUuid ruleId() const;
|
||||||
void setRuleId(const QString &ruleId);
|
void setRuleId(const QUuid &ruleId);
|
||||||
|
|
||||||
QString tagId() const;
|
QString tagId() const;
|
||||||
|
|
||||||
@ -29,8 +30,8 @@ signals:
|
|||||||
void valueChanged();
|
void valueChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString m_deviceId;
|
QUuid m_deviceId;
|
||||||
QString m_ruleId;
|
QUuid m_ruleId;
|
||||||
QString m_tagId;
|
QString m_tagId;
|
||||||
QString m_value;
|
QString m_value;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -46,6 +46,19 @@ void Tags::addTag(Tag *tag)
|
|||||||
beginInsertRows(QModelIndex(), m_list.count(), m_list.count());
|
beginInsertRows(QModelIndex(), m_list.count(), m_list.count());
|
||||||
m_list.append(tag);
|
m_list.append(tag);
|
||||||
endInsertRows();
|
endInsertRows();
|
||||||
|
qDebug() << "tags count changed";
|
||||||
|
emit countChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Tags::addTags(QList<Tag *> tags)
|
||||||
|
{
|
||||||
|
beginInsertRows(QModelIndex(), m_list.count(), m_list.count() + tags.count() - 1);
|
||||||
|
foreach (Tag *tag, tags) {
|
||||||
|
tag->setParent(this);
|
||||||
|
connect(tag, &Tag::valueChanged, this, &Tags::tagValueChanged);
|
||||||
|
}
|
||||||
|
m_list.append(tags);
|
||||||
|
endInsertRows();
|
||||||
emit countChanged();
|
emit countChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,7 +81,7 @@ Tag *Tags::get(int index) const
|
|||||||
return m_list.at(index);
|
return m_list.at(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
Tag *Tags::findDeviceTag(const QString &deviceId, const QString &tagId) const
|
Tag *Tags::findDeviceTag(const QUuid &deviceId, const QString &tagId) const
|
||||||
{
|
{
|
||||||
foreach (Tag *tag, m_list) {
|
foreach (Tag *tag, m_list) {
|
||||||
if (tag->deviceId() == deviceId && tag->tagId() == tagId) {
|
if (tag->deviceId() == deviceId && tag->tagId() == tagId) {
|
||||||
|
|||||||
@ -25,11 +25,12 @@ public:
|
|||||||
QHash<int, QByteArray> roleNames() const override;
|
QHash<int, QByteArray> roleNames() const override;
|
||||||
|
|
||||||
void addTag(Tag *tag);
|
void addTag(Tag *tag);
|
||||||
|
void addTags(QList<Tag*> tags);
|
||||||
void removeTag(Tag *tag);
|
void removeTag(Tag *tag);
|
||||||
|
|
||||||
Tag* get(int index) const;
|
Tag* get(int index) const;
|
||||||
|
|
||||||
Q_INVOKABLE Tag* findDeviceTag(const QString &deviceId, const QString &tagId) const;
|
Q_INVOKABLE Tag* findDeviceTag(const QUuid &deviceId, const QString &tagId) const;
|
||||||
Q_INVOKABLE Tag* findRuleTag(const QString &ruleId, const QString &tagId) const;
|
Q_INVOKABLE Tag* findRuleTag(const QString &ruleId, const QString &tagId) const;
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
|
|||||||
@ -212,5 +212,6 @@
|
|||||||
<file>ui/images/browser/MediaBrowserIconNapster.svg</file>
|
<file>ui/images/browser/MediaBrowserIconNapster.svg</file>
|
||||||
<file>ui/images/browser/MediaBrowserIconSoundCloud.svg</file>
|
<file>ui/images/browser/MediaBrowserIconSoundCloud.svg</file>
|
||||||
<file>ui/images/browser/MediaBrowserIconDeezer.svg</file>
|
<file>ui/images/browser/MediaBrowserIconDeezer.svg</file>
|
||||||
|
<file>ui/images/view-grid-symbolic.svg</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|||||||
@ -197,5 +197,7 @@
|
|||||||
<file>ui/magic/NewMagicPage.qml</file>
|
<file>ui/magic/NewMagicPage.qml</file>
|
||||||
<file>ui/components/WebViewWrapper.qml</file>
|
<file>ui/components/WebViewWrapper.qml</file>
|
||||||
<file>ui/magic/NewScenePage.qml</file>
|
<file>ui/magic/NewScenePage.qml</file>
|
||||||
|
<file>ui/mainviews/GroupsView.qml</file>
|
||||||
|
<file>ui/grouping/GroupPage.qml</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|||||||
@ -79,6 +79,10 @@ Page {
|
|||||||
}
|
}
|
||||||
tabEntryComponent.createObject(tabBar, {text: qsTr("Things"), iconSource: "../images/share.svg", pageIndex: pi++})
|
tabEntryComponent.createObject(tabBar, {text: qsTr("Things"), iconSource: "../images/share.svg", pageIndex: pi++})
|
||||||
tabEntryComponent.createObject(tabBar, {text: qsTr("Scenes"), iconSource: "../images/slideshow.svg", pageIndex: pi++})
|
tabEntryComponent.createObject(tabBar, {text: qsTr("Scenes"), iconSource: "../images/slideshow.svg", pageIndex: pi++})
|
||||||
|
if (engine.jsonRpcClient.ensureServerVersion(1.6)) {
|
||||||
|
tabEntryComponent.createObject(tabBar, {text: qsTr("Groups"), iconSource: "../images/view-grid-symbolic.svg", pageIndex: pi++})
|
||||||
|
}
|
||||||
|
|
||||||
root.tabsReady = true
|
root.tabsReady = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -292,6 +296,13 @@ Page {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GroupsView {
|
||||||
|
id: groupsView
|
||||||
|
property string title: qsTr("My groups" + count);
|
||||||
|
width: swipeView.width
|
||||||
|
height: swipeView.height
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
|
|||||||
@ -86,7 +86,7 @@ Item {
|
|||||||
Component.onCompleted: ready = true
|
Component.onCompleted: ready = true
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.margins: parent.margins
|
anchors.margins: parent ? parent.margins : 0
|
||||||
source: ready && width > 0 && height > 0 && icon.name ? icon.name : ""
|
source: ready && width > 0 && height > 0 && icon.name ? icon.name : ""
|
||||||
sourceSize {
|
sourceSize {
|
||||||
width: width
|
width: width
|
||||||
@ -100,7 +100,7 @@ Item {
|
|||||||
id: colorizedImage
|
id: colorizedImage
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.margins: parent.margins
|
anchors.margins: parent ? parent.margins : 0
|
||||||
visible: active && image.status == Image.Ready
|
visible: active && image.status == Image.Ready
|
||||||
|
|
||||||
// Whether or not a color has been set.
|
// Whether or not a color has been set.
|
||||||
|
|||||||
@ -70,6 +70,13 @@ Page {
|
|||||||
iconSource: Qt.binding(function() { return favoritesProxy.count === 0 ? "../images/starred.svg" : "../images/non-starred.svg"}),
|
iconSource: Qt.binding(function() { return favoritesProxy.count === 0 ? "../images/starred.svg" : "../images/non-starred.svg"}),
|
||||||
functionName: "toggleFavorite"
|
functionName: "toggleFavorite"
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
thingMenu.addItem(menuEntryComponent.createObject(thingMenu,
|
||||||
|
{
|
||||||
|
text: qsTr("Grouping"),
|
||||||
|
iconSource: "../images/view-grid-symbolic.svg",
|
||||||
|
functionName: "addToGroup"
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function openDeviceMagicPage() {
|
function openDeviceMagicPage() {
|
||||||
@ -85,6 +92,12 @@ Page {
|
|||||||
engine.tagsManager.untagDevice(root.device.id, "favorites")
|
engine.tagsManager.untagDevice(root.device.id, "favorites")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
function addToGroup() {
|
||||||
|
// engine.tagsManager.tagDevice(root.device.id, "group", "My group 1")
|
||||||
|
var dialog = addToGroupDialog.createObject(root)
|
||||||
|
dialog.open();
|
||||||
|
}
|
||||||
|
|
||||||
function openThingSettingsPage() {
|
function openThingSettingsPage() {
|
||||||
pageStack.push(Qt.resolvedUrl("../thingconfiguration/ConfigureThingPage.qml"), {device: root.device})
|
pageStack.push(Qt.resolvedUrl("../thingconfiguration/ConfigureThingPage.qml"), {device: root.device})
|
||||||
}
|
}
|
||||||
@ -101,6 +114,65 @@ Page {
|
|||||||
onTriggered: thingMenu[functionName]()
|
onTriggered: thingMenu[functionName]()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: addToGroupDialog
|
||||||
|
MeaDialog {
|
||||||
|
title: qsTr("Configure groups")
|
||||||
|
headerIcon: "../images/view-grid-symbolic.svg"
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
TextField {
|
||||||
|
id: newGroupdTextField
|
||||||
|
Layout.fillWidth: true
|
||||||
|
placeholderText: qsTr("New group")
|
||||||
|
}
|
||||||
|
Button {
|
||||||
|
text: qsTr("OK")
|
||||||
|
enabled: newGroupdTextField.displayText.length > 0 && !groupTags.containsId("group-" + newGroupdTextField.displayText)
|
||||||
|
onClicked: {
|
||||||
|
engine.tagsManager.tagDevice(root.device.id, "group-" + newGroupdTextField.text, 1000)
|
||||||
|
newGroupdTextField.text = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ListView {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
height: 200
|
||||||
|
|
||||||
|
model: TagListModel {
|
||||||
|
id: groupTags
|
||||||
|
tagsProxy: TagsProxyModel {
|
||||||
|
tags: engine.tagsManager.tags
|
||||||
|
filterTagId: "group-.*"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delegate: CheckDelegate {
|
||||||
|
width: parent.width
|
||||||
|
text: model.tagId.substring(6)
|
||||||
|
checked: innerProxy.count > 0
|
||||||
|
onClicked: {
|
||||||
|
if (innerProxy.count == 0) {
|
||||||
|
engine.tagsManager.tagDevice(root.device.id, model.tagId, 1000)
|
||||||
|
} else {
|
||||||
|
engine.tagsManager.untagDevice(root.device.id, model.tagId, model.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DevicesProxy {
|
||||||
|
id: innerProxy
|
||||||
|
engine: _engine
|
||||||
|
filterTagId: model.tagId
|
||||||
|
filterDeviceId: root.device.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
|
|||||||
38
nymea-app/ui/grouping/GroupPage.qml
Normal file
38
nymea-app/ui/grouping/GroupPage.qml
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import QtQuick 2.5
|
||||||
|
import QtQuick.Controls 2.1
|
||||||
|
import QtQuick.Controls.Material 2.1
|
||||||
|
import QtQuick.Layouts 1.1
|
||||||
|
import Nymea 1.0
|
||||||
|
import "../components"
|
||||||
|
|
||||||
|
Page {
|
||||||
|
id: root
|
||||||
|
header: NymeaHeader {
|
||||||
|
text: root.groupTag.substring(6)
|
||||||
|
onBackPressed: pageStack.pop()
|
||||||
|
}
|
||||||
|
|
||||||
|
property string groupTag
|
||||||
|
|
||||||
|
|
||||||
|
DevicesProxy {
|
||||||
|
id: devicesInGroup
|
||||||
|
engine: _engine
|
||||||
|
filterTagId: root.groupTag
|
||||||
|
}
|
||||||
|
|
||||||
|
InterfacesProxy {
|
||||||
|
id: interfacesInGroup
|
||||||
|
devicesProxyFilter: devicesInGroup
|
||||||
|
showStates: true
|
||||||
|
}
|
||||||
|
|
||||||
|
ListView {
|
||||||
|
anchors.fill: parent
|
||||||
|
model: devicesInGroup
|
||||||
|
delegate: Label {
|
||||||
|
text: model.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
179
nymea-app/ui/images/view-grid-symbolic.svg
Normal file
179
nymea-app/ui/images/view-grid-symbolic.svg
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="96"
|
||||||
|
height="96"
|
||||||
|
id="svg4874"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.91+devel r"
|
||||||
|
viewBox="0 0 96 96.000001"
|
||||||
|
sodipodi:docname="view-grid-symbolic.svg">
|
||||||
|
<defs
|
||||||
|
id="defs4876" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="5.6199994"
|
||||||
|
inkscape:cx="-33.300718"
|
||||||
|
inkscape:cy="62.909239"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="g4780"
|
||||||
|
showgrid="true"
|
||||||
|
showborder="true"
|
||||||
|
fit-margin-top="0"
|
||||||
|
fit-margin-left="0"
|
||||||
|
fit-margin-right="0"
|
||||||
|
fit-margin-bottom="0"
|
||||||
|
inkscape:snap-bbox="true"
|
||||||
|
inkscape:bbox-paths="true"
|
||||||
|
inkscape:bbox-nodes="true"
|
||||||
|
inkscape:snap-bbox-edge-midpoints="true"
|
||||||
|
inkscape:snap-bbox-midpoints="true"
|
||||||
|
inkscape:object-paths="true"
|
||||||
|
inkscape:snap-intersection-paths="true"
|
||||||
|
inkscape:object-nodes="true"
|
||||||
|
inkscape:snap-smooth-nodes="true"
|
||||||
|
inkscape:snap-midpoints="true"
|
||||||
|
inkscape:snap-object-midpoints="true"
|
||||||
|
inkscape:snap-center="true"
|
||||||
|
showguides="true"
|
||||||
|
inkscape:guide-bbox="true"
|
||||||
|
inkscape:snap-global="true">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid5451"
|
||||||
|
empspacing="8" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="1,0"
|
||||||
|
position="8,-8.0000001"
|
||||||
|
id="guide4063" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="1,0"
|
||||||
|
position="4,-8.0000001"
|
||||||
|
id="guide4065" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="0,1"
|
||||||
|
position="-8,88.000001"
|
||||||
|
id="guide4067" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="0,1"
|
||||||
|
position="-8,92.000001"
|
||||||
|
id="guide4069" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="0,1"
|
||||||
|
position="104,4"
|
||||||
|
id="guide4071" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="0,1"
|
||||||
|
position="-5,8.0000001"
|
||||||
|
id="guide4073" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="1,0"
|
||||||
|
position="92,-8.0000001"
|
||||||
|
id="guide4075" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="1,0"
|
||||||
|
position="88,-8.0000001"
|
||||||
|
id="guide4077" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="0,1"
|
||||||
|
position="-8,84.000001"
|
||||||
|
id="guide4074" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="1,0"
|
||||||
|
position="12,-8.0000001"
|
||||||
|
id="guide4076" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="0,1"
|
||||||
|
position="-5,12"
|
||||||
|
id="guide4078" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="1,0"
|
||||||
|
position="84,-9.0000001"
|
||||||
|
id="guide4080" />
|
||||||
|
<sodipodi:guide
|
||||||
|
position="48,-8.0000001"
|
||||||
|
orientation="1,0"
|
||||||
|
id="guide4170" />
|
||||||
|
<sodipodi:guide
|
||||||
|
position="-8,48"
|
||||||
|
orientation="0,1"
|
||||||
|
id="guide4172" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata4879">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(67.857146,-78.50504)">
|
||||||
|
<g
|
||||||
|
transform="matrix(0,-1,-1,0,373.50506,516.50504)"
|
||||||
|
id="g4845"
|
||||||
|
style="display:inline">
|
||||||
|
<g
|
||||||
|
inkscape:export-ydpi="90"
|
||||||
|
inkscape:export-xdpi="90"
|
||||||
|
inkscape:export-filename="next01.png"
|
||||||
|
transform="matrix(-0.9996045,0,0,1,575.94296,-611.00001)"
|
||||||
|
id="g4778"
|
||||||
|
inkscape:label="Layer 1">
|
||||||
|
<g
|
||||||
|
transform="matrix(-1,0,0,1,575.99999,611)"
|
||||||
|
id="g4780"
|
||||||
|
style="display:inline">
|
||||||
|
<rect
|
||||||
|
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:none;stroke:none;stroke-width:4;marker:none;enable-background:accumulate"
|
||||||
|
id="rect4782"
|
||||||
|
width="96.037987"
|
||||||
|
height="96"
|
||||||
|
x="-438.00244"
|
||||||
|
y="345.36221"
|
||||||
|
transform="scale(-1,1)" />
|
||||||
|
<path
|
||||||
|
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:none;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4.00079107;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||||
|
d="m 429.99805,433.36328 -2,0 -34.01367,0 0,-36.00195 36.01367,0 0,36.00195 z m -4,-4.00195 0,-27.99805 -28.01172,0 0,27.99805 28.01172,0 z"
|
||||||
|
id="rect4201"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:none;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4.00079155;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||||
|
d="m 429.99805,389.36133 -2,0 -34.01367,0 0,-36 36.01367,0 0,36 z m -4,-4 0,-27.99805 -28.01172,0 0,27.99805 28.01172,0 z"
|
||||||
|
id="rect4203"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:none;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4.00079155;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||||
|
d="m 385.98242,433.36328 -2,0 -34.01562,0 0,-36.00195 36.01562,0 0,36.00195 z m -4.00195,-4.00195 0,-27.99805 -28.01172,0 0,27.99805 28.01172,0 z"
|
||||||
|
id="rect4205"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:none;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4.00079155;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||||
|
d="m 385.98242,389.36133 -2,0 -34.01562,0 0,-36 36.01562,0 0,36 z m -4.00195,-4 0,-27.99805 -28.01172,0 0,27.99805 28.01172,0 z"
|
||||||
|
id="rect4207"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 10 KiB |
354
nymea-app/ui/mainviews/GroupsView.qml
Normal file
354
nymea-app/ui/mainviews/GroupsView.qml
Normal file
@ -0,0 +1,354 @@
|
|||||||
|
import QtQuick 2.9
|
||||||
|
import QtQuick.Controls 2.2
|
||||||
|
import QtQuick.Layouts 1.3
|
||||||
|
import Nymea 1.0
|
||||||
|
import QtQuick.Controls.Material 2.2
|
||||||
|
import "../components"
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
readonly property int count: groupsGridView.count
|
||||||
|
|
||||||
|
GridView {
|
||||||
|
id: groupsGridView
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: app.margins / 2
|
||||||
|
|
||||||
|
readonly property int minTileWidth: 180
|
||||||
|
readonly property int minTileHeight: 180
|
||||||
|
readonly property int tilesPerRow: root.width / minTileWidth
|
||||||
|
|
||||||
|
model: TagListModel {
|
||||||
|
tagsProxy: TagsProxyModel {
|
||||||
|
tags: engine.tagsManager.tags
|
||||||
|
filterTagId: "group-.*"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cellWidth: width / tilesPerRow
|
||||||
|
cellHeight: cellWidth
|
||||||
|
|
||||||
|
delegate: Item {
|
||||||
|
id: groupDelegate
|
||||||
|
width: groupsGridView.cellWidth
|
||||||
|
height: groupsGridView.cellHeight
|
||||||
|
|
||||||
|
Pane {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: app.margins / 2
|
||||||
|
Material.elevation: 2
|
||||||
|
padding: 0
|
||||||
|
|
||||||
|
DevicesProxy {
|
||||||
|
id: devicesInGroup
|
||||||
|
engine: _engine
|
||||||
|
filterTagId: model.tagId
|
||||||
|
filterTagValue: model.value
|
||||||
|
}
|
||||||
|
|
||||||
|
InterfacesProxy {
|
||||||
|
id: controlsInGroup
|
||||||
|
shownInterfaces: ["light", "simpleclosable"]
|
||||||
|
devicesProxyFilter: devicesInGroup
|
||||||
|
showStates: true
|
||||||
|
showActions: true
|
||||||
|
}
|
||||||
|
InterfacesProxy {
|
||||||
|
id: sensorsInGroup
|
||||||
|
shownInterfaces: ["temperaturesensor", "lightsensor", "presencesensor"]
|
||||||
|
devicesProxyFilter: devicesInGroup
|
||||||
|
showStates: true
|
||||||
|
}
|
||||||
|
|
||||||
|
contentItem: ItemDelegate {
|
||||||
|
padding: 0
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
pageStack.push(Qt.resolvedUrl("../grouping/GroupPage.qml"), {groupTag: model.tagId})
|
||||||
|
}
|
||||||
|
|
||||||
|
contentItem: ColumnLayout {
|
||||||
|
Rectangle {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: 30
|
||||||
|
color: Qt.rgba(app.foregroundColor.r, app.foregroundColor.g, app.foregroundColor.b, .05)
|
||||||
|
Label {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors { leftMargin: app.margins; rightMargin: app.margins }
|
||||||
|
text: model.tagId.substring(6)
|
||||||
|
elide: Text.ElideRight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Item {
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: controlsInGroup
|
||||||
|
delegate: Loader {
|
||||||
|
id: controlLoader
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.leftMargin: app.margins / 2
|
||||||
|
Layout.rightMargin: app.margins / 2
|
||||||
|
sourceComponent: {
|
||||||
|
switch (model.name) {
|
||||||
|
case "simpleclosable":
|
||||||
|
return closableDelegate
|
||||||
|
case "light":
|
||||||
|
return lightDelegate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Binding {
|
||||||
|
target: controlLoader.item
|
||||||
|
property: "devices"
|
||||||
|
value: devicesInGroup
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Item {
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: app.iconSize * 1.2
|
||||||
|
Layout.alignment: Qt.AlignRight
|
||||||
|
color: Qt.rgba(app.foregroundColor.r, app.foregroundColor.g, app.foregroundColor.b, 0.05)
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: sensorsInGroup
|
||||||
|
delegate: Row {
|
||||||
|
ColorIcon {
|
||||||
|
height: app.iconSize * .8
|
||||||
|
width: height
|
||||||
|
name: app.interfaceToIcon(model.name)
|
||||||
|
color: app.interfaceToColor(model.name)
|
||||||
|
}
|
||||||
|
DevicesProxy {
|
||||||
|
id: innerProxy
|
||||||
|
engine: _engine
|
||||||
|
parentProxy: devicesInGroup
|
||||||
|
shownInterfaces: [model.name]
|
||||||
|
}
|
||||||
|
|
||||||
|
Led {
|
||||||
|
visible: ["presencesensor"].indexOf(model.name) >= 0
|
||||||
|
state: {
|
||||||
|
var stateName = null
|
||||||
|
switch (model.name) {
|
||||||
|
case "presencesensor":
|
||||||
|
stateName = "isPresent"
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!stateName) {
|
||||||
|
return "off";
|
||||||
|
}
|
||||||
|
var ret = false;
|
||||||
|
for (var i = 0; i < innerProxy.count; i++) {
|
||||||
|
ret |= innerProxy.get(i).states.getState(innerProxy.get(i).deviceClass.stateTypes.findByName(stateName).id).value
|
||||||
|
}
|
||||||
|
return ret ? "on" : "off";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
text: {
|
||||||
|
var stateName = null;
|
||||||
|
switch (model.name) {
|
||||||
|
case "temperaturesensor":
|
||||||
|
stateName = "temperature";
|
||||||
|
break;
|
||||||
|
case "lightsensor":
|
||||||
|
stateName = "lightIntensity"
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!stateName) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
var ret = 0
|
||||||
|
for (var i = 0; i < innerProxy.count; i++) {
|
||||||
|
ret += innerProxy.get(i).states.getState(innerProxy.get(i).deviceClass.stateTypes.findByName(stateName).id).value
|
||||||
|
}
|
||||||
|
return (ret / innerProxy.count).toFixed(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: lightDelegate
|
||||||
|
RowLayout {
|
||||||
|
property var devices
|
||||||
|
|
||||||
|
DevicesProxy {
|
||||||
|
id: lights
|
||||||
|
engine: _engine
|
||||||
|
parentProxy: devices
|
||||||
|
shownInterfaces: ["light"]
|
||||||
|
}
|
||||||
|
|
||||||
|
DevicesProxy {
|
||||||
|
id: dimmableLights
|
||||||
|
engine: _engine
|
||||||
|
parentProxy: devices
|
||||||
|
shownInterfaces: ["dimmablelight"]
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
text: qsTr("Lighting")
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: slider.height
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
visible: dimmableLights.count == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
Slider {
|
||||||
|
id: slider
|
||||||
|
from: 0
|
||||||
|
to: 100
|
||||||
|
visible: dimmableLights.count > 0
|
||||||
|
value: {
|
||||||
|
var median = 0
|
||||||
|
var count = 0;
|
||||||
|
for (var i = 0; i < dimmableLights.count; i++) {
|
||||||
|
var device = dimmableLights.get(i);
|
||||||
|
var brightnessId = device.deviceClass.stateTypes.findByName("brightness").id
|
||||||
|
median += device.states.getState(brightnessId).value
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
return median / count;
|
||||||
|
}
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
onPressedChanged: {
|
||||||
|
for (var i = 0; i < dimmableLights.count; i++) {
|
||||||
|
var device = dimmableLights.get(i);
|
||||||
|
var brightnessId = device.deviceClass.actionTypes.findByName("brightness").id
|
||||||
|
engine.deviceManager.executeAction(device.id, brightnessId, [{paramTypeId: brightnessId, value: value}]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ColorIcon {
|
||||||
|
Layout.preferredHeight: app.iconSize
|
||||||
|
Layout.preferredWidth: app.iconSize
|
||||||
|
name: isOn ? "../images/light-on.svg" : "../images/light-off.svg"
|
||||||
|
color: isOn ? app.accentColor : keyColor
|
||||||
|
|
||||||
|
property bool isOn: {
|
||||||
|
for (var i = 0; i < lights.count; i++) {
|
||||||
|
var device = lights.get(i)
|
||||||
|
var powerId = device.deviceClass.stateTypes.findByName("power").id
|
||||||
|
if (device.states.getState(powerId).value === true) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: {
|
||||||
|
for (var i = 0; i < lights.count; i++) {
|
||||||
|
var device = lights.get(i)
|
||||||
|
var powerId = device.deviceClass.stateTypes.findByName("power").id
|
||||||
|
engine.deviceManager.executeAction(device.id, powerId, [{paramTypeId: powerId, value: !parent.isOn}])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: closableDelegate
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
|
||||||
|
property var devices: null
|
||||||
|
DevicesProxy {
|
||||||
|
id: simpleClosables
|
||||||
|
engine: _engine
|
||||||
|
parentProxy: devices
|
||||||
|
shownInterfaces: ["simpleclosable"]
|
||||||
|
}
|
||||||
|
DevicesProxy {
|
||||||
|
id: closables
|
||||||
|
engine: _engine
|
||||||
|
parentProxy: devices
|
||||||
|
shownInterfaces: ["closable"]
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemDelegate {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: app.iconSize
|
||||||
|
|
||||||
|
ColorIcon {
|
||||||
|
height: parent.height
|
||||||
|
width: height
|
||||||
|
anchors.centerIn: parent
|
||||||
|
name: Qt.resolvedUrl("../images/up.svg")
|
||||||
|
}
|
||||||
|
onClicked: {
|
||||||
|
for (var i = 0; i < simpleClosables.count; i++) {
|
||||||
|
var device = simpleClosables.get(i)
|
||||||
|
var openId = device.deviceClass.actionTypes.findByName("open").id
|
||||||
|
engine.deviceManager.executeAction(device.id, openId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ItemDelegate {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: app.iconSize
|
||||||
|
visible: closables.count > 0
|
||||||
|
|
||||||
|
ColorIcon {
|
||||||
|
height: parent.height
|
||||||
|
width: height
|
||||||
|
anchors.centerIn: parent
|
||||||
|
name: Qt.resolvedUrl("../images/media-playback-stop.svg")
|
||||||
|
}
|
||||||
|
onClicked: {
|
||||||
|
for (var i = 0; i < closables.count; i++) {
|
||||||
|
var device = closables.get(i)
|
||||||
|
var openId = device.deviceClass.actionTypes.findByName("stop").id
|
||||||
|
engine.deviceManager.executeAction(device.id, openId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ItemDelegate {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: app.iconSize
|
||||||
|
|
||||||
|
ColorIcon {
|
||||||
|
height: parent.height
|
||||||
|
width: height
|
||||||
|
anchors.centerIn: parent
|
||||||
|
name: Qt.resolvedUrl("../images/down.svg")
|
||||||
|
}
|
||||||
|
onClicked: {
|
||||||
|
for (var i = 0; i < simpleClosables.count; i++) {
|
||||||
|
var device = simpleClosables.get(i)
|
||||||
|
var closeId = device.deviceClass.actionTypes.findByName("close").id
|
||||||
|
engine.deviceManager.executeAction(device.id, closeId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user