From 88fab1f333cdc352014eb544a9a770f2183e1b4e Mon Sep 17 00:00:00 2001 From: Albert Vaca Date: Tue, 13 Aug 2013 05:07:32 +0200 Subject: [PATCH] Plugins are now owned by devices and not by daemon Plugins can no longer emit networkpackages for *every* device. Plugins are stored in device, wich selectively loads them. A Device is needed in order to instantiate a Plugin (via PluginLoader) PluginLoader is a singleton, because every instance of Device need it. Added KPluginSelector in the KCM to select the plugins to load. Added architecture explanation to README Only PingPlugin is working by now. --- README | 42 +++++- daemon/daemon.cpp | 32 +---- daemon/daemon.h | 9 +- daemon/device.cpp | 52 +++++++- daemon/device.h | 24 ++-- daemon/plugins/CMakeLists.txt | 3 + daemon/plugins/packageinterface.cpp | 13 +- daemon/plugins/packageinterface.h | 12 +- daemon/plugins/ping/kdeconnect_ping.desktop | 5 - daemon/plugins/ping/pingpackageinterface.cpp | 13 +- daemon/plugins/ping/pingpackageinterface.h | 7 +- daemon/plugins/pluginloader.cpp | 81 +++++++----- daemon/plugins/pluginloader.h | 24 ++-- kcm/CMakeLists.txt | 2 +- kcm/devicesmodel.cpp | 1 - kcm/kcm.cpp | 61 +++++++-- kcm/kcm.h | 12 +- kcm/kcm.ui | 132 +++++++++++-------- 18 files changed, 337 insertions(+), 188 deletions(-) diff --git a/README b/README index 7af405a74..1c6445fec 100644 --- a/README +++ b/README @@ -1,8 +1,41 @@ -The kdeconnect protocol: +Class diagram +============== + + Backend_1 ... Backend_N + \ | / + Daemon + / | \ + Device_1 ... Device_N + / \ + |-Plugin_1 |-DeviceLink_1 + |-Plugin_2 |-DeviceLink_2 + |- ... |-... + |-Plugin_N |-DeviceLink_N + + +Daemon instantiates Backends + +Backends manage to create DeviceLinks with the devices they can reach, and Q_EMIT them to Daemon. + +When Daemon receives a DeviceLink from a backend it: + - If he already knows the Device, adds the DeviceLink to the Device + - If not, it creates a new Device. + +Devices contain a list of DeviceLinks, plus a list of Plugins (instantiated automatically) + +Information for and from Plugins is encapsulated in NetworkPackages. + +When a DeviceLink receives a NetworkPackage from the device in the other end, Device will notify all the plugins. + +When a Plugin wants to send a NetworkPackage, it does so using the pointer to Device + + + +The NetworkPackage format +========================= -Communication between heterogenous devices is achieved using NetworkPackages. NetworkPackages are independent and self-contained pieces of information that -are sent from one device to another serialized in json. +are sent from one device to another (via a DeviceLink) serialized in json. The basic structure of a NetworkPackage is the following: @@ -16,5 +49,6 @@ The basic structure of a NetworkPackage is the following: } Each type of package defines what it should contain inside its "body", so only -the sender and receiver of this type of package need agree about it. +the emisor Plugin and receiver Plugin of this type of package need agree about +its content. diff --git a/daemon/daemon.cpp b/daemon/daemon.cpp index 9b947167f..b8cff2159 100644 --- a/daemon/daemon.cpp +++ b/daemon/daemon.cpp @@ -57,13 +57,7 @@ Daemon::Daemon(QObject *parent, const QList&) //Debugging qDebug() << "Starting KdeConnect daemon"; - //Load plugins - PluginLoader *loader = new PluginLoader(this); - connect(loader, SIGNAL(pluginLoaded(PackageInterface*)), this, SLOT(pluginLoaded(PackageInterface*))); - loader->loadAllPlugins(); - - //Load backends (hardcoded by now) - //use: https://techbase.kde.org/Development/Tutorials/Services/Plugins + //Load backends (hardcoded by now, should be plugins in a future) mLinkProviders.insert(new BroadcastTcpLinkProvider()); //mLinkProviders.insert(new AvahiTcpLinkProvider()); //mLinkProviders.insert(new LoopbackLinkProvider()); @@ -77,12 +71,6 @@ Daemon::Daemon(QObject *parent, const QList&) const QString& name = data.readEntry("name", defaultName); Device* device = new Device(id, name); mDevices[id] = device; - Q_FOREACH (PackageInterface* pr, mPackageInterfaces) { - connect(device, SIGNAL(receivedPackage(const Device&, const NetworkPackage&)), - pr, SLOT(receivePackage(const Device&, const NetworkPackage&))); - connect(pr, SIGNAL(sendPackage(const NetworkPackage&)), - device, SLOT(sendPackage(const NetworkPackage&))); - } } QNetworkSession* network = new QNetworkSession(QNetworkConfigurationManager().defaultConfiguration()); @@ -123,19 +111,6 @@ QStringList Daemon::devices() return mDevices.keys(); } -void Daemon::pluginLoaded(PackageInterface* packageInterface) -{ - qDebug() << "PLUUUUUUUUUUUUUUUUGINLOADEEEEEEEEEEEEEEEEEEEEEEED"; - mPackageInterfaces.append(packageInterface); - Q_FOREACH(Device* device, mDevices) { - connect(device, SIGNAL(receivedPackage(const Device&, const NetworkPackage&)), - packageInterface, SLOT(receivePackage(const Device&, const NetworkPackage&))); - connect(packageInterface, SIGNAL(sendPackage(const NetworkPackage&)), - device, SLOT(sendPackage(const NetworkPackage&))); - } - -} - void Daemon::onNewDeviceLink(const NetworkPackage& identityPackage, DeviceLink* dl) { const QString& id = identityPackage.get("deviceId"); @@ -166,10 +141,7 @@ void Daemon::onNewDeviceLink(const NetworkPackage& identityPackage, DeviceLink* Device* device = new Device(id, name, dl); mDevices[id] = device; - Q_FOREACH (PackageInterface* pr, mPackageInterfaces) { - connect(device, SIGNAL(receivedPackage(const Device&, const NetworkPackage&)), - pr, SLOT(receivePackage(const Device&, const NetworkPackage&))); - } + Q_EMIT newDeviceAdded(id); } diff --git a/daemon/daemon.h b/daemon/daemon.h index 9e6a8bb07..e69cd6e82 100644 --- a/daemon/daemon.h +++ b/daemon/daemon.h @@ -72,19 +72,14 @@ Q_SIGNALS: private Q_SLOTS: void onNewDeviceLink(const NetworkPackage& identityPackage, DeviceLink* dl); - void pluginLoaded(PackageInterface*); private: - - //Every known device - QMap mDevices; - //Different ways to find devices and connect to them QSet mLinkProviders; - //The classes that send and receive the packages - QVector mPackageInterfaces; + //Every known device + QMap mDevices; }; diff --git a/daemon/device.cpp b/daemon/device.cpp index b380a6850..1b46d7831 100644 --- a/daemon/device.cpp +++ b/daemon/device.cpp @@ -3,8 +3,14 @@ #include #include #include +#include +#include +#include +#include + #include +#include "plugins/pluginloader.h" #include "devicelinks/devicelink.h" #include "linkproviders/linkprovider.h" #include "networkpackage.h" @@ -19,6 +25,7 @@ Device::Device(const QString& id, const QString& name) //Register in bus QDBusConnection::sessionBus().registerObject("/modules/kdeconnect/devices/"+id, this, QDBusConnection::ExportScriptableContents | QDBusConnection::ExportAdaptors); + reloadPlugins(); } Device::Device(const QString& id, const QString& name, DeviceLink* link) @@ -32,6 +39,8 @@ Device::Device(const QString& id, const QString& name, DeviceLink* link) QDBusConnection::sessionBus().registerObject("/modules/kdeconnect/devices/"+id, this, QDBusConnection::ExportScriptableContents | QDBusConnection::ExportAdaptors); addLink(link); + + reloadPlugins(); } /* Device::Device(const QString& id, const QString& name, DeviceLink* link) @@ -50,6 +59,43 @@ Device::Device(const QString& id, const QString& name, DeviceLink* link) QDBusConnection::sessionBus().registerObject("/modules/kdeconnect/Devices/"+id, this); } */ + +void Device::reloadPlugins() +{ + + qDeleteAll(m_plugins); + m_plugins.clear(); + + QString path = KStandardDirs().resourceDirs("config").first()+"kdeconnect/"; + QMap pluginStates = KSharedConfig::openConfig(path + id())->group("Plugins").entryMap(); + + PluginLoader* loader = PluginLoader::instance(); + + //Code borrowed from KWin + foreach (const QString& pluginName, loader->getPluginList()) { + + const QString value = pluginStates.value(pluginName + QString::fromLatin1("Enabled"), QString()); + bool enabled = (value.isNull() ? true : QVariant(value).toBool()); //Enable all plugins by default + + qDebug() << pluginName << "enabled:" << enabled; + + if (enabled) { + PackageInterface* plugin = loader->instantiatePluginForDevice(pluginName, this); + + connect(this, SIGNAL(receivedPackage(const NetworkPackage&)), + plugin, SLOT(receivePackage(const NetworkPackage&))); + // connect(packageInterface, SIGNAL(sendPackage(const NetworkPackage&)), + // device, SLOT(sendPackage(const NetworkPackage&))); + + + m_plugins.append(plugin); + } + } + + +} + + void Device::setPair(bool b) { qDebug() << "setPair" << b; @@ -122,10 +168,10 @@ void Device::privateReceivedPackage(const NetworkPackage& np) if (np.type() == "kdeconnect.identity" && !m_knownIdentiy) { m_deviceName = np.get("deviceName"); } else if (m_paired) { - qDebug() << "package received from paired device"; - emit receivedPackage(*this, np); + qDebug() << "package received from trusted device"; + Q_EMIT receivedPackage(np); } else { - qDebug() << "not paired, ignoring package"; + qDebug() << "device" << name() << "not trusted, ignoring package" << np.type(); } } diff --git a/daemon/device.h b/daemon/device.h index 74ec9d373..813a8ff7d 100644 --- a/daemon/device.h +++ b/daemon/device.h @@ -28,6 +28,7 @@ #include "devicelinks/devicelink.h" class DeviceLink; +class PackageInterface; class Device : public QObject @@ -38,7 +39,6 @@ class Device Q_PROPERTY(QString name READ name) public: - //Device known from KConfig, we trust it but we need to wait for a incoming devicelink to communicate Device(const QString& id, const QString& name); @@ -56,19 +56,20 @@ public: void addLink(DeviceLink*); void removeLink(DeviceLink*); - - //Send and receive -Q_SIGNALS: - void receivedPackage(const Device& device, const NetworkPackage& np); -public Q_SLOTS: - bool sendPackage(const NetworkPackage& np) const; - - //Public dbus operations -public Q_SLOTS: Q_SCRIPTABLE QStringList availableLinks() const; Q_SCRIPTABLE bool paired() const { return m_paired; } Q_SCRIPTABLE bool reachable() const { return !m_deviceLinks.empty(); } + + //Send and receive +Q_SIGNALS: + void receivedPackage(const NetworkPackage& np); +public Q_SLOTS: + bool sendPackage(const NetworkPackage& np) const; + + //Dbus operations called from kcm +public Q_SLOTS: Q_SCRIPTABLE void setPair(bool b); + Q_SCRIPTABLE void reloadPlugins(); Q_SCRIPTABLE void sendPing(); Q_SIGNALS: @@ -83,9 +84,12 @@ private: QString m_deviceId; QString m_deviceName; QList m_deviceLinks; + QList m_plugins; bool m_knownIdentiy; }; +Q_DECLARE_METATYPE(Device*) + #endif // DEVICE_H diff --git a/daemon/plugins/CMakeLists.txt b/daemon/plugins/CMakeLists.txt index 4467d269d..b710c0403 100644 --- a/daemon/plugins/CMakeLists.txt +++ b/daemon/plugins/CMakeLists.txt @@ -1,2 +1,5 @@ +install(FILES kdeconnect_package_interface.desktop DESTINATION ${SERVICETYPES_INSTALL_DIR}) + add_subdirectory(ping) + diff --git a/daemon/plugins/packageinterface.cpp b/daemon/plugins/packageinterface.cpp index b5f5f720b..efa8dd407 100644 --- a/daemon/plugins/packageinterface.cpp +++ b/daemon/plugins/packageinterface.cpp @@ -20,8 +20,17 @@ #include "packageinterface.h" -PackageInterface::PackageInterface(QObject* parent) +#include + +#include "../device.h" + +PackageInterface::PackageInterface(QObject* parent, const QVariantList& args) : QObject(parent) { - //gcc complains if we don't add something to compile on a class with virtual functions + mDevice = qvariant_cast< Device* >(args.first()); +} + +Device* PackageInterface::device() +{ + return mDevice; } diff --git a/daemon/plugins/packageinterface.h b/daemon/plugins/packageinterface.h index 4569087b5..dd2d360b8 100644 --- a/daemon/plugins/packageinterface.h +++ b/daemon/plugins/packageinterface.h @@ -22,6 +22,7 @@ #define PACKAGEINTERFACE_H #include +#include #include #include @@ -40,17 +41,18 @@ class KDE_EXPORT PackageInterface Q_OBJECT public: - PackageInterface(QObject* parent = 0); + PackageInterface(QObject* parent, const QVariantList& args); virtual ~PackageInterface() { } + Device* device(); public Q_SLOTS: //Returns true if it has handled the package in some way //device.sendPackage can be used to send an answer back to the device - virtual bool receivePackage(const Device& device, const NetworkPackage& np) = 0; + virtual bool receivePackage(const NetworkPackage& np) = 0; + +private: + Device* mDevice; -Q_SIGNALS: - //Sends a package to *all* connected devices - void sendPackage(const NetworkPackage& np); }; #endif diff --git a/daemon/plugins/ping/kdeconnect_ping.desktop b/daemon/plugins/ping/kdeconnect_ping.desktop index fe19ccdb8..4fbe2a1a5 100644 --- a/daemon/plugins/ping/kdeconnect_ping.desktop +++ b/daemon/plugins/ping/kdeconnect_ping.desktop @@ -8,11 +8,6 @@ X-KDE-PluginInfo-Email=albertvaka@gmail.com X-KDE-PluginInfo-Name=kdeconnect_ping X-KDE-PluginInfo-Version=0.1 X-KDE-PluginInfo-Website=http://albertvaka.wordpress.com -X-KDE-PluginInfo-Category=Network -X-KDE-PluginInfo-Depends= X-KDE-PluginInfo-License=GPL -X-KDE-PluginInfo-EnabledByDefault=true -X-KDE-ParentApp=kdeconnect -X-KDE-Version=4.0 Name=Ping Comment=Send and receive pings diff --git a/daemon/plugins/ping/pingpackageinterface.cpp b/daemon/plugins/ping/pingpackageinterface.cpp index 4bc0a5370..be28f68a0 100644 --- a/daemon/plugins/ping/pingpackageinterface.cpp +++ b/daemon/plugins/ping/pingpackageinterface.cpp @@ -20,19 +20,20 @@ #include "pingpackageinterface.h" -#include -#include +#include +#include +#include K_PLUGIN_FACTORY( KdeConnectPluginFactory, registerPlugin< PingPackageInterface >(); ) K_EXPORT_PLUGIN( KdeConnectPluginFactory("kdeconnect_ping", "kdeconnect_ping") ) PingPackageInterface::PingPackageInterface(QObject* parent, const QVariantList& args) - : PackageInterface(parent) + : PackageInterface(parent, args) { - Q_UNUSED(args); + qDebug() << "Plugin constructor for device" << device()->name(); } -bool PingPackageInterface::receivePackage(const Device& device, const NetworkPackage& np) +bool PingPackageInterface::receivePackage(const NetworkPackage& np) { if (np.type() != PACKAGE_TYPE_PING) return false; @@ -41,7 +42,7 @@ bool PingPackageInterface::receivePackage(const Device& device, const NetworkPac notification->setPixmap(KIcon("dialog-ok").pixmap(48, 48)); notification->setComponentData(KComponentData("kdeconnect", "kdeconnect")); notification->setTitle("Ping!"); - notification->setText(device.name()); + notification->setText(device()->name()); notification->sendEvent(); return true; diff --git a/daemon/plugins/ping/pingpackageinterface.h b/daemon/plugins/ping/pingpackageinterface.h index 5ad4474cb..e21354f36 100644 --- a/daemon/plugins/ping/pingpackageinterface.h +++ b/daemon/plugins/ping/pingpackageinterface.h @@ -21,7 +21,7 @@ #ifndef PINGPACKAGEINTERFACE_H #define PINGPACKAGEINTERFACE_H -#include +#include #include "../packageinterface.h" @@ -32,8 +32,9 @@ class KDE_EXPORT PingPackageInterface public: explicit PingPackageInterface(QObject *parent, const QVariantList &args); - - virtual bool receivePackage(const Device& device, const NetworkPackage& np); + +public Q_SLOTS: + virtual bool receivePackage(const NetworkPackage& np); }; diff --git a/daemon/plugins/pluginloader.cpp b/daemon/plugins/pluginloader.cpp index b6eaedc4d..194ed4476 100644 --- a/daemon/plugins/pluginloader.cpp +++ b/daemon/plugins/pluginloader.cpp @@ -21,49 +21,58 @@ #include "pluginloader.h" #include "packageinterface.h" +#include "plugins/ping/pingpackageinterface.h" #include #include -PluginLoader::PluginLoader(QObject * parent) - : QObject(parent) +#include "../device.h" + +PluginLoader* PluginLoader::instance() { + static PluginLoader* instance = new PluginLoader(); + return instance; } -PluginLoader::~PluginLoader() +PluginLoader::PluginLoader() { -} - -void PluginLoader::loadAllPlugins() -{ - kDebug() << "Load all plugins"; KService::List offers = KServiceTypeTrader::self()->query("KdeConnect/Plugin"); - - qDebug() << "LO TRAIGO DE OFERTA CHACHO" << offers; - - KService::List::const_iterator iter; - for(iter = offers.begin(); iter < offers.end(); ++iter) - { - QString error; - KService::Ptr service = *iter; - - KPluginFactory *factory = KPluginLoader(service->library()).factory(); - - if (!factory) - { - //KMessageBox::error(0, i18n("

KPluginFactory could not load the plugin:
%1

", - // service->library())); - kError(5001) << "KPluginFactory could not load the plugin:" << service->library(); - continue; - } - - PackageInterface *plugin = factory->create(this); - - if (plugin) { - kDebug() << "Load plugin:" << service->name(); - emit pluginLoaded(plugin); - } else { - kDebug() << error; - } + for(KService::List::const_iterator iter = offers.begin(); iter < offers.end(); ++iter) { + KService::Ptr service = *iter; + plugins[service->library()] = service; } -} \ No newline at end of file +} + +QStringList PluginLoader::getPluginList() +{ + return plugins.keys(); +} + +PackageInterface* PluginLoader::instantiatePluginForDevice(QString id, Device* device) { + + KService::Ptr service = plugins[id]; + if (!service) { + qDebug() << "Plugin unknown" << id; + return NULL; + } + + KPluginFactory *factory = KPluginLoader(service->library()).factory(); + if (!factory) { + qDebug() << "KPluginFactory could not load the plugin:" << service->library(); + return NULL; + } + + QVariant deviceVariant; + deviceVariant.setValue(device); + + //FIXME: create return NULL + QObject *plugin = factory->create(device, QVariantList() << deviceVariant); + if (!plugin) { + qDebug() << "Error loading plugin"; + return NULL; + } + + qDebug() << "Loaded plugin:" << service->name(); + return (PackageInterface*)plugin; +} + diff --git a/daemon/plugins/pluginloader.h b/daemon/plugins/pluginloader.h index 4ae29d22d..8a2b6bda3 100644 --- a/daemon/plugins/pluginloader.h +++ b/daemon/plugins/pluginloader.h @@ -22,21 +22,29 @@ #define PACKAGEINTERFACELOADER_H #include +#include +#include #include "packageinterface.h" +#include +#include -class PluginLoader : public QObject +class Device; + +class PluginLoader { - Q_OBJECT - public: - PluginLoader(QObject * parent); - virtual ~PluginLoader(); - void loadAllPlugins(); +public: + static PluginLoader* instance(); + PackageInterface* instantiatePluginForDevice(QString name, Device* device); + QStringList getPluginList(); + +private: + PluginLoader(); + QMap plugins; + - signals: - void pluginLoaded(PackageInterface * plugin); }; #endif diff --git a/kcm/CMakeLists.txt b/kcm/CMakeLists.txt index 8b5ed0ae9..9c39d4276 100644 --- a/kcm/CMakeLists.txt +++ b/kcm/CMakeLists.txt @@ -25,7 +25,7 @@ target_link_libraries(kcm_kdeconnect ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY} ${KDE4_KDEUI_LIBRARY} - ${KDE4_KIO_LIBRARY} + ${KDE4_KCMUTILS_LIBS} ) add_dependencies(kcm_kdeconnect diff --git a/kcm/devicesmodel.cpp b/kcm/devicesmodel.cpp index 3ae35099c..990f87b72 100644 --- a/kcm/devicesmodel.cpp +++ b/kcm/devicesmodel.cpp @@ -118,7 +118,6 @@ QVariant DevicesModel::data(const QModelIndex &index, int role) const } - qDebug() << index.row() << ">= " << m_deviceList.count() << (index.row() >= m_deviceList.count()); if (!index.isValid() || index.row() < 0 || index.row() >= m_deviceList.count()) { return QVariant(); } diff --git a/kcm/kcm.cpp b/kcm/kcm.cpp index fc909b470..d6156c047 100644 --- a/kcm/kcm.cpp +++ b/kcm/kcm.cpp @@ -32,6 +32,8 @@ #include #include +#include +#include #include #include #include @@ -43,7 +45,8 @@ KdeConnectKcm::KdeConnectKcm(QWidget *parent, const QVariantList&) : KCModule(KdeConnectKcmFactory::componentData(), parent) , kcmUi(new Ui::KdeConnectKcmUi()) , pairedDevicesList(new DevicesModel(this)) - , config(KSharedConfig::openConfig("kdeconnectrc")) + , currentDevice(0) + //, config(KSharedConfig::openConfig("kdeconnectrc")) { kcmUi->setupUi(this); @@ -52,6 +55,8 @@ KdeConnectKcm::KdeConnectKcm(QWidget *parent, const QVariantList&) kcmUi->deviceInfo->setVisible(false); + setButtons(KCModule::NoAdditionalButton); + connect(kcmUi->deviceList, SIGNAL(pressed(QModelIndex)), this, SLOT(deviceSelected(QModelIndex))); connect(kcmUi->ping_button, SIGNAL(pressed()), this, SLOT(sendPing())); connect(kcmUi->trust_checkbox,SIGNAL(toggled(bool)), this, SLOT(trustedStateChanged(bool))); @@ -64,27 +69,63 @@ KdeConnectKcm::~KdeConnectKcm() void KdeConnectKcm::deviceSelected(const QModelIndex& current) { + //Store previous selection + pluginsConfigChanged(); + + //FIXME: KPluginSelector has no way to remove a list of plugins and load another, so we need to destroy and recreate it each time + delete kcmUi->pluginSelector; + kcmUi->pluginSelector = new KPluginSelector(this); + kcmUi->verticalLayout_2->addWidget(kcmUi->pluginSelector); + bool valid = current.isValid(); kcmUi->deviceInfo->setVisible(valid); if (!valid) return; - selectedIndex = current; - bool paired = pairedDevicesList->getDevice(current)->paired(); - kcmUi->trust_checkbox->setChecked(paired); + + currentDevice = pairedDevicesList->getDevice(current); + kcmUi->deviceName->setText(currentDevice->name()); + kcmUi->trust_checkbox->setChecked(currentDevice->paired()); + + KService::List offers = KServiceTypeTrader::self()->query("KdeConnect/Plugin"); + QList scriptinfos = KPluginInfo::fromServices(offers); + + QString path = KStandardDirs().resourceDirs("config").first()+"kdeconnect/"; + KSharedConfigPtr deviceConfig = KSharedConfig::openConfig(path + currentDevice->id()); + kcmUi->pluginSelector->addPlugins(scriptinfos, KPluginSelector::ReadConfigFile, "Plugins", QString(), deviceConfig); + + connect(kcmUi->pluginSelector, SIGNAL(changed(bool)), this, SLOT(pluginsConfigChanged())); } void KdeConnectKcm::trustedStateChanged(bool b) { - if (!selectedIndex.isValid()) return; - DeviceDbusInterface* device = pairedDevicesList->getDevice(selectedIndex); - device->setPair(b); - pairedDevicesList->deviceStatusChanged(device->id()); + if (!currentDevice) return; + currentDevice->setPair(b); + pairedDevicesList->deviceStatusChanged(currentDevice->id()); +} + +void KdeConnectKcm::pluginsConfigChanged() +{ + //Store previous selection + if (!currentDevice) return; + + DeviceDbusInterface* auxCurrentDevice = currentDevice; //HACK to avoid infinite recursion (for some reason calling save on pluginselector emits changed) + currentDevice = 0; + kcmUi->pluginSelector->save(); + currentDevice = auxCurrentDevice; + + currentDevice->reloadPlugins(); +} + +void KdeConnectKcm::save() +{ + pluginsConfigChanged(); + KCModule::save(); } void KdeConnectKcm::sendPing() { - if (!selectedIndex.isValid()) return; - pairedDevicesList->getDevice(selectedIndex)->sendPing(); + if (!currentDevice) return; + currentDevice->sendPing(); } diff --git a/kcm/kcm.h b/kcm/kcm.h index dbfb94343..f03696dca 100644 --- a/kcm/kcm.h +++ b/kcm/kcm.h @@ -30,13 +30,13 @@ #include "wizard.h" #include "devicesmodel.h" -class Create; class QModelIndex; class AccountsModel; class AccountWidget; class QStackedLayout; class QItemSelectionModel; class QDBusInterface; +class DeviceDbusInterface; namespace Ui { class KdeConnectKcmUi; @@ -50,17 +50,21 @@ public: KdeConnectKcm(QWidget *parent, const QVariantList&); virtual ~KdeConnectKcm(); +private: + virtual void save(); + private Q_SLOTS: void deviceSelected(const QModelIndex& current); void trustedStateChanged(bool); + void pluginsConfigChanged(); void sendPing(); - + private: Ui::KdeConnectKcmUi* kcmUi; DevicesModel* pairedDevicesList; AddDeviceWizard* addDeviceWizard; - KSharedConfigPtr config; - QModelIndex selectedIndex; + DeviceDbusInterface* currentDevice; + //KSharedConfigPtr config; }; diff --git a/kcm/kcm.ui b/kcm/kcm.ui index 13f8063f0..b9879b6ae 100644 --- a/kcm/kcm.ui +++ b/kcm/kcm.ui @@ -45,84 +45,102 @@ - + 0 0 - - - - - false - - - false - - + + + + 0 + 0 + + true - + + false + + - - - Qt::Vertical - - - - 20 - 215 - - - + + + + + + 10 + 75 + true + + + + Device + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + Trust this device + + + + + + + + 0 + 0 + + + + Send ping + + + + - + - + 0 0 - - Trust this device + + Qt::WheelFocus - - - - - 0 - 0 - - - - Send ping - - - - - - - Qt::Vertical - - - - 20 - 215 - - - - @@ -131,6 +149,14 @@ + + + KPluginSelector + QWidget +
kpluginselector.h
+ 1 +
+