allow loading of individual runners, including from packages

svn path=/trunk/KDE/kdelibs/; revision=1106782
This commit is contained in:
Aaron J. Seigo 2010-03-23 22:43:34 +00:00
parent f2e0fc2d93
commit b16960c73b
6 changed files with 183 additions and 84 deletions

View File

@ -45,16 +45,30 @@ namespace Plasma
K_GLOBAL_STATIC(QMutex, s_bigLock) K_GLOBAL_STATIC(QMutex, s_bigLock)
AbstractRunner::AbstractRunner(QObject *parent, const QString &serviceId) AbstractRunner::AbstractRunner(QObject *parent, const QString &path)
: QObject(parent), : QObject(parent),
d(new AbstractRunnerPrivate(this, KService::serviceByStorageId(serviceId))) d(new AbstractRunnerPrivate(this))
{ {
d->init(path);
}
AbstractRunner::AbstractRunner(const KService::Ptr service, QObject *parent)
: QObject(parent),
d(new AbstractRunnerPrivate(this))
{
d->init(service);
} }
AbstractRunner::AbstractRunner(QObject *parent, const QVariantList &args) AbstractRunner::AbstractRunner(QObject *parent, const QVariantList &args)
: QObject(parent), : QObject(parent),
d(new AbstractRunnerPrivate(this, KService::serviceByStorageId(args.count() > 0 ? args[0].toString() : QString()))) d(new AbstractRunnerPrivate(this))
{ {
if (args.count() > 0) {
KService::Ptr service = KService::serviceByStorageId(args[0].toString());
if (service) {
d->init(service);
}
}
} }
AbstractRunner::~AbstractRunner() AbstractRunner::~AbstractRunner()
@ -187,6 +201,7 @@ void AbstractRunner::clearActions()
QMimeData * AbstractRunner::mimeDataForMatch(const QueryMatch *match) QMimeData * AbstractRunner::mimeDataForMatch(const QueryMatch *match)
{ {
Q_UNUSED(match)
return 0; return 0;
} }
@ -274,37 +289,54 @@ void AbstractRunner::match(Plasma::RunnerContext &search)
QString AbstractRunner::name() const QString AbstractRunner::name() const
{ {
if (!d->runnerDescription.isValid()) { if (d->runnerDescription.isValid()) {
return objectName(); return d->runnerDescription.name();
} }
return d->runnerDescription.name(); if (d->package) {
return d->package->metadata().name();
}
return objectName();
} }
QIcon AbstractRunner::icon() const QIcon AbstractRunner::icon() const
{ {
if (!d->runnerDescription.isValid()) { if (d->runnerDescription.isValid()) {
return QIcon(); return KIcon(d->runnerDescription.icon());
} }
return KIcon(d->runnerDescription.icon()); if (d->package) {
return KIcon(d->package->metadata().icon());
}
return QIcon();
} }
QString AbstractRunner::id() const QString AbstractRunner::id() const
{ {
if (!d->runnerDescription.isValid()) { if (d->runnerDescription.isValid()) {
return objectName(); return d->runnerDescription.pluginName();
} }
return d->runnerDescription.pluginName();
if (d->package) {
return d->package->metadata().pluginName();
}
return objectName();
} }
QString AbstractRunner::description() const QString AbstractRunner::description() const
{ {
if (!d->runnerDescription.isValid()) { if (!d->runnerDescription.isValid()) {
return objectName(); return d->runnerDescription.property("Comment").toString();
} }
return d->runnerDescription.property("Comment").toString(); if (d->package) {
return d->package->metadata().description();
}
return objectName();
} }
const Package* AbstractRunner::package() const const Package* AbstractRunner::package() const
@ -326,37 +358,17 @@ DataEngine *AbstractRunner::dataEngine(const QString &name) const
return d->dataEngine(name); return d->dataEngine(name);
} }
AbstractRunnerPrivate::AbstractRunnerPrivate(AbstractRunner *r, KService::Ptr service) AbstractRunnerPrivate::AbstractRunnerPrivate(AbstractRunner *r)
: priority(AbstractRunner::NormalPriority), : priority(AbstractRunner::NormalPriority),
speed(AbstractRunner::NormalSpeed), speed(AbstractRunner::NormalSpeed),
blackListed(0), blackListed(0),
script(0), script(0),
runnerDescription(service),
runner(r), runner(r),
fastRuns(0), fastRuns(0),
package(0), package(0),
hasRunOptions(false), hasRunOptions(false),
defaultSyntax(0) defaultSyntax(0)
{ {
if (runnerDescription.isValid()) {
const QString api = runnerDescription.property("X-Plasma-API").toString();
if (!api.isEmpty()) {
const QString path = KStandardDirs::locate("data",
"plasma/runners/" + runnerDescription.pluginName() + '/');
PackageStructure::Ptr structure =
Plasma::packageStructure(api, Plasma::RunnerComponent);
structure->setPath(path);
package = new Package(path, structure);
script = Plasma::loadScriptEngine(api, runner);
if (!script) {
kDebug() << "Could not create a(n)" << api << "ScriptEngine for the"
<< runnerDescription.name() << "Runner.";
delete package;
package = 0;
}
}
}
} }
AbstractRunnerPrivate::~AbstractRunnerPrivate() AbstractRunnerPrivate::~AbstractRunnerPrivate()
@ -367,6 +379,58 @@ AbstractRunnerPrivate::~AbstractRunnerPrivate()
package = 0; package = 0;
} }
void AbstractRunnerPrivate::init(const KService::Ptr service)
{
runnerDescription = KPluginInfo(service);
if (runnerDescription.isValid()) {
const QString api = runnerDescription.property("X-Plasma-API").toString();
if (!api.isEmpty()) {
const QString path = KStandardDirs::locate("data", "plasma/runners/" + runnerDescription.pluginName() + '/');
prepScripting(path, api);
if (!script) {
kDebug() << "Could not create a(n)" << api << "ScriptEngine for the" << runnerDescription.name() << "Runner.";
}
}
}
}
void AbstractRunnerPrivate::init(const QString &path)
{
prepScripting(path);
}
void AbstractRunnerPrivate::prepScripting(const QString &path, QString api)
{
if (script) {
return;
}
if (package) {
delete package;
}
PackageStructure::Ptr structure = Plasma::packageStructure(api, Plasma::RunnerComponent);
structure->setPath(path);
package = new Package(path, structure);
if (!package->isValid()) {
kDebug() << "Invalid Runner package at" << path;
delete package;
package = 0;
return;
}
if (api.isEmpty()) {
api = package->metadata().implementationApi();
}
script = Plasma::loadScriptEngine(api, runner);
if (!script) {
delete package;
package = 0;
}
}
// put all setup routines for script here. at this point we can assume that // put all setup routines for script here. at this point we can assume that
// package exists and that we have a script engine // package exists and that we have a script engine
void AbstractRunnerPrivate::setupScriptSupport() void AbstractRunnerPrivate::setupScriptSupport()

