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:
parent
9b7eecc69d
commit
88fab1f333
18 changed files with 337 additions and 188 deletions
42
README
42
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
|
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.
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -1,2 +1,5 @@
|
||||||
|
|
||||||
|
install(FILES kdeconnect_package_interface.desktop DESTINATION ${SERVICETYPES_INSTALL_DIR})
|
||||||
|
|
||||||
add_subdirectory(ping)
|
add_subdirectory(ping)
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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"
|
||||||
|
|
||||||
|
@ -32,8 +32,9 @@ 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);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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::Ptr service = *iter;
|
||||||
|
plugins[service->library()] = service;
|
||||||
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("<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);
|
|
||||||
|
|
||||||
if (plugin) {
|
|
||||||
kDebug() << "Load plugin:" << service->name();
|
|
||||||
emit pluginLoaded(plugin);
|
|
||||||
} else {
|
|
||||||
kDebug() << error;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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*>(device);
|
||||||
|
|
||||||
|
//FIXME: create<PackageInterface> return NULL
|
||||||
|
QObject *plugin = factory->create<QObject>(device, QVariantList() << deviceVariant);
|
||||||
|
if (!plugin) {
|
||||||
|
qDebug() << "Error loading plugin";
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug() << "Loaded plugin:" << service->name();
|
||||||
|
return (PackageInterface*)plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -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:
|
|
||||||
PluginLoader(QObject * parent);
|
|
||||||
virtual ~PluginLoader();
|
|
||||||
|
|
||||||
void loadAllPlugins();
|
public:
|
||||||
|
static PluginLoader* instance();
|
||||||
|
PackageInterface* instantiatePluginForDevice(QString name, Device* device);
|
||||||
|
QStringList getPluginList();
|
||||||
|
|
||||||
|
private:
|
||||||
|
PluginLoader();
|
||||||
|
QMap<QString,KService::Ptr> plugins;
|
||||||
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void pluginLoaded(PackageInterface * plugin);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
61
kcm/kcm.cpp
61
kcm/kcm.cpp
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
12
kcm/kcm.h
12
kcm/kcm.h
|
@ -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;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
132
kcm/kcm.ui
132
kcm/kcm.ui
|
@ -45,84 +45,102 @@
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QGroupBox" name="deviceInfoBorder">
|
<widget class="QGroupBox" name="deviceInfoBorder_2">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||||
<horstretch>0</horstretch>
|
<horstretch>0</horstretch>
|
||||||
<verstretch>0</verstretch>
|
<verstretch>0</verstretch>
|
||||||
</sizepolicy>
|
</sizepolicy>
|
||||||
</property>
|
</property>
|
||||||
<property name="title">
|
<layout class="QVBoxLayout" name="deviceInfoBorder">
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
<property name="flat">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<property name="checkable">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
|
||||||
<item>
|
<item>
|
||||||
<widget class="QGroupBox" name="deviceInfo">
|
<widget class="QGroupBox" name="deviceInfo">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string/>
|
<string/>
|
||||||
</property>
|
</property>
|
||||||
<property name="flat">
|
<property name="flat">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
<property name="checkable">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
<item>
|
<item>
|
||||||
<spacer name="verticalSpacer_2">
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
<property name="orientation">
|
<item>
|
||||||
<enum>Qt::Vertical</enum>
|
<widget class="QLabel" name="deviceName">
|
||||||
</property>
|
<property name="font">
|
||||||
<property name="sizeHint" stdset="0">
|
<font>
|
||||||
<size>
|
<pointsize>10</pointsize>
|
||||||
<width>20</width>
|
<weight>75</weight>
|
||||||
<height>215</height>
|
<bold>true</bold>
|
||||||
</size>
|
</font>
|
||||||
</property>
|
</property>
|
||||||
</spacer>
|
<property name="text">
|
||||||
|
<string>Device</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="trust_checkbox">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Trust this device</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="ping_button">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Send ping</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QCheckBox" name="trust_checkbox">
|
<widget class="KPluginSelector" name="pluginSelector" native="true">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||||
<horstretch>0</horstretch>
|
<horstretch>0</horstretch>
|
||||||
<verstretch>0</verstretch>
|
<verstretch>0</verstretch>
|
||||||
</sizepolicy>
|
</sizepolicy>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="focusPolicy">
|
||||||
<string>Trust this device</string>
|
<enum>Qt::WheelFocus</enum>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="ping_button">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Send ping</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<spacer name="verticalSpacer">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Vertical</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>20</width>
|
|
||||||
<height>215</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@ -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>
|
||||||
|
|
Loading…
Reference in a new issue