Initial work on the device browser

This commit is contained in:
Michael Zanetti 2019-07-04 18:40:51 +02:00
parent ef2f213a6b
commit 9dfde053ca
16 changed files with 407 additions and 0 deletions

View File

@ -21,6 +21,8 @@
#include "devicemanager.h"
#include "engine.h"
#include "jsonrpc/jsontypes.h"
#include "types/browseritems.h"
#include "types/browseritem.h"
#include <QMetaEnum>
DeviceManager::DeviceManager(JsonRpcClient* jsonclient, QObject *parent) :
@ -425,3 +427,62 @@ int DeviceManager::executeAction(const QUuid &deviceId, const QUuid &actionTypeI
return m_jsonClient->sendCommand("Actions.ExecuteAction", p, this, "executeActionResponse");
}
BrowserItems *DeviceManager::browseDevice(const QUuid &deviceId, const QString &nodeId)
{
QVariantMap params;
params.insert("deviceId", deviceId.toString());
params.insert("nodeId", nodeId);
int id = m_jsonClient->sendCommand("Devices.BrowseDevice", params, this, "browseDeviceResponse");
// Intentionally not parented. The caller takes ownership and needs to destroy when not needed any more.
BrowserItems *itemModel = new BrowserItems();
itemModel->setBusy(true);
QPointer<BrowserItems> itemModelPtr(itemModel);
m_browsingRequests.insert(id, itemModelPtr);
return itemModel;
}
void DeviceManager::browseDeviceResponse(const QVariantMap &params)
{
qDebug() << "Browsing response:" << qUtf8Printable(QJsonDocument::fromVariant(params).toJson(QJsonDocument::Indented));
int id = params.value("id").toInt();
if (!m_browsingRequests.contains(id)) {
qWarning() << "Received a browsing reply for an id we don't know.";
return;
}
QPointer<BrowserItems> itemModel = m_browsingRequests.take(id);
if (!itemModel) {
qDebug() << "BrowserItems model seems to have disappeared. Discarding browsing result.";
return;
}
foreach (const QVariant &itemVariant, params.value("params").toMap().value("items").toList()) {
QVariantMap itemMap = itemVariant.toMap();
BrowserItem *item = new BrowserItem(itemMap.value("id").toString(), this);
item->setDisplayName(itemMap.value("displayName").toString());
item->setDescription(itemMap.value("description").toString());
item->setThumbnail(itemMap.value("thumbnail").toString());
item->setExecutable(itemMap.value("executable").toBool());
item->setBrowsable(itemMap.value("browsable").toBool());
itemModel->addBrowserItem(item);
}
itemModel->setBusy(false);
}
void DeviceManager::executeBrowserItem(const QUuid &deviceId, const QString &nodeId)
{
QVariantMap params;
params.insert("deviceId", deviceId);
params.insert("nodeId", nodeId);
m_jsonClient->sendCommand("Devices.ExecuteBrowserItem", params, this, "executeBrowserItemResponse");
}
void DeviceManager::executeBrowserItemResponse(const QVariantMap &params)
{
qDebug() << "Execute Browser Item finished" << params;
}

View File

@ -30,6 +30,7 @@
#include "types/plugins.h"
#include "jsonrpc/jsonhandler.h"
#include "jsonrpc/jsonrpcclient.h"
class BrowserItems;
class DeviceManager : public JsonHandler
{
@ -73,6 +74,8 @@ public:
Q_INVOKABLE void reconfigureDevice(const QUuid &deviceId, const QVariantList &deviceParams);
Q_INVOKABLE void reconfigureDiscoveredDevice(const QUuid &deviceId, const QUuid &deviceDescriptorId);
Q_INVOKABLE int executeAction(const QUuid &deviceId, const QUuid &actionTypeId, const QVariantList &params = QVariantList());
Q_INVOKABLE BrowserItems* browseDevice(const QUuid &deviceId, const QString &nodeId = QString());
Q_INVOKABLE void executeBrowserItem(const QUuid &deviceId, const QString &nodeId);
private:
Q_INVOKABLE void notificationReceived(const QVariantMap &data);
@ -89,6 +92,8 @@ private:
Q_INVOKABLE void editDeviceResponse(const QVariantMap &params);
Q_INVOKABLE void executeActionResponse(const QVariantMap &params);
Q_INVOKABLE void reconfigureDeviceResponse(const QVariantMap &params);
Q_INVOKABLE void browseDeviceResponse(const QVariantMap &params);
Q_INVOKABLE void executeBrowserItemResponse(const QVariantMap &params);
public slots:
void savePluginConfig(const QUuid &pluginId);
@ -117,6 +122,8 @@ private:
JsonRpcClient *m_jsonClient = nullptr;
QHash<int, QPointer<BrowserItems> > m_browsingRequests;
};
#endif // DEVICEMANAGER_H

View File

@ -75,6 +75,7 @@ DeviceClass *JsonTypes::unpackDeviceClass(const QVariantMap &deviceClassMap, QOb
deviceClass->setDisplayName(deviceClassMap.value("displayName").toString());
deviceClass->setId(deviceClassMap.value("id").toUuid());
deviceClass->setVendorId(deviceClassMap.value("vendorId").toUuid());
deviceClass->setBrowsable(deviceClassMap.value("browsable").toBool());
QVariantList createMethodsList = deviceClassMap.value("createMethods").toList();
QStringList createMethods;
foreach (QVariant method, createMethodsList) {

View File

@ -31,6 +31,8 @@
#include "types/statedescriptor.h"
#include "types/stateevaluator.h"
#include "types/stateevaluators.h"
#include "types/browseritems.h"
#include "types/browseritem.h"
#include "models/logsmodel.h"
#include "models/logsmodelng.h"
#include "models/valuelogsproxymodel.h"
@ -109,6 +111,9 @@ void registerQmlTypes() {
qmlRegisterUncreatableType<State>(uri, 1, 0, "State", "Can't create this in QML. Get it from the States.");
qmlRegisterUncreatableType<States>(uri, 1, 0, "States", "Can't create this in QML. Get it from the Device.");
qmlRegisterUncreatableType<BrowserItems>(uri, 1, 0, "BrowserItems", "Can't create this in QML. Get it from DeviceManager.");
qmlRegisterUncreatableType<BrowserItem>(uri, 1, 0, "BrowserItem", "Can't create this in QML. Get it from BroweserItems.");
qmlRegisterUncreatableType<Vendor>(uri, 1, 0, "Vendor", "Can't create this in QML. Get it from the Vendors.");
qmlRegisterUncreatableType<Vendors>(uri, 1, 0, "Vendors", "Can't create this in QML. Get it from the DeviceManager.");
qmlRegisterType<VendorsProxy>(uri, 1, 0, "VendorsProxy");

View File

@ -8,6 +8,8 @@ QT -= gui
QT += network
HEADERS += \
types/browseritem.h \
types/browseritems.h \
types/networkdevice.h \
types/networkdevices.h \
types/package.h \
@ -62,6 +64,8 @@ HEADERS += \
types/wirelessaccesspoints.h \
SOURCES += \
types/browseritem.cpp \
types/browseritems.cpp \
types/networkdevice.cpp \
types/networkdevices.cpp \
types/package.cpp \

View File

@ -0,0 +1,63 @@
#include "browseritem.h"
BrowserItem::BrowserItem(const QString &id, QObject *parent):
QObject(parent),
m_id(id)
{
}
QString BrowserItem::id() const
{
return m_id;
}
QString BrowserItem::displayName() const
{
return m_displayName;
}
void BrowserItem::setDisplayName(const QString &displayName)
{
m_displayName = displayName;
}
QString BrowserItem::description() const
{
return m_description;
}
void BrowserItem::setDescription(const QString &description)
{
m_description = description;
}
QString BrowserItem::thumbnail() const
{
return m_thumbnail;
}
void BrowserItem::setThumbnail(const QString &thumbnail)
{
m_thumbnail = thumbnail;
}
bool BrowserItem::executable() const
{
return m_executable;
}
void BrowserItem::setExecutable(bool executable)
{
m_executable = executable;
}
bool BrowserItem::browsable() const
{
return m_browsable;
}
void BrowserItem::setBrowsable(bool browsable)
{
m_browsable = browsable;
}

View File

@ -0,0 +1,46 @@
#ifndef BROWSERITEM_H
#define BROWSERITEM_H
#include <QObject>
#include <QUuid>
class BrowserItem : public QObject
{
Q_OBJECT
Q_PROPERTY(QUuid id READ id CONSTANT)
Q_PROPERTY(QString displayName READ displayName CONSTANT)
Q_PROPERTY(QString description READ description CONSTANT)
Q_PROPERTY(QString thumbnail READ thumbnail CONSTANT)
Q_PROPERTY(bool executable READ executable CONSTANT)
Q_PROPERTY(bool browsable READ browsable CONSTANT)
public:
explicit BrowserItem(const QString &id, QObject *parent = nullptr);
QString id() const;
QString displayName() const;
void setDisplayName(const QString &displayName);
QString description() const;
void setDescription(const QString &description);
QString thumbnail() const;
void setThumbnail(const QString &thumbnail);
bool executable() const;
void setExecutable(bool executable);
bool browsable() const;
void setBrowsable(bool browsable);
private:
QString m_id;
QString m_displayName;
QString m_description;
QString m_thumbnail;
bool m_executable = false;
bool m_browsable = false;
};
#endif // BROWSERITEM_H

View File

@ -0,0 +1,73 @@
#include "browseritems.h"
#include "browseritem.h"
#include <QDebug>
BrowserItems::BrowserItems(QObject *parent): QAbstractListModel(parent)
{
}
BrowserItems::~BrowserItems()
{
qDebug() << "Deleting BrowserItems";
}
bool BrowserItems::busy() const
{
return m_busy;
}
int BrowserItems::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return m_list.count();
}
QVariant BrowserItems::data(const QModelIndex &index, int role) const
{
switch (role) {
case RoleId:
return m_list.at(index.row())->id();
case RoleDisplayName:
return m_list.at(index.row())->displayName();
case RoleDescription:
return m_list.at(index.row())->description();
case RoleThumbnail:
return m_list.at(index.row())->thumbnail();
case RoleExecutable:
return m_list.at(index.row())->executable();
case RoleBrowsable:
return m_list.at(index.row())->browsable();
}
return QVariant();
}
QHash<int, QByteArray> BrowserItems::roleNames() const
{
QHash<int, QByteArray> roles;
roles.insert(RoleId, "id");
roles.insert(RoleDisplayName, "displayName");
roles.insert(RoleDescription, "description");
roles.insert(RoleThumbnail, "thumbnail");
roles.insert(RoleExecutable, "executable");
roles.insert(RoleBrowsable, "browsable");
return roles;
}
void BrowserItems::addBrowserItem(BrowserItem *browserItem)
{
browserItem->setParent(this);
beginInsertRows(QModelIndex(), m_list.count(), m_list.count());
m_list.append(browserItem);
endInsertRows();
emit countChanged();
}
void BrowserItems::setBusy(bool busy)
{
if (m_busy != busy) {
m_busy = busy;
emit busyChanged();
}
}

View File

@ -0,0 +1,50 @@
#ifndef BROWSERITEMS_H
#define BROWSERITEMS_H
#include <QAbstractListModel>
class BrowserItem;
class BrowserItems: public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY(int count READ rowCount NOTIFY countChanged)
Q_PROPERTY(bool busy READ busy NOTIFY busyChanged)
public:
enum Roles {
RoleId,
RoleDisplayName,
RoleDescription,
RoleThumbnail,
RoleBrowsable,
RoleExecutable
};
Q_ENUM(Roles)
explicit BrowserItems(QObject *parent = nullptr);
virtual ~BrowserItems() override;
bool busy() const;
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role) const override;
virtual QHash<int, QByteArray> roleNames() const override;
virtual void addBrowserItem(BrowserItem *browserItem);
void setBusy(bool busy);
// Q_INVOKABLE virtual BrowserItem* get(int index) const;
// Q_INVOKABLE virtual BrowserItem* getBrowserItem(const QString &itemId);
// void clear();
signals:
void countChanged();
void busyChanged();
protected:
bool m_busy = false;
QList<BrowserItem*> m_list;
};
#endif // BROWSERITEMS_H

View File

@ -167,6 +167,16 @@ QString DeviceClass::baseInterface() const
}
bool DeviceClass::browsable() const
{
return m_browsable;
}
void DeviceClass::setBrowsable(bool browsable)
{
m_browsable = browsable;
}
ParamTypes *DeviceClass::paramTypes() const
{
return m_paramTypes;

View File

@ -46,6 +46,7 @@ class DeviceClass : public QObject
Q_PROPERTY(SetupMethod setupMethod READ setupMethod CONSTANT)
Q_PROPERTY(QStringList interfaces READ interfaces CONSTANT)
Q_PROPERTY(QString baseInterface READ baseInterface CONSTANT)
Q_PROPERTY(bool browsable READ browsable CONSTANT)
Q_PROPERTY(ParamTypes *paramTypes READ paramTypes NOTIFY paramTypesChanged)
Q_PROPERTY(ParamTypes *settingsTypes READ settingsTypes NOTIFY settingsTypesChanged)
Q_PROPERTY(ParamTypes *discoveryParamTypes READ discoveryParamTypes NOTIFY discoveryParamTypesChanged)
@ -91,6 +92,9 @@ public:
QString baseInterface() const;
bool browsable() const;
void setBrowsable(bool browsable);
ParamTypes *paramTypes() const;
void setParamTypes(ParamTypes *paramTypes);
@ -120,6 +124,7 @@ private:
QStringList m_createMethods;
SetupMethod m_setupMethod;
QStringList m_interfaces;
bool m_browsable = false;
ParamTypes *m_paramTypes = nullptr;
ParamTypes *m_settingsTypes = nullptr;

View File

@ -181,5 +181,6 @@
<file>ui/images/lock-closed.svg</file>
<file>ui/images/lock-open.svg</file>
<file>ui/images/system-update.svg</file>
<file>ui/images/folder-symbolic.svg</file>
</qresource>
</RCC>

View File

@ -184,5 +184,6 @@
<file>ui/components/UpdateRunningOverlay.qml</file>
<file>ui/connection/SetupWizard.qml</file>
<file>ui/system/NetworkSettingsPage.qml</file>
<file>ui/devicepages/DeviceBrowserPage.qml</file>
</qresource>
</RCC>

View File

@ -0,0 +1,55 @@
import QtQuick 2.5
import QtQuick.Controls 2.1
import QtQuick.Layouts 1.1
import Nymea 1.0
import "../components"
Page {
id: root
header: GuhHeader {
text: qsTr("Browse %1").arg(root.device.name)
onBackPressed: pageStack.pop()
}
property Device device: null
property string nodeId: ""
Component.onCompleted: {
d.model = engine.deviceManager.browseDevice(root.device.id, root.nodeId);
}
QtObject {
id: d
property BrowserItems model: null
}
ListView {
id: listView
anchors.fill: parent
model: d.model
delegate: MeaListItemDelegate {
width: parent.width
text: model.displayName
progressive: model.browsable
subText: model.description
prominentSubText: false
iconName: model.thumbnail
onClicked: {
print("clicked:", model.id)
if (model.executable) {
engine.deviceManager.executeBrowserItem(root.device.id, model.id)
} else if (model.browsable) {
pageStack.push(Qt.resolvedUrl("DeviceBrowserPage.qml"), {device: root.device, nodeId: model.id})
}
}
}
BusyIndicator {
anchors.centerIn: parent
running: listView.model.busy
visible: running
}
}
}

View File

@ -18,6 +18,14 @@ Page {
text: device.name
onBackPressed: pageStack.pop()
HeaderButton {
imageSource: "../images/folder-symbolic.svg"
visible: root.deviceClass.browsable
onClicked: {
pageStack.push(Qt.resolvedUrl("DeviceBrowserPage.qml"), {device: root.device})
}
}
HeaderButton {
imageSource: "../images/navigation-menu.svg"
onClicked: thingMenu.open();

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg id="svg4874" width="96" height="96" version="1.1" viewBox="0 0 96 96" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<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/>
</cc:Work>
</rdf:RDF>
</metadata>
<g id="layer1" transform="translate(67.857 -78.505)">
<rect id="rect4782" transform="rotate(90)" x="78.505" y="-28.143" width="96" height="96" style="color:#000000;fill:none"/>
<path id="path4643" d="m-47.869 86.504-0.01172 2e-3c-5.0328 0.05818-8.7136-0.12027-11.725 1.541-1.5055 0.83064-2.6968 2.2356-3.3555 3.9902-0.65866 1.7547-0.89648 3.8364-0.89648 6.4668v54.002c0 2.6304 0.23782 4.7121 0.89648 6.4668 0.65866 1.7546 1.85 3.1596 3.3555 3.9902 3.011 1.6613 6.6918 1.4848 11.725 1.543h0.01172 56.023 0.011719c5.0328-0.0582 8.7136 0.11832 11.725-1.543 1.5055-0.83064 2.6968-2.2356 3.3555-3.9902 0.65866-1.7547 0.89648-3.8364 0.89648-6.4668v-38c0-2.6333-0.24451-4.7263-0.91016-6.4883-0.66565-1.762-1.8593-3.1729-3.3691-4.0117-3.0197-1.6776-6.7207-1.5-11.721-1.5h-46c-5 0-8.701-0.17761-11.721 1.5-1.5098 0.8388-2.7035 2.2497-3.3691 4.0117-0.66565 1.762-0.91016 3.855-0.91016 6.4883v40h4v-40c0-2.3667 0.25549-4.0257 0.65234-5.0762 0.39685-1.0505 0.82821-1.5146 1.5684-1.9258 1.4803-0.82239 4.7793-0.99805 9.7793-0.99805h46c5 0 8.299 0.17566 9.7793 0.99805 0.74015 0.41119 1.1715 0.87528 1.5684 1.9258 0.39685 1.0505 0.65234 2.7095 0.65234 5.0762v38c0 2.3696-0.25037 4.0209-0.64062 5.0606-0.39025 1.0396-0.80933 1.4898-1.543 1.8945-1.4645 0.80804-4.7782 0.98616-9.8164 1.0449h-55.977-0.02344c-5.0383-0.0588-8.3519-0.23688-9.8164-1.0449-0.73364-0.40478-1.1508-0.85491-1.541-1.8945-0.39025-1.0396-0.64258-2.691-0.64258-5.0606v-54.002c0-2.3696 0.25232-4.0209 0.64258-5.0605 0.39025-1.0396 0.80738-1.4898 1.541-1.8945 1.4645-0.80804 4.7782-0.98616 9.8164-1.0449l20.172 2e-3 6 6 33.828-2e-3v-4l-32.172 2e-3 -6-6z" style="color-rendering:auto;color:#000000;dominant-baseline:auto;fill:#808080;font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;image-rendering:auto;isolation:auto;mix-blend-mode:normal;shape-padding:0;shape-rendering:auto;solid-color:#000000;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB