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.
This commit is contained in:
Albert Vaca 2013-08-13 05:07:32 +02:00
parent 9b7eecc69d
commit 88fab1f333
18 changed files with 337 additions and 188 deletions

42
README
View file

@ -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 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: 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 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.

View file

@ -57,13 +57,7 @@ Daemon::Daemon(QObject *parent, const QList<QVariant>&)
//Debugging //Debugging
qDebug() << "Starting KdeConnect daemon"; qDebug() << "Starting KdeConnect daemon";
//Load plugins //Load backends (hardcoded by now, should be plugins in a future)
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
mLinkProviders.insert(new BroadcastTcpLinkProvider()); mLinkProviders.insert(new BroadcastTcpLinkProvider());
//mLinkProviders.insert(new AvahiTcpLinkProvider()); //mLinkProviders.insert(new AvahiTcpLinkProvider());
//mLinkProviders.insert(new LoopbackLinkProvider()); //mLinkProviders.insert(new LoopbackLinkProvider());
@ -77,12 +71,6 @@ Daemon::Daemon(QObject *parent, const QList<QVariant>&)
const QString& name = data.readEntry<QString>("name", defaultName); const QString& name = data.readEntry<QString>("name", defaultName);
Device* device = new Device(id, name); Device* device = new Device(id, name);
mDevices[id] = device; 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()); QNetworkSession* network = new QNetworkSession(QNetworkConfigurationManager().defaultConfiguration());
@ -123,19 +111,6 @@ QStringList Daemon::devices()
return mDevices.keys(); 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) void Daemon::onNewDeviceLink(const NetworkPackage& identityPackage, DeviceLink* dl)
{ {
const QString& id = identityPackage.get<QString>("deviceId"); const QString& id = identityPackage.get<QString>("deviceId");
@ -166,10 +141,7 @@ void Daemon::onNewDeviceLink(const NetworkPackage& identityPackage, DeviceLink*
Device* device = new Device(id, name, dl); Device* device = new Device(id, name, dl);
mDevices[id] = device; 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); Q_EMIT newDeviceAdded(id);
} }

View file

@ -72,19 +72,14 @@ Q_SIGNALS:
private Q_SLOTS: private Q_SLOTS:
void onNewDeviceLink(const NetworkPackage& identityPackage, DeviceLink* dl); void onNewDeviceLink(const NetworkPackage& identityPackage, DeviceLink* dl);
void pluginLoaded(PackageInterface*);
private: private:
//Every known device
QMap<QString, Device*> mDevices;
//Different ways to find devices and connect to them //Different ways to find devices and connect to them
QSet<LinkProvider*> mLinkProviders; QSet<LinkProvider*> mLinkProviders;
//The classes that send and receive the packages //Every known device
QVector<PackageInterface*> mPackageInterfaces; QMap<QString, Device*> mDevices;
}; };

View file

@ -3,8 +3,14 @@
#include <KSharedPtr> #include <KSharedPtr>
#include <KSharedConfig> #include <KSharedConfig>
#include <KConfigGroup> #include <KConfigGroup>
#include <KStandardDirs>
#include <KPluginSelector>
#include <KServiceTypeTrader>
#include <KPluginInfo>
#include <QDebug> #include <QDebug>
#include "plugins/pluginloader.h"
#include "devicelinks/devicelink.h" #include "devicelinks/devicelink.h"
#include "linkproviders/linkprovider.h" #include "linkproviders/linkprovider.h"
#include "networkpackage.h" #include "networkpackage.h"
@ -19,6 +25,7 @@ Device::Device(const QString& id, const QString& name)
//Register in bus //Register in bus
QDBusConnection::sessionBus().registerObject("/modules/kdeconnect/devices/"+id, this, QDBusConnection::ExportScriptableContents | QDBusConnection::ExportAdaptors); QDBusConnection::sessionBus().registerObject("/modules/kdeconnect/devices/"+id, this, QDBusConnection::ExportScriptableContents | QDBusConnection::ExportAdaptors);
reloadPlugins();
} }
Device::Device(const QString& id, const QString& name, DeviceLink* link) 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); QDBusConnection::sessionBus().registerObject("/modules/kdeconnect/devices/"+id, this, QDBusConnection::ExportScriptableContents | QDBusConnection::ExportAdaptors);
addLink(link); addLink(link);
reloadPlugins();
} }
/* /*
Device::Device(const QString& id, const QString& name, DeviceLink* link) 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); 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<QString,QString> 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) void Device::setPair(bool b)
{ {
qDebug() << "setPair" << b; qDebug() << "setPair" << b;
@ -122,10 +168,10 @@ void Device::privateReceivedPackage(const NetworkPackage& np)
if (np.type() == "kdeconnect.identity" && !m_knownIdentiy) { if (np.type() == "kdeconnect.identity" && !m_knownIdentiy) {
m_deviceName = np.get<QString>("deviceName"); m_deviceName = np.get<QString>("deviceName");
} else if (m_paired) { } else if (m_paired) {
qDebug() << "package received from paired device"; qDebug() << "package received from trusted device";
emit receivedPackage(*this, np); Q_EMIT receivedPackage(np);
} else { } else {
qDebug() << "not paired, ignoring package"; qDebug() << "device" << name() << "not trusted, ignoring package" << np.type();
} }
} }

View file

@ -28,6 +28,7 @@
#include "devicelinks/devicelink.h" #include "devicelinks/devicelink.h"
class DeviceLink; class DeviceLink;
class PackageInterface;
class Device class Device
: public QObject : public QObject
@ -38,7 +39,6 @@ class Device
Q_PROPERTY(QString name READ name) Q_PROPERTY(QString name READ name)
public: public:
//Device known from KConfig, we trust it but we need to wait for a incoming devicelink to communicate //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); Device(const QString& id, const QString& name);
@ -56,19 +56,20 @@ public:
void addLink(DeviceLink*); void addLink(DeviceLink*);
void removeLink(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 QStringList availableLinks() const;
Q_SCRIPTABLE bool paired() const { return m_paired; } Q_SCRIPTABLE bool paired() const { return m_paired; }
Q_SCRIPTABLE bool reachable() const { return !m_deviceLinks.empty(); } 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 setPair(bool b);
Q_SCRIPTABLE void reloadPlugins();
Q_SCRIPTABLE void sendPing(); Q_SCRIPTABLE void sendPing();
Q_SIGNALS: Q_SIGNALS:
@ -83,9 +84,12 @@ private:
QString m_deviceId; QString m_deviceId;
QString m_deviceName; QString m_deviceName;
QList<DeviceLink*> m_deviceLinks; QList<DeviceLink*> m_deviceLinks;
QList<PackageInterface*> m_plugins;
bool m_knownIdentiy; bool m_knownIdentiy;
}; };
Q_DECLARE_METATYPE(Device*)
#endif // DEVICE_H #endif // DEVICE_H

View file

@ -1,2 +1,5 @@
install(FILES kdeconnect_package_interface.desktop DESTINATION ${SERVICETYPES_INSTALL_DIR})
add_subdirectory(ping) add_subdirectory(ping)

View file

@ -20,8 +20,17 @@
#include "packageinterface.h" #include "packageinterface.h"
PackageInterface::PackageInterface(QObject* parent) #include <QPointer>
#include "../device.h"
PackageInterface::PackageInterface(QObject* parent, const QVariantList& args)
: QObject(parent) : 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;
} }

View file

@ -22,6 +22,7 @@
#define PACKAGEINTERFACE_H #define PACKAGEINTERFACE_H
#include <QObject> #include <QObject>
#include <QVariantList>
#include <kdemacros.h> #include <kdemacros.h>
#include <KPluginFactory> #include <KPluginFactory>
@ -40,17 +41,18 @@ class KDE_EXPORT PackageInterface
Q_OBJECT Q_OBJECT
public: public:
PackageInterface(QObject* parent = 0); PackageInterface(QObject* parent, const QVariantList& args);
virtual ~PackageInterface() { } virtual ~PackageInterface() { }
Device* device();
public Q_SLOTS: public Q_SLOTS:
//Returns true if it has handled the package in some way //Returns true if it has handled the package in some way
//device.sendPackage can be used to send an answer back to the device //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 #endif

View file

@ -8,11 +8,6 @@ X-KDE-PluginInfo-Email=albertvaka@gmail.com
X-KDE-PluginInfo-Name=kdeconnect_ping X-KDE-PluginInfo-Name=kdeconnect_ping
X-KDE-PluginInfo-Version=0.1 X-KDE-PluginInfo-Version=0.1
X-KDE-PluginInfo-Website=http://albertvaka.wordpress.com 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-License=GPL
X-KDE-PluginInfo-EnabledByDefault=true
X-KDE-ParentApp=kdeconnect
X-KDE-Version=4.0
Name=Ping Name=Ping
Comment=Send and receive pings Comment=Send and receive pings

View file

@ -20,19 +20,20 @@
#include "pingpackageinterface.h" #include "pingpackageinterface.h"
#include <KDebug> #include <KNotification>
#include <kicon.h> #include <KIcon>
#include <QDebug>
K_PLUGIN_FACTORY( KdeConnectPluginFactory, registerPlugin< PingPackageInterface >(); ) K_PLUGIN_FACTORY( KdeConnectPluginFactory, registerPlugin< PingPackageInterface >(); )
K_EXPORT_PLUGIN( KdeConnectPluginFactory("kdeconnect_ping", "kdeconnect_ping") ) K_EXPORT_PLUGIN( KdeConnectPluginFactory("kdeconnect_ping", "kdeconnect_ping") )
PingPackageInterface::PingPackageInterface(QObject* parent, const QVariantList& args) 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; 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->setPixmap(KIcon("dialog-ok").pixmap(48, 48));
notification->setComponentData(KComponentData("kdeconnect", "kdeconnect")); notification->setComponentData(KComponentData("kdeconnect", "kdeconnect"));
notification->setTitle("Ping!"); notification->setTitle("Ping!");
notification->setText(device.name()); notification->setText(device()->name());
notification->sendEvent(); notification->sendEvent();
return true; return true;

View file

@ -21,7 +21,7 @@
#ifndef PINGPACKAGEINTERFACE_H #ifndef PINGPACKAGEINTERFACE_H
#define PINGPACKAGEINTERFACE_H #define PINGPACKAGEINTERFACE_H
#include <knotification.h> #include <QObject>
#include "../packageinterface.h" #include "../packageinterface.h"
@ -33,7 +33,8 @@ class KDE_EXPORT PingPackageInterface
public: public:
explicit PingPackageInterface(QObject *parent, const QVariantList &args); 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);
}; };

View file

@ -21,49 +21,58 @@
#include "pluginloader.h" #include "pluginloader.h"
#include "packageinterface.h" #include "packageinterface.h"
#include "plugins/ping/pingpackageinterface.h"
#include <KServiceTypeTrader> #include <KServiceTypeTrader>
#include <KDebug> #include <KDebug>
PluginLoader::PluginLoader(QObject * parent) #include "../device.h"
: QObject(parent)
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"); KService::List offers = KServiceTypeTrader::self()->query("KdeConnect/Plugin");
for(KService::List::const_iterator iter = offers.begin(); iter < offers.end(); ++iter) {
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; KService::Ptr service = *iter;
plugins[service->library()] = service;
}
}
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(); KPluginFactory *factory = KPluginLoader(service->library()).factory();
if (!factory) {
if (!factory) qDebug() << "KPluginFactory could not load the plugin:" << service->library();
{ return NULL;
//KMessageBox::error(0, i18n("<html><p>KPluginFactory could not load the plugin:<br /><i>%1</i></p></html>",
// service->library()));
kError(5001) << "KPluginFactory could not load the plugin:" << service->library();
continue;
} }
PackageInterface *plugin = factory->create<PackageInterface>(this); QVariant deviceVariant;
deviceVariant.setValue<Device*>(device);
if (plugin) { //FIXME: create<PackageInterface> return NULL
kDebug() << "Load plugin:" << service->name(); QObject *plugin = factory->create<QObject>(device, QVariantList() << deviceVariant);
emit pluginLoaded(plugin); if (!plugin) {
} else { qDebug() << "Error loading plugin";
kDebug() << error; return NULL;
}
} }
qDebug() << "Loaded plugin:" << service->name();
return (PackageInterface*)plugin;
} }

View file

@ -22,21 +22,29 @@
#define PACKAGEINTERFACELOADER_H #define PACKAGEINTERFACELOADER_H
#include <QObject> #include <QObject>
#include <QMap>
#include <QString>
#include "packageinterface.h" #include "packageinterface.h"
#include <KPluginFactory>
#include <KService>
class PluginLoader : public QObject class Device;
class PluginLoader
{ {
Q_OBJECT
public: public:
PluginLoader(QObject * parent); static PluginLoader* instance();
virtual ~PluginLoader(); PackageInterface* instantiatePluginForDevice(QString name, Device* device);
QStringList getPluginList();
private:
PluginLoader();
QMap<QString,KService::Ptr> plugins;
void loadAllPlugins();
signals:
void pluginLoaded(PackageInterface * plugin);
}; };
#endif #endif

View file

@ -25,7 +25,7 @@ target_link_libraries(kcm_kdeconnect
${QT_QTCORE_LIBRARY} ${QT_QTCORE_LIBRARY}
${QT_QTGUI_LIBRARY} ${QT_QTGUI_LIBRARY}
${KDE4_KDEUI_LIBRARY} ${KDE4_KDEUI_LIBRARY}
${KDE4_KIO_LIBRARY} ${KDE4_KCMUTILS_LIBS}
) )
add_dependencies(kcm_kdeconnect add_dependencies(kcm_kdeconnect

View file

@ -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()) { if (!index.isValid() || index.row() < 0 || index.row() >= m_deviceList.count()) {
return QVariant(); return QVariant();
} }

View file

@ -32,6 +32,8 @@
#include <QDBusConnection> #include <QDBusConnection>
#include <QDBusInterface> #include <QDBusInterface>
#include <KServiceTypeTrader>
#include <KPluginInfo>
#include <KDebug> #include <KDebug>
#include <kpluginfactory.h> #include <kpluginfactory.h>
#include <kstandarddirs.h> #include <kstandarddirs.h>
@ -43,7 +45,8 @@ KdeConnectKcm::KdeConnectKcm(QWidget *parent, const QVariantList&)
: KCModule(KdeConnectKcmFactory::componentData(), parent) : KCModule(KdeConnectKcmFactory::componentData(), parent)
, kcmUi(new Ui::KdeConnectKcmUi()) , kcmUi(new Ui::KdeConnectKcmUi())
, pairedDevicesList(new DevicesModel(this)) , pairedDevicesList(new DevicesModel(this))
, config(KSharedConfig::openConfig("kdeconnectrc")) , currentDevice(0)
//, config(KSharedConfig::openConfig("kdeconnectrc"))
{ {
kcmUi->setupUi(this); kcmUi->setupUi(this);
@ -52,6 +55,8 @@ KdeConnectKcm::KdeConnectKcm(QWidget *parent, const QVariantList&)
kcmUi->deviceInfo->setVisible(false); kcmUi->deviceInfo->setVisible(false);
setButtons(KCModule::NoAdditionalButton);
connect(kcmUi->deviceList, SIGNAL(pressed(QModelIndex)), this, SLOT(deviceSelected(QModelIndex))); connect(kcmUi->deviceList, SIGNAL(pressed(QModelIndex)), this, SLOT(deviceSelected(QModelIndex)));
connect(kcmUi->ping_button, SIGNAL(pressed()), this, SLOT(sendPing())); connect(kcmUi->ping_button, SIGNAL(pressed()), this, SLOT(sendPing()));
connect(kcmUi->trust_checkbox,SIGNAL(toggled(bool)), this, SLOT(trustedStateChanged(bool))); connect(kcmUi->trust_checkbox,SIGNAL(toggled(bool)), this, SLOT(trustedStateChanged(bool)));
@ -64,27 +69,63 @@ KdeConnectKcm::~KdeConnectKcm()
void KdeConnectKcm::deviceSelected(const QModelIndex& current) 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(); bool valid = current.isValid();
kcmUi->deviceInfo->setVisible(valid); kcmUi->deviceInfo->setVisible(valid);
if (!valid) return; if (!valid) return;
selectedIndex = current;
bool paired = pairedDevicesList->getDevice(current)->paired(); currentDevice = pairedDevicesList->getDevice(current);
kcmUi->trust_checkbox->setChecked(paired); kcmUi->deviceName->setText(currentDevice->name());
kcmUi->trust_checkbox->setChecked(currentDevice->paired());
KService::List offers = KServiceTypeTrader::self()->query("KdeConnect/Plugin");
QList<KPluginInfo> 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) void KdeConnectKcm::trustedStateChanged(bool b)
{ {
if (!selectedIndex.isValid()) return; if (!currentDevice) return;
DeviceDbusInterface* device = pairedDevicesList->getDevice(selectedIndex); currentDevice->setPair(b);
device->setPair(b); pairedDevicesList->deviceStatusChanged(currentDevice->id());
pairedDevicesList->deviceStatusChanged(device->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() void KdeConnectKcm::sendPing()
{ {
if (!selectedIndex.isValid()) return; if (!currentDevice) return;
pairedDevicesList->getDevice(selectedIndex)->sendPing(); currentDevice->sendPing();
} }

View file

@ -30,13 +30,13 @@
#include "wizard.h" #include "wizard.h"
#include "devicesmodel.h" #include "devicesmodel.h"
class Create;
class QModelIndex; class QModelIndex;
class AccountsModel; class AccountsModel;
class AccountWidget; class AccountWidget;
class QStackedLayout; class QStackedLayout;
class QItemSelectionModel; class QItemSelectionModel;
class QDBusInterface; class QDBusInterface;
class DeviceDbusInterface;
namespace Ui { namespace Ui {
class KdeConnectKcmUi; class KdeConnectKcmUi;
@ -50,17 +50,21 @@ public:
KdeConnectKcm(QWidget *parent, const QVariantList&); KdeConnectKcm(QWidget *parent, const QVariantList&);
virtual ~KdeConnectKcm(); virtual ~KdeConnectKcm();
private:
virtual void save();
private Q_SLOTS: private Q_SLOTS:
void deviceSelected(const QModelIndex& current); void deviceSelected(const QModelIndex& current);
void trustedStateChanged(bool); void trustedStateChanged(bool);
void pluginsConfigChanged();
void sendPing(); void sendPing();
private: private:
Ui::KdeConnectKcmUi* kcmUi; Ui::KdeConnectKcmUi* kcmUi;
DevicesModel* pairedDevicesList; DevicesModel* pairedDevicesList;
AddDeviceWizard* addDeviceWizard; AddDeviceWizard* addDeviceWizard;
KSharedConfigPtr config; DeviceDbusInterface* currentDevice;
QModelIndex selectedIndex; //KSharedConfigPtr config;
}; };

View file

@ -45,7 +45,16 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QGroupBox" name="deviceInfoBorder"> <widget class="QGroupBox" name="deviceInfoBorder_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QVBoxLayout" name="deviceInfoBorder">
<item>
<widget class="QGroupBox" name="deviceInfo">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred"> <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch> <horstretch>0</horstretch>
@ -56,30 +65,37 @@
<string/> <string/>
</property> </property>
<property name="flat"> <property name="flat">
<bool>false</bool> <bool>true</bool>
</property> </property>
<property name="checkable"> <property name="checkable">
<bool>false</bool> <bool>false</bool>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_2"> <layout class="QVBoxLayout" name="verticalLayout_2">
<item> <item>
<widget class="QGroupBox" name="deviceInfo"> <layout class="QHBoxLayout" name="horizontalLayout">
<property name="title">
<string/>
</property>
<property name="flat">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item> <item>
<spacer name="verticalSpacer_2"> <widget class="QLabel" name="deviceName">
<property name="font">
<font>
<pointsize>10</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Device</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation"> <property name="orientation">
<enum>Qt::Vertical</enum> <enum>Qt::Horizontal</enum>
</property> </property>
<property name="sizeHint" stdset="0"> <property name="sizeHint" stdset="0">
<size> <size>
<width>20</width> <width>40</width>
<height>215</height> <height>20</height>
</size> </size>
</property> </property>
</spacer> </spacer>
@ -110,18 +126,20 @@
</property> </property>
</widget> </widget>
</item> </item>
</layout>
</item>
<item> <item>
<spacer name="verticalSpacer"> <widget class="KPluginSelector" name="pluginSelector" native="true">
<property name="orientation"> <property name="sizePolicy">
<enum>Qt::Vertical</enum> <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property> </property>
<property name="sizeHint" stdset="0"> <property name="focusPolicy">
<size> <enum>Qt::WheelFocus</enum>
<width>20</width>
<height>215</height>
</size>
</property> </property>
</spacer> </widget>
</item> </item>
</layout> </layout>
</widget> </widget>
@ -131,6 +149,14 @@
</item> </item>
</layout> </layout>
</widget> </widget>
<customwidgets>
<customwidget>
<class>KPluginSelector</class>
<extends>QWidget</extends>
<header>kpluginselector.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/> <resources/>
<connections/> <connections/>
</ui> </ui>