View File

@ -281,12 +281,9 @@ class PLASMA_EXPORT AbstractRunner : public QObject
friend class RunnerManager; friend class RunnerManager;
friend class RunnerManagerPrivate; friend class RunnerManagerPrivate;
/** explicit AbstractRunner(QObject *parent = 0, const QString &path = QString());
* Constructs a Runner object. Since AbstractRunner has pure virtuals, explicit AbstractRunner(const KService::Ptr service, QObject *parent = 0);
* this constructor can not be called directly. Rather a subclass must
* be created
*/
explicit AbstractRunner(QObject *parent = 0, const QString &serviceId = QString());
AbstractRunner(QObject *parent, const QVariantList &args); AbstractRunner(QObject *parent, const QVariantList &args);
/** /**

View File

@ -111,7 +111,7 @@ class PLASMA_EXPORT Applet : public QGraphicsWidget
~Applet(); ~Applet();
/** /**
* @return a package structure representing a Theme * @return a package structure representing an Applet
*/ */
static PackageStructure::Ptr packageStructure(); static PackageStructure::Ptr packageStructure();

View File

@ -32,8 +32,11 @@ class AbstractRunner;
class AbstractRunnerPrivate : public DataEngineConsumer class AbstractRunnerPrivate : public DataEngineConsumer
{ {
public: public:
AbstractRunnerPrivate(AbstractRunner *r, KService::Ptr service); AbstractRunnerPrivate(AbstractRunner *r);
~AbstractRunnerPrivate(); ~AbstractRunnerPrivate();
void init(const KService::Ptr service);
void init(const QString &path);
void prepScripting(const QString &path, QString api = QString());
void setupScriptSupport(); void setupScriptSupport();
AbstractRunner::Priority priority; AbstractRunner::Priority priority;

View File

@ -153,21 +153,9 @@ public:
KService::List offers = KServiceTypeTrader::self()->query("Plasma/Runner", QString("[X-KDE-PluginInfo-Name] == '%1'").arg(singleModeRunnerId)); KService::List offers = KServiceTypeTrader::self()->query("Plasma/Runner", QString("[X-KDE-PluginInfo-Name] == '%1'").arg(singleModeRunnerId));
if (!offers.isEmpty()) { if (!offers.isEmpty()) {
const KService::Ptr &service = offers[0]; const KService::Ptr &service = offers[0];
QString api = service->property("X-Plasma-API").toString(); currentSingleRunner = loadInstalledRunner(service);
QString error;
if (api.isEmpty()) {
QVariantList args;
args << service->storageId();
if (Plasma::isPluginVersionCompatible(KPluginLoader(*service).pluginVersion())) {
currentSingleRunner = service->createInstance<AbstractRunner>(q, args, &error);
}
} else {
currentSingleRunner = new AbstractRunner(q, service->storageId());
}
if (currentSingleRunner) { if (currentSingleRunner) {
QMetaObject::invokeMethod(currentSingleRunner, "init");
emit currentSingleRunner->prepare(); emit currentSingleRunner->prepare();
singleRunnerWasLoaded = true; singleRunnerWasLoaded = true;
} }
@ -201,7 +189,7 @@ public:
} }
KPluginInfo description(service); KPluginInfo description(service);
QString runnerName = description.pluginName(); const QString runnerName = description.pluginName();
description.load(pluginConf); description.load(pluginConf);
const bool loaded = runners.contains(runnerName); const bool loaded = runners.contains(runnerName);
@ -217,36 +205,10 @@ public:
//kDebug() << loadAll << description.isPluginEnabled() << noWhiteList << whiteList.contains(runnerName); //kDebug() << loadAll << description.isPluginEnabled() << noWhiteList << whiteList.contains(runnerName);
if (selected) { if (selected) {
if (!loaded) { if (!loaded) {
QString api = service->property("X-Plasma-API").toString(); AbstractRunner *runner = loadInstalledRunner(service);
QString error;
AbstractRunner *runner = 0;
if (api.isEmpty()) {
QVariantList args;
args << service->storageId();
if (Plasma::isPluginVersionCompatible(KPluginLoader(*service).pluginVersion())) {
runner = service->createInstance<AbstractRunner>(q, args, &error);
}
} else {
//kDebug() << "got a script runner known as" << api;
runner = new AbstractRunner(q, service->storageId());
}
if (runner) { if (runner) {
kDebug() << "================= loading runner:" << service->name() << "=================";
/*
foreach (const RunnerSyntax &syntax, runner->syntaxes()) {
kDebug() << syntax.exampleQueriesWithTermDescription().join(", ") << " ==> " << syntax.description();
}
*/
QMetaObject::invokeMethod(runner, "init");
runners.insert(runnerName, runner); runners.insert(runnerName, runner);
} else {
kDebug() << "failed to load runner:" << service->name()
<< ". error reported:" << error;
continue;
} }
} }
} else if (loaded) { } else if (loaded) {
@ -260,6 +222,34 @@ public:
kDebug() << "All runners loaded, total:" << runners.count(); kDebug() << "All runners loaded, total:" << runners.count();
} }
AbstractRunner *loadInstalledRunner(const KService::Ptr service)
{
AbstractRunner *runner = 0;
const QString api = service->property("X-Plasma-API").toString();
if (api.isEmpty()) {
QVariantList args;
args << service->storageId();
if (Plasma::isPluginVersionCompatible(KPluginLoader(*service).pluginVersion())) {
QString error;
runner = service->createInstance<AbstractRunner>(q, args, &error);
if (!runner) {
kDebug() << "Failed to load runner:" << service->name() << ". error reported:" << error;
}
}
} else {
//kDebug() << "got a script runner known as" << api;
runner = new AbstractRunner(service, q);
}
if (runner) {
kDebug() << "================= loading runner:" << service->name() << "=================";
QMetaObject::invokeMethod(runner, "init");
}
return runner;
}
void jobDone(ThreadWeaver::Job *job) void jobDone(ThreadWeaver::Job *job)
{ {
FindMatchesJob *runJob = dynamic_cast<FindMatchesJob *>(job); FindMatchesJob *runJob = dynamic_cast<FindMatchesJob *>(job);
@ -420,6 +410,28 @@ QStringList RunnerManager::allowedRunners() const
return config.readEntry("pluginWhiteList", QStringList()); return config.readEntry("pluginWhiteList", QStringList());
} }
void RunnerManager::loadRunner(const KService::Ptr service)
{
KPluginInfo description(service);
const QString runnerName = description.pluginName();
if (!runnerName.isEmpty() && !d->runners.contains(runnerName)) {
AbstractRunner *runner = d->loadInstalledRunner(service);
if (runner) {
d->runners.insert(runnerName, runner);
}
}
}
void RunnerManager::loadRunner(const QString &path)
{
if (!d->runners.contains(path)) {
AbstractRunner *runner = new AbstractRunner(this, path);
if (runner) {
d->runners.insert(path, runner);
}
}
}
AbstractRunner* RunnerManager::runner(const QString &name) const AbstractRunner* RunnerManager::runner(const QString &name) const
{ {
if (d->runners.isEmpty()) { if (d->runners.isEmpty()) {

View File

@ -162,6 +162,29 @@ class PLASMA_EXPORT RunnerManager : public QObject
*/ */
void setAllowedRunners(const QStringList &runners); void setAllowedRunners(const QStringList &runners);
/**
* Attempts to add the AbstractRunner plugin represented
* by the KService passed in. Usually one can simply let
* the configuration of plugins handle loading Runner plugins,
* but in cases where specific runners should be loaded this
* allows for that to take place
*
* @arg service the service to use to load the plugin
* @since 4.5
*/
void loadRunner(const KService::Ptr service);
/**
* Attempts to add the AbstractRunner from a Plasma::Package on disk.
* Usually one can simply let the configuration of plugins
* handle loading Runner plugins, but in cases where specific
* runners should be loaded this allows for that to take place
*
* @arg path the path to a Runner package to load
* @since 4.5
*/
void loadRunner(const QString &path);
/** /**
* @return the list of allowed plugins * @return the list of allowed plugins
* @since 4.4 * @since 4.4