From d194a6112299cfe045c34e5cdb6adbbb81418d09 Mon Sep 17 00:00:00 2001 From: "Javier S. Pedro" Date: Fri, 10 Aug 2012 00:45:24 +0200 Subject: new watchhandler for watchlet/prov lifecycle mgmt --- libsowatch/notificationprovider.h | 2 +- libsowatch/watchserver.cpp | 43 ++++++++++--- libsowatch/watchserver.h | 10 ++- metawatch/metawatch.cpp | 10 ++- metawatch/metawatchscanner.cpp | 2 + sowatchd/daemon.cpp | 105 +++++------------------------- sowatchd/daemon.h | 4 +- sowatchd/sowatchd.pro | 6 +- sowatchd/watchhandler.cpp | 132 ++++++++++++++++++++++++++++++++++++++ sowatchd/watchhandler.h | 41 ++++++++++++ sowatchui/sowatchui.pro | 4 +- sowatchui/watchesmodel.cpp | 7 ++ 12 files changed, 258 insertions(+), 108 deletions(-) create mode 100644 sowatchd/watchhandler.cpp create mode 100644 sowatchd/watchhandler.h diff --git a/libsowatch/notificationprovider.h b/libsowatch/notificationprovider.h index d5449f8..b18b3d6 100644 --- a/libsowatch/notificationprovider.h +++ b/libsowatch/notificationprovider.h @@ -12,7 +12,7 @@ class SOWATCH_EXPORT NotificationProvider : public QObject { Q_OBJECT -protected: +public: explicit NotificationProvider(QObject *parent = 0); virtual ~NotificationProvider(); diff --git a/libsowatch/watchserver.cpp b/libsowatch/watchserver.cpp index d5db9da..2cadc98 100644 --- a/libsowatch/watchserver.cpp +++ b/libsowatch/watchserver.cpp @@ -50,21 +50,46 @@ void WatchServer::setNextWatchletButton(const QString& value) } } -void WatchServer::addProvider(NotificationProvider *provider) +void WatchServer::addWatchlet(Watchlet *watchlet) { - provider->setParent(this); - connect(provider, SIGNAL(incomingNotification(Notification*)), SLOT(postNotification(Notification*))); + insertWatchlet(_watchlets.size(), watchlet); } -void WatchServer::addWatchlet(Watchlet *watchlet) +void WatchServer::insertWatchlet(int position, Watchlet *watchlet) +{ + const QString id = watchlet->id(); + Q_ASSERT(watchlet->_server == this); + Q_ASSERT(!_watchletIds.contains(id)); + + _watchlets.insert(position, watchlet); + _watchletIds[id] = watchlet; +} + +void WatchServer::removeWatchlet(const Watchlet *watchlet) { - // A watchlet is best not reparented; just look that the parent is correct + const QString id = watchlet->id(); + Q_ASSERT(watchlet->_server == this); - _watchlets.append(watchlet); - QString id = watchlet->id(); - if (!_watchletIds.contains(id)) { - _watchletIds[id] = watchlet; + Q_ASSERT(_watchletIds.contains(id)); + + if (_currentWatchlet == watchlet) { + closeWatchlet(); } + + _watchlets.removeAll(const_cast(watchlet)); + _watchletIds.remove(id); +} + +void WatchServer::addProvider(NotificationProvider *provider) +{ + connect(provider, SIGNAL(incomingNotification(Notification*)), + this, SLOT(postNotification(Notification*))); +} + +void WatchServer::removeProvider(const NotificationProvider *provider) +{ + disconnect(provider, SIGNAL(incomingNotification(Notification*)), + this, SLOT(postNotification(Notification*))); } QList WatchServer::liveNotifications() diff --git a/libsowatch/watchserver.h b/libsowatch/watchserver.h index 54d3dc1..c1e6ef0 100644 --- a/libsowatch/watchserver.h +++ b/libsowatch/watchserver.h @@ -25,15 +25,19 @@ class SOWATCH_EXPORT WatchServer : public QObject Q_PROPERTY(QString nextWatchletButton READ nextWatchletButton WRITE setNextWatchletButton) public: - explicit WatchServer(Watch* watch, QObject* parent = 0); + explicit WatchServer(Watch *watch, QObject *parent = 0); Watch* watch(); QString nextWatchletButton() const; void setNextWatchletButton(const QString& value); - void addWatchlet(Watchlet* watchlet); - void addProvider(NotificationProvider* provider); + void addWatchlet(Watchlet *watchlet); + void insertWatchlet(int position, Watchlet *watchlet); + void removeWatchlet(const Watchlet *watchlet); + + void addProvider(NotificationProvider *provider); + void removeProvider(const NotificationProvider *provider); /** Get a list of all current live notifications. */ QList liveNotifications(); diff --git a/metawatch/metawatch.cpp b/metawatch/metawatch.cpp index fe080e4..6f8edca 100644 --- a/metawatch/metawatch.cpp +++ b/metawatch/metawatch.cpp @@ -120,7 +120,13 @@ MetaWatch::MetaWatch(ConfigKey* settings, QObject* parent) : MetaWatch::~MetaWatch() { - delete _paintEngine; + if (_socket) { + _socket->close(); + delete _socket; + } + if (_paintEngine) { + delete _paintEngine; + } } QPaintEngine* MetaWatch::paintEngine() const @@ -724,7 +730,7 @@ void MetaWatch::socketDisconnected() timeToNextRetry = connectRetryTimes[_connectRetries]; _connectRetries++; } - qDebug() << "Backing off for " << timeToNextRetry << "seconds for next retry"; + qDebug() << "Backing off for" << timeToNextRetry << "seconds for next retry"; _connectAlignedTimer->start(timeToNextRetry / 2, timeToNextRetry * 2); if (_connectAlignedTimer->lastError() != QSystemAlignedTimer::NoError) { // I would like to know why QtM couldn't _emulate_ here using a QTimer by itself. diff --git a/metawatch/metawatchscanner.cpp b/metawatch/metawatchscanner.cpp index 99ccc93..a34f71b 100644 --- a/metawatch/metawatchscanner.cpp +++ b/metawatch/metawatchscanner.cpp @@ -37,9 +37,11 @@ void MetaWatchScanner::handleDiscoveredService(const QBluetoothServiceInfo &info qDebug() << "metawatch bluetooth scan found:" << deviceName; if (deviceName.contains("Digital", Qt::CaseInsensitive)) { foundInfo["driver"] = QString("metawatch-digital"); + foundInfo["next-watchlet-button"] = QString("A"); emit watchFound(foundInfo); } else if (deviceName.contains("Analog", Qt::CaseInsensitive)) { foundInfo["driver"] = QString("metawatch-analog"); + foundInfo["next-watchlet-button"] = QString("A"); emit watchFound(foundInfo); } else { qWarning() << "Unknown MetaWatch device found:" << deviceName; diff --git a/sowatchd/daemon.cpp b/sowatchd/daemon.cpp index c668f59..bcf3686 100644 --- a/sowatchd/daemon.cpp +++ b/sowatchd/daemon.cpp @@ -21,14 +21,8 @@ Daemon::Daemon(QObject *parent) : QString Daemon::getWatchStatus(const QString &name) { - if (_servers.contains(name)) { - WatchServer* server = _servers[name]; - Watch* watch = server->watch(); - if (watch->isConnected()) { - return QLatin1String("connected"); - } else { - return QLatin1String("enabled"); - } + if (_watches.contains(name)) { + return _watches[name]->status(); } else { return QLatin1String("disabled"); } @@ -42,87 +36,29 @@ void Daemon::terminate() void Daemon::startWatch(const QString &name) { qDebug() << "Starting watch" << name; - QScopedPointer watchSettings(_config->getSubkey(name)); - - const QString driver = watchSettings->value("driver").toString().toLower(); - if (driver.isEmpty()) { - qWarning() << "Watch" << name << "has no driver setting"; - return; - } - - WatchPluginInterface *watchPlugin = _registry->getWatchPlugin(driver); - if (!watchPlugin) { - qWarning() << "Invalid driver" << driver; - return; - } - - // Create the watch object from the plugin - Watch *watch = watchPlugin->getWatch(driver, watchSettings.data(), this); - if (!watch) { - qWarning() << "Driver" << driver << "failed to initiate watch"; - } - - // Create the server - WatchServer* server = new WatchServer(watch, this); - _servers[name] = server; - + QScopedPointer watchConfig(_config->getSubkey(name)); + WatchHandler *handler = new WatchHandler(watchConfig.data(), this); + _status_mapper->setMapping(handler, name); + _watches[name] = handler; handleWatchStatusChange(name); - - // Connect watch status signals - _status_mapper->setMapping(watch, name); - connect(watch, SIGNAL(connected()), + connect(handler, SIGNAL(statusChanged()), _status_mapper, SLOT(map())); - connect(watch, SIGNAL(disconnected()), - _status_mapper, SLOT(map())); - - // Configure the server - server->setNextWatchletButton(watchSettings->value("next-watchlet-button").toString()); - - // Initialize providers - QStringList list; - list = watchSettings->value("active-notifications").toStringList(); - foreach (const QString& s, list) { - QScopedPointer settings(watchSettings->getSubkey(s)); - QString id = settings->value("id").toString().toLower(); - NotificationPluginInterface *plugin = _registry->getNotificationPlugin(id); - if (plugin) { - NotificationProvider *provider = plugin->getProvider(id, settings.data(), server); - server->addProvider(provider); - } else { - qWarning() << "Unknown notification provider" << id; - } - } - - // Initialize watchlets - list = watchSettings->value("active-watchlets").toStringList(); - foreach (const QString& s, list) { - QScopedPointer settings(watchSettings->getSubkey(s)); - QString id = settings->value("id").toString().toLower(); - WatchletPluginInterface *plugin = _registry->getWatchletPlugin(id); - if (plugin) { - Watchlet *watchlet = plugin->getWatchlet(id, settings.data(), server); - server->addWatchlet(watchlet); - } else { - qWarning() << "Unknown watchlet" << id; - } - } } void Daemon::stopWatch(const QString &name) { qDebug() << "Stopping watch" << name; - WatchServer* server = _servers[name]; - Watch* watch = server->watch(); - server->deleteLater(); - watch->deleteLater(); - _servers.remove(name); + WatchHandler *handler = _watches[name]; + _watches.remove(name); + _status_mapper->removeMappings(handler); + delete handler; handleWatchStatusChange(name); } void Daemon::startEnabledWatches() { QStringList watches = _watches_list->value().toStringList(); - QSet startedWatches = _servers.keys().toSet(); + QSet startedWatches = _watches.keys().toSet(); QSet removed = startedWatches - watches.toSet(); // Those watches have been entirely removed from the list, not disabled first @@ -132,7 +68,7 @@ void Daemon::startEnabledWatches() foreach (const QString& s, watches) { bool enabled_in_config = _config->value(s + "/enable").toBool(); - bool currently_started = _servers.contains(s); + bool currently_started = _watches.contains(s); if (enabled_in_config && !currently_started) { startWatch(s); @@ -145,12 +81,11 @@ void Daemon::startEnabledWatches() void Daemon::handleSettingsChanged(const QString &subkey) { qDebug() << "Daemon settings changed" << subkey; - static QRegExp enabled_key_pattern("^([^/])/enable$"); + static QRegExp enabled_key_pattern("([^/]+)/enable"); if (enabled_key_pattern.exactMatch(subkey)) { - QStringList watches = _watches_list->value().toStringList(); QString watchName = enabled_key_pattern.cap(1); bool enabled_in_config = _config->value(subkey).toBool(); - bool currently_started = _servers.contains(watchName); + bool currently_started = _watches.contains(watchName); if (enabled_in_config && !currently_started) { startWatch(watchName); @@ -164,14 +99,8 @@ void Daemon::handleSettingsChanged(const QString &subkey) void Daemon::handleWatchStatusChange(const QString &name) { - if (_servers.contains(name)) { - WatchServer* server = _servers[name]; - Watch* watch = server->watch(); - if (watch->isConnected()) { - emit WatchStatusChanged(name, QLatin1String("connected")); - } else { - emit WatchStatusChanged(name, QLatin1String("enabled")); - } + if (_watches.contains(name)) { + emit WatchStatusChanged(name, _watches[name]->status()); } else if (_watches_list->value().toStringList().contains(name)) { emit WatchStatusChanged(name, QLatin1String("disabled")); } else { diff --git a/sowatchd/daemon.h b/sowatchd/daemon.h index d35b56b..e3f748b 100644 --- a/sowatchd/daemon.h +++ b/sowatchd/daemon.h @@ -7,6 +7,8 @@ #include +#include "watchhandler.h" + namespace sowatch { @@ -28,7 +30,7 @@ private: Registry* _registry; ConfigKey* _config; ConfigKey* _watches_list; - QMap _servers; + QMap _watches; QSignalMapper *_status_mapper; void startWatch(const QString& name); diff --git a/sowatchd/sowatchd.pro b/sowatchd/sowatchd.pro index 4b1b668..9299f05 100644 --- a/sowatchd/sowatchd.pro +++ b/sowatchd/sowatchd.pro @@ -5,8 +5,10 @@ TEMPLATE = app QT += core gui dbus CONFIG -= app_bundle -SOURCES += main.cpp daemon.cpp daemonadaptor.cpp -HEADERS += global.h daemon.h daemonadaptor.h +SOURCES += main.cpp daemon.cpp daemonadaptor.cpp \ + watchhandler.cpp +HEADERS += global.h daemon.h daemonadaptor.h \ + watchhandler.h LIBS += -L$$OUT_PWD/../libsowatch/ -lsowatch INCLUDEPATH += $$PWD/../libsowatch diff --git a/sowatchd/watchhandler.cpp b/sowatchd/watchhandler.cpp new file mode 100644 index 0000000..e396c17 --- /dev/null +++ b/sowatchd/watchhandler.cpp @@ -0,0 +1,132 @@ +#include "watchhandler.h" + +using namespace sowatch; + +WatchHandler::WatchHandler(ConfigKey *config, QObject *parent) + : QObject(parent), + _config(config->getSubkey("", this)) +{ + Registry *registry = Registry::registry(); + + qDebug() << "Starting watch handler on" << _config->key(); + + connect(_config, SIGNAL(subkeyChanged(QString)), + SLOT(handleConfigSubkeyChanged(QString))); + + const QString driver = _config->value("driver").toString(); + if (driver.isEmpty()) { + qWarning() << "Watch" << _config->value("name") << "has no driver setting"; + return; + } + + WatchPluginInterface *watchPlugin = registry->getWatchPlugin(driver); + if (!watchPlugin) { + qWarning() << "Invalid driver" << driver; + return; + } + + // Create the watch object from the plugin + _watch = watchPlugin->getWatch(driver, _config, this); + if (!_watch) { + qWarning() << "Driver" << driver << "failed to initiate watch"; + return; + } + + // Setup watch status connections + connect(_watch, SIGNAL(connected()), + SIGNAL(statusChanged())); + connect(_watch, SIGNAL(connected()), + SIGNAL(statusChanged())); + + // Now create the UI server + _server = new WatchServer(_watch, this); + + // Configure the server + _server->setNextWatchletButton(_config->value("next-watchlet-button").toString()); + + updateProviders(); + updateWatchlets(); +} + +QString WatchHandler::status() const +{ + if (_watch->isConnected()) { + return "connected"; + } else if (_config->value("enable").toBool()) { + return "enabled"; + } else { + return "disabled"; + } +} + +void WatchHandler::updateWatchlets() +{ + Registry *registry = Registry::registry(); + QStringList newWatchlets = _config->value("watchlets").toStringList(); + QStringList curWatchlets = _watchlet_order; + + // TODO: Something better than removing all and readding + foreach (const QString& s, curWatchlets) { + Watchlet* watchlet = _watchlets[s]; + _server->removeWatchlet(watchlet); + delete watchlet; + } + + _watchlet_order.clear(); + _watchlets.clear(); + + foreach (const QString& s, newWatchlets) { + WatchletPluginInterface *plugin = registry->getWatchletPlugin(s); + if (!plugin) { + qWarning() << "Unknown watchlet" << s; + continue; + } + ConfigKey *subconfig = _config->getSubkey(s); + Watchlet* watchlet = plugin->getWatchlet(s, subconfig, _server); + _watchlet_order << s; + _watchlets[s] = watchlet; + _server->addWatchlet(watchlet); + delete subconfig; + } + + qDebug() << "Watchlets reloaded"; +} + +void WatchHandler::updateProviders() +{ + Registry *registry = Registry::registry(); + QSet curProviders = _providers.keys().toSet(); + QSet newProviders = _config->value("providers").toStringList().toSet(); + QSet removed = curProviders - newProviders; + QSet added = newProviders - curProviders; + + foreach (const QString& s, removed) { + NotificationProvider *provider = _providers[s]; + _server->removeProvider(provider); + delete provider; + } + + foreach (const QString& s, added) { + NotificationPluginInterface *plugin = registry->getNotificationPlugin(s); + if (!plugin) { + qWarning() << "Unknown notification provider" << s; + continue; + } + ConfigKey *subconfig = _config->getSubkey(s); + NotificationProvider *provider = plugin->getProvider(s, subconfig, _server); + _server->addProvider(provider); + _providers[s] = provider; + delete subconfig; + } +} + +void WatchHandler::handleConfigSubkeyChanged(const QString &subkey) +{ + if (subkey == "watchlets") { + updateWatchlets(); + } else if (subkey == "providers") { + updateProviders(); + } else if (subkey == "next-watchlet-button") { + _server->setNextWatchletButton(_config->value("next-watchlet-button").toString()); + } +} diff --git a/sowatchd/watchhandler.h b/sowatchd/watchhandler.h new file mode 100644 index 0000000..3fa7c6b --- /dev/null +++ b/sowatchd/watchhandler.h @@ -0,0 +1,41 @@ +#ifndef WATCHHANDLER_H +#define WATCHHANDLER_H + +#include +#include + +#include + +namespace sowatch +{ + +class WatchHandler : public QObject +{ + Q_OBJECT + Q_PROPERTY(QString status READ status NOTIFY statusChanged) + +public: + explicit WatchHandler(ConfigKey *config, QObject *parent = 0); + + QString status() const; + +signals: + void statusChanged(); + +private slots: + void updateWatchlets(); + void updateProviders(); + void handleConfigSubkeyChanged(const QString& key); + +private: + ConfigKey *_config; + Watch *_watch; + WatchServer *_server; + QList _watchlet_order; + QMap _watchlets; + QMap _providers; +}; + +} + +#endif // WATCHHANDLER_H diff --git a/sowatchui/sowatchui.pro b/sowatchui/sowatchui.pro index 9caa163..c0589fc 100644 --- a/sowatchui/sowatchui.pro +++ b/sowatchui/sowatchui.pro @@ -10,9 +10,9 @@ DEPLOYMENTFOLDERS = qml_folder # Install icon files also to resources directory res_files.files += sowatch64.png sowatch80.png !isEmpty(MEEGO_VERSION_MAJOR)|maemo5 { - res_files.path = /opt/sowatch/share/metawatch + res_files.path = /opt/sowatch/share } else { - res_files.path = /usr/share/sowatch/metawatch + res_files.path = /usr/share/sowatch } INSTALLS += res_files diff --git a/sowatchui/watchesmodel.cpp b/sowatchui/watchesmodel.cpp index 0930715..302e484 100644 --- a/sowatchui/watchesmodel.cpp +++ b/sowatchui/watchesmodel.cpp @@ -12,6 +12,7 @@ WatchesModel::WatchesModel(QObject *parent) : { QHash roles = roleNames(); roles[Qt::DisplayRole] = QByteArray("title"); + roles[Qt::DecorationRole] = QByteArray("iconSource"); roles[Qt::StatusTipRole] = QByteArray("subtitle"); roles[EnabledRole] = QByteArray("enabled"); roles[ConfigKeyRole] = QByteArray("configKey"); @@ -44,6 +45,12 @@ QVariant WatchesModel::data(const QModelIndex &index, int role) const switch (role) { case Qt::DisplayRole: return config->value("name"); + case Qt::DecorationRole: +#if defined(QT_DEBUG) + return QVariant(QDir::current().absoluteFilePath(SOWATCH_RESOURCES_DIR "/sowatch64.png")); +#else + return QVariant(SOWATCH_RESOURCES_DIR "/sowatch64.png"); +#endif case Qt::StatusTipRole: if (config->value("enable").toBool()) { QString status = _status[id]; -- cgit v1.2.3