diff options
author | Javier S. Pedro <maemo@javispedro.com> | 2012-08-09 01:53:38 +0200 |
---|---|---|
committer | Javier S. Pedro <maemo@javispedro.com> | 2012-08-09 01:53:38 +0200 |
commit | 3aa62b0543d978c1a01c5cf05a898fd8d805c44b (patch) | |
tree | 84ebdd8d94728375cd21457d8f5773f46ee0dcc7 | |
parent | 081aa7b760986092377be7f62cac3bdee7400874 (diff) | |
download | sowatch-3aa62b0543d978c1a01c5cf05a898fd8d805c44b.tar.gz sowatch-3aa62b0543d978c1a01c5cf05a898fd8d805c44b.zip |
new watch scanning ui
-rw-r--r-- | metawatch/metawatchscanner.cpp | 2 | ||||
-rw-r--r-- | sowatchd/daemon.xml | 4 | ||||
-rw-r--r-- | sowatchui/main.cpp | 16 | ||||
-rw-r--r-- | sowatchui/qml/MainPage.qml | 79 | ||||
-rw-r--r-- | sowatchui/qml/NewWatchSheet.qml | 43 | ||||
-rw-r--r-- | sowatchui/qml/WatchPage.qml | 36 | ||||
-rw-r--r-- | sowatchui/qml/main.qml | 22 | ||||
-rw-r--r-- | sowatchui/scannerproxy.cc | 26 | ||||
-rw-r--r-- | sowatchui/scannerproxy.h | 58 | ||||
-rw-r--r-- | sowatchui/scanwatchesmodel.cc | 102 | ||||
-rw-r--r-- | sowatchui/scanwatchesmodel.h | 49 | ||||
-rw-r--r-- | sowatchui/sowatchui.pro | 17 | ||||
-rw-r--r-- | sowatchui/watchesmodel.cc | 136 | ||||
-rw-r--r-- | sowatchui/watchesmodel.h | 40 |
14 files changed, 553 insertions, 77 deletions
diff --git a/metawatch/metawatchscanner.cpp b/metawatch/metawatchscanner.cpp index 418500c..99ccc93 100644 --- a/metawatch/metawatchscanner.cpp +++ b/metawatch/metawatchscanner.cpp @@ -34,7 +34,7 @@ void MetaWatchScanner::handleDiscoveredService(const QBluetoothServiceInfo &info QVariantMap foundInfo; foundInfo["address"] = dev.address().toString(); foundInfo["name"] = deviceName; - qDebug() << "metawatch bluetooth scan found" << deviceName; + qDebug() << "metawatch bluetooth scan found:" << deviceName; if (deviceName.contains("Digital", Qt::CaseInsensitive)) { foundInfo["driver"] = QString("metawatch-digital"); emit watchFound(foundInfo); diff --git a/sowatchd/daemon.xml b/sowatchd/daemon.xml index 0a08913..2d21592 100644 --- a/sowatchd/daemon.xml +++ b/sowatchd/daemon.xml @@ -6,5 +6,9 @@ <arg name="status" type="s" direction="out" /> </method> <method name="Terminate" /> + <signal name="WatchStatusChanged"> + <arg name="watch" type="s" /> + <arg name="status" type="s" /> + </signal> </interface> </node> diff --git a/sowatchui/main.cpp b/sowatchui/main.cpp index 54a65fa..f306fa9 100644 --- a/sowatchui/main.cpp +++ b/sowatchui/main.cpp @@ -1,11 +1,27 @@ #include <QtGui/QApplication> #include "qmlapplicationviewer.h" +#include <sowatch.h> + +#include "watchesmodel.h" +#include "scanwatchesmodel.h" + +static sowatch::Registry *registry; +static WatchesModel *watches; +static ScanWatchesModel *watchScanner; + Q_DECL_EXPORT int main(int argc, char *argv[]) { QScopedPointer<QApplication> app(createApplication(argc, argv)); QScopedPointer<QmlApplicationViewer> viewer(QmlApplicationViewer::create()); + registry = sowatch::Registry::registry(); + watches = new WatchesModel(app.data()); + watchScanner = new ScanWatchesModel(app.data()); + + viewer->rootContext()->setContextProperty("watches", watches); + viewer->rootContext()->setContextProperty("watchScanner", watchScanner); + viewer->setOrientation(QmlApplicationViewer::ScreenOrientationAuto); viewer->setMainQmlFile(QLatin1String("qml/main.qml")); viewer->showExpanded(); diff --git a/sowatchui/qml/MainPage.qml b/sowatchui/qml/MainPage.qml index a7ba7d7..b660161 100644 --- a/sowatchui/qml/MainPage.qml +++ b/sowatchui/qml/MainPage.qml @@ -1,67 +1,38 @@ import QtQuick 1.1 -import com.nokia.meego 1.0 +import com.nokia.meego 1.1 +import com.nokia.extras 1.1 Page { id: mainPage - tools: commonTools + anchors.leftMargin: UiConstants.DefaultMargin + anchors.rightMargin: UiConstants.DefaultMargin - ListModel { - id: testModel - ListElement { - name: "one" - } - ListElement { - name: "two" + tools: ToolBarLayout { + ToolIcon { + platformIconId: "toolbar-add" + anchors.right: parent.right + onClicked: newWatchSheet.open() } } - Flickable { - anchors.fill: parent - contentWidth: mainPage.width - contentHeight: mainColumn.height + 100 - - Column { - id: mainColumn + NewWatchSheet { + id: newWatchSheet + } - width: mainPage.width - height: childrenRect.height - spacing: 8 + ListView { + id: watchesListView + anchors.fill: parent + model: watches - ListView { - model: testModel - width: mainPage.width - height: 50*model.count - clip: true - interactive: false - delegate: Rectangle { - height: 50 - width: mainPage.width - color: "red" - Text { - text: name - } - } - } - ListView { - model: testModel - width: mainPage.width - height: 50*model.count - clip: true - interactive: false - delegate: Rectangle { - height: 50 - width: mainPage.width - color: "green" - Text { - text: name - } - } - } - Button { - anchors.horizontalCenter: parent.horizontalCenter - text: qsTr("Refresh") - onClicked: Sowatch.refreshWatches() - } + delegate: ListDelegate { + Image { + source: "image://theme/icon-m-common-drilldown-arrow" + (theme.inverted ? "-inverse" : "") + anchors.right: parent.right; + anchors.verticalCenter: parent.verticalCenter + } } } + ScrollDecorator { + flickableItem: watchesListView + } } diff --git a/sowatchui/qml/NewWatchSheet.qml b/sowatchui/qml/NewWatchSheet.qml new file mode 100644 index 0000000..1028bd5 --- /dev/null +++ b/sowatchui/qml/NewWatchSheet.qml @@ -0,0 +1,43 @@ +import QtQuick 1.1 +import com.nokia.meego 1.1 +import com.nokia.extras 1.1 + +Sheet { + id: sheet + anchors.margins: UiConstants.DefaultMargin + + rejectButtonText: qsTr("Cancel") + + title: BusyIndicator { + anchors.centerIn: parent; + running: watchScanner.active + } + + Binding { + target: watchScanner + property: "enabled" + value: sheet.status === DialogStatus.Open + } + + content: ListView { + id: listView + anchors.fill: parent + anchors.margins: UiConstants.DefaultMargin + + flickableDirection: Flickable.VerticalFlick + + model: watchScanner + + delegate: ListDelegate { + onClicked: { + watches.addFoundWatch(object); + close(); + accepted(); + } + } + + ScrollDecorator { + flickableItem: listView + } + } +} diff --git a/sowatchui/qml/WatchPage.qml b/sowatchui/qml/WatchPage.qml new file mode 100644 index 0000000..fb7011c --- /dev/null +++ b/sowatchui/qml/WatchPage.qml @@ -0,0 +1,36 @@ +import QtQuick 1.1 +import com.nokia.meego 1.1 +import com.nokia.extras 1.1 + +Page { + id: watchPage + anchors.leftMargin: UiConstants.DefaultMargin + anchors.rightMargin: UiConstants.DefaultMargin + + tools: ToolBarLayout { + ToolIcon { + platformIconId: "toolbar-back" + anchors.left: parent.left + onClicked: pageStack.pop() + } + } + + ListView { + id: emptyListView + anchors.fill: parent + model: ListModel { + + } + + delegate: ListDelegate { + Image { + source: "image://theme/icon-m-common-drilldown-arrow" + (theme.inverted ? "-inverse" : "") + anchors.right: parent.right; + anchors.verticalCenter: parent.verticalCenter + } + } + } + ScrollDecorator { + flickableItem: watchesListView + } +} diff --git a/sowatchui/qml/main.qml b/sowatchui/qml/main.qml index eb4c081..ca838a2 100644 --- a/sowatchui/qml/main.qml +++ b/sowatchui/qml/main.qml @@ -1,5 +1,5 @@ import QtQuick 1.1 -import com.nokia.meego 1.0 +import com.nokia.meego 1.1 PageStackWindow { id: appWindow @@ -10,30 +10,14 @@ PageStackWindow { id: mainPage } - ToolBarLayout { - id: commonTools - visible: true - ToolIcon { - platformIconId: "toolbar-view-menu" - anchors.right: (parent === undefined) ? undefined : parent.right - onClicked: (myMenu.status === DialogStatus.Closed) ? myMenu.open() : myMenu.close() - } - } - Menu { id: myMenu visualParent: pageStack MenuLayout { MenuItem { - text: qsTr("Start service") - onClicked: { - Sowatch.start(); - } - } - MenuItem { - text: qsTr("Stop service") + text: qsTr("Crap") onClicked: { - Sowatch.stop(); + console.log("Crap") } } } diff --git a/sowatchui/scannerproxy.cc b/sowatchui/scannerproxy.cc new file mode 100644 index 0000000..cfa4365 --- /dev/null +++ b/sowatchui/scannerproxy.cc @@ -0,0 +1,26 @@ +/* + * This file was generated by qdbusxml2cpp version 0.7 + * Command line was: qdbusxml2cpp -c ScannerProxy -p scannerproxy ../sowatchd/scanner.xml + * + * qdbusxml2cpp is Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). + * + * This is an auto-generated file. + * This file may have been hand-edited. Look for HAND-EDIT comments + * before re-generating it. + */ + +#include "scannerproxy.h" + +/* + * Implementation of interface class ScannerProxy + */ + +ScannerProxy::ScannerProxy(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent) + : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent) +{ +} + +ScannerProxy::~ScannerProxy() +{ +} + diff --git a/sowatchui/scannerproxy.h b/sowatchui/scannerproxy.h new file mode 100644 index 0000000..3b1b9c8 --- /dev/null +++ b/sowatchui/scannerproxy.h @@ -0,0 +1,58 @@ +/* + * This file was generated by qdbusxml2cpp version 0.7 + * Command line was: qdbusxml2cpp -c ScannerProxy -p scannerproxy ../sowatchd/scanner.xml + * + * qdbusxml2cpp is Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). + * + * This is an auto-generated file. + * Do not edit! All changes made to it will be lost. + */ + +#ifndef SCANNERPROXY_H_1344446154 +#define SCANNERPROXY_H_1344446154 + +#include <QtCore/QObject> +#include <QtCore/QByteArray> +#include <QtCore/QList> +#include <QtCore/QMap> +#include <QtCore/QString> +#include <QtCore/QStringList> +#include <QtCore/QVariant> +#include <QtDBus/QtDBus> + +/* + * Proxy class for interface com.javispedro.sowatch.WatchScanner + */ +class ScannerProxy: public QDBusAbstractInterface +{ + Q_OBJECT +public: + static inline const char *staticInterfaceName() + { return "com.javispedro.sowatch.WatchScanner"; } + +public: + ScannerProxy(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0); + + ~ScannerProxy(); + +public Q_SLOTS: // METHODS + inline QDBusPendingReply<> Start() + { + QList<QVariant> argumentList; + return asyncCallWithArgumentList(QLatin1String("Start"), argumentList); + } + +Q_SIGNALS: // SIGNALS + void Finished(); + void Started(); + void WatchFound(const QVariantMap &info); +}; + +namespace com { + namespace javispedro { + namespace sowatch { + typedef ::ScannerProxy WatchScanner; + } + } +} +#endif diff --git a/sowatchui/scanwatchesmodel.cc b/sowatchui/scanwatchesmodel.cc new file mode 100644 index 0000000..5b7c331 --- /dev/null +++ b/sowatchui/scanwatchesmodel.cc @@ -0,0 +1,102 @@ +#include <QtDebug> + +#include "scanwatchesmodel.h" + +ScanWatchesModel::ScanWatchesModel(QObject *parent) : + QAbstractListModel(parent), + _scanner(new ScannerProxy("com.javispedro.sowatchd", "/com/javispedro/sowatch/allscanner", QDBusConnection::sessionBus())), + _timer(new QTimer(this)), + _enabled(false), _active(false) +{ + QHash<int, QByteArray> roles = roleNames(); + roles[Qt::DisplayRole] = QByteArray("title"); + roles[Qt::StatusTipRole] = QByteArray("subtitle"); + roles[ObjectRole] = QByteArray("object"); + setRoleNames(roles); + + _timer->setSingleShot(true); + _timer->setInterval(3000); + + connect(_scanner, SIGNAL(WatchFound(QVariantMap)), SLOT(handleWatchFound(QVariantMap))); + connect(_scanner, SIGNAL(Started()), SLOT(handleStarted())); + connect(_scanner, SIGNAL(Finished()), SLOT(handleFinished())); + connect(_timer, SIGNAL(timeout()), SLOT(handleTimeout())); +} + +ScanWatchesModel::~ScanWatchesModel() +{ +} + +bool ScanWatchesModel::enabled() const +{ + return _enabled; +} + +void ScanWatchesModel::setEnabled(bool enabled) +{ + _timer->stop(); + + _enabled = enabled; + + if (_enabled && !_active) { + _scanner->Start(); + } +} + +bool ScanWatchesModel::active() const +{ + return _active; +} + +int ScanWatchesModel::rowCount(const QModelIndex &parent) const +{ + return _list.count(); +} + +QVariant ScanWatchesModel::data(const QModelIndex &index, int role) const +{ + qDebug() << "Asked for data" << index.row() << index.column() << role; + const QVariantMap &info = _list.at(index.row()); + switch (role) { + case Qt::DisplayRole: + return info["name"]; + case Qt::StatusTipRole: + return info["address"]; + case ObjectRole: + return QVariant::fromValue(info); + } + return QVariant(); +} + +void ScanWatchesModel::handleWatchFound(const QVariantMap &info) +{ + qDebug() << "Watch found" << info << endl; + if (!_list.contains(info)) { + int count = _list.count(); + beginInsertRows(QModelIndex(), count, count); + _list.append(info); + endInsertRows(); + } +} + +void ScanWatchesModel::handleStarted() +{ + _active = true; + emit activeChanged(); +} + +void ScanWatchesModel::handleFinished() +{ + qDebug() << "Scan finished"; + _active = false; + if (_enabled) { + _timer->start(); + } + emit activeChanged(); +} + +void ScanWatchesModel::handleTimeout() +{ + qDebug() << "Restarting scan"; + _scanner->Start(); +} diff --git a/sowatchui/scanwatchesmodel.h b/sowatchui/scanwatchesmodel.h new file mode 100644 index 0000000..424ded4 --- /dev/null +++ b/sowatchui/scanwatchesmodel.h @@ -0,0 +1,49 @@ +#ifndef SCANWATCHESMODEL_H +#define SCANWATCHESMODEL_H + +#include <QtCore/QAbstractListModel> +#include <QtCore/QTimer> +#include <sowatch.h> + +#include "scannerproxy.h" + +class ScanWatchesModel : public QAbstractListModel +{ + Q_OBJECT + Q_PROPERTY(bool enabled READ enabled WRITE setEnabled) + Q_PROPERTY(bool active READ active NOTIFY activeChanged) + +public: + explicit ScanWatchesModel(QObject *parent = 0); + ~ScanWatchesModel(); + + enum DataRoles { + ObjectRole = Qt::UserRole + }; + + bool enabled() const; + void setEnabled(bool enabled); + + bool active() const; + + int rowCount(const QModelIndex &parent) const; + QVariant data(const QModelIndex &index, int role) const; + +signals: + void activeChanged(); + +private slots: + void handleWatchFound(const QVariantMap& info); + void handleStarted(); + void handleFinished(); + void handleTimeout(); + +private: + ScannerProxy *_scanner; + QList<QVariantMap> _list; + QTimer *_timer; + bool _enabled; + bool _active; +}; + +#endif // SCANWATCHESMODEL_H diff --git a/sowatchui/sowatchui.pro b/sowatchui/sowatchui.pro index c73875c..e02afcc 100644 --- a/sowatchui/sowatchui.pro +++ b/sowatchui/sowatchui.pro @@ -9,6 +9,10 @@ DEPLOYMENTFOLDERS = qml_folder # Additional import path used to resolve QML modules in Creator's code model QML_IMPORT_PATH = +simulator { + QML_IMPORT_PATH += $$[QT_INSTALL_PREFIX]/imports/simulatorHarmattan + DEFINES += QT_INSTALL_PREFIX=\\\"$$[QT_INSTALL_PREFIX]\\\" +} # Speed up launching on MeeGo/Harmattan when using applauncherd daemon CONFIG += qdeclarative-boostable @@ -19,11 +23,18 @@ INCLUDEPATH += $$PWD/../libsowatch DEPENDPATH += $$PWD/../libsowatch # Source files -SOURCES += main.cpp +SOURCES += main.cpp \ + watchesmodel.cc \ + scanwatchesmodel.cc scannerproxy.cc -OTHER_FILES += \ +HEADERS += \ + watchesmodel.h \ + scanwatchesmodel.h scannerproxy.h + +OTHER_FILES += qml/main.qml \ qml/MainPage.qml \ - qml/main.qml \ + qml/NewWatchSheet.qml \ + qml/WatchPage.qml \ sowatch_harmattan.desktop \ sowatch.desktop diff --git a/sowatchui/watchesmodel.cc b/sowatchui/watchesmodel.cc new file mode 100644 index 0000000..d12e7db --- /dev/null +++ b/sowatchui/watchesmodel.cc @@ -0,0 +1,136 @@ +#include <QtDebug> + +#include "watchesmodel.h" + +using namespace sowatch; + +WatchesModel::WatchesModel(QObject *parent) : + QAbstractListModel(parent), + _config(new GConfKey("/apps/sowatch", this)), + _active_watches(_config->getSubkey("active-watches", this)) +{ + QHash<int, QByteArray> roles = roleNames(); + roles[Qt::DisplayRole] = QByteArray("title"); + roles[Qt::StatusTipRole] = QByteArray("subtitle"); + roles[ObjectRole] = QByteArray("object"); + setRoleNames(roles); + + connect(_config, SIGNAL(changed()), + this, SLOT(handleConfigChanged())); + connect(_config, SIGNAL(subkeyChanged(QString)), + this, SLOT(handleSubkeyChanged(QString))); + qDebug() << "connects"; + + reload(); +} + +WatchesModel::~WatchesModel() +{ +} + +int WatchesModel::rowCount(const QModelIndex &parent) const +{ + return _list.count(); +} + +QVariant WatchesModel::data(const QModelIndex &index, int role) const +{ + qDebug() << "Asked for data" << index.row() << index.column() << role; + ConfigKey *config = _list[index.row()]; + switch (role) { + case Qt::DisplayRole: + return config->value("name"); + case Qt::StatusTipRole: + return QVariant(tr("Configured")); + } + return QVariant(); +} + +bool WatchesModel::removeRows(int row, int count, const QModelIndex &parent) +{ + +} + +void WatchesModel::addFoundWatch(const QVariantMap &info) +{ + QStringList existing = _config->dirs(); + QString base = "watch%1"; + QString name = base.arg(""); + int num = 1; + + while (existing.contains(name)) { + num++; + name = base.arg(num); + } + + ConfigKey* newkey = _config->getSubkey(name); + foreach (const QString& key, info.keys()) { + newkey->set(key, info[key]); + } + + // Now add to active watches + QStringList active = _active_watches->value().toStringList(); + active << name; + _active_watches->set(active); +} + +void WatchesModel::reload() +{ + QStringList dirs = _config->dirs(); + + beginResetModel(); + foreach (ConfigKey* conf, _list) { + conf->deleteLater(); + } + _list.clear(); + foreach (const QString& s, dirs) { + _list.append(_config->getSubkey(s, this)); + } + endResetModel(); + + qDebug() << "Found" << _list.count() << "configured watches"; +} + +void WatchesModel::handleConfigChanged() +{ + qDebug() << "Key changed"; +} + +void WatchesModel::handleSubkeyChanged(const QString &subkey) +{ + QRegExp nameexp("^([^/]+)/name"); + if (nameexp.exactMatch(subkey)) { + qDebug() << "Name key changed:" << subkey; + QString id = nameexp.cap(1); + int i = findRowByWatchId(id); + if (i != -1) { + if (_config->value(subkey).isNull()) { + beginRemoveRows(QModelIndex(), i, i); + _list[i]->deleteLater(); + _list.removeAt(i); + qDebug() << "Removing" << i; + endRemoveRows(); + } else { + emit dataChanged(createIndex(i, 0), createIndex(i, 0)); + qDebug() << "Changing" << i; + } + } else { + i = _list.size(); + qDebug() << "Inserting" << i; + beginInsertRows(QModelIndex(), i, i); + _list.append(_config->getSubkey(id, this)); + endInsertRows(); + } + } +} + +int WatchesModel::findRowByWatchId(const QString &id) +{ + QString pattern(_config->key() + "/" + id); + for (int i = 0; i < _list.size(); i++) { + if (_list[i]->key().endsWith("/" + id)) { + return i; + } + } + return -1; +} diff --git a/sowatchui/watchesmodel.h b/sowatchui/watchesmodel.h new file mode 100644 index 0000000..cc6c9af --- /dev/null +++ b/sowatchui/watchesmodel.h @@ -0,0 +1,40 @@ +#ifndef WATCHESMODEL_H +#define WATCHESMODEL_H + +#include <QAbstractListModel> + +#include <sowatch.h> + +class WatchesModel : public QAbstractListModel +{ + Q_OBJECT +public: + explicit WatchesModel(QObject *parent = 0); + ~WatchesModel(); + + enum DataRoles { + ObjectRole = Qt::UserRole + }; + + int rowCount(const QModelIndex &parent) const; + QVariant data(const QModelIndex &index, int role) const; + bool removeRows(int row, int count, const QModelIndex &parent); + +public slots: + void addFoundWatch(const QVariantMap& info); + +private slots: + void reload(); + void handleConfigChanged(); + void handleSubkeyChanged(const QString& subkey); + +private: + int findRowByWatchId(const QString& id); + +private: + sowatch::ConfigKey *_config; + sowatch::ConfigKey *_active_watches; + QList<sowatch::ConfigKey*> _list; +}; + +#endif // WATCHESMODEL_H |