diff --git a/abstractrunner.cpp b/abstractrunner.cpp index 966ddaf42..69cbfcf2b 100644 --- a/abstractrunner.cpp +++ b/abstractrunner.cpp @@ -23,8 +23,11 @@ #include #include +#include #include +#include +#include "scripting/runnerscript.h" #include "searchcontext.h" namespace Plasma @@ -38,21 +41,47 @@ class AbstractRunner::Private Priority priority; Speed speed; int tier; + RunnerScript* script; + KPluginInfo runnerDescription; + AbstractRunner* runner; - Private() + Private(AbstractRunner* r, KService::Ptr service) : priority(NormalPriority), speed(NormalSpeed), - tier(0) - {} + tier(0), + script(0), + runnerDescription(service), + runner(r) + { + if (runnerDescription.isValid()) { + QString language = runnerDescription.property("X-Plasma-Language").toString(); + + if (!language.isEmpty()) { + script = Plasma::loadScriptEngine(language, runner); + if (!script) { + kDebug() << "Could not create a" << language << "ScriptEngine for the" + << runnerDescription.name() << "Runner."; + } else { + QTimer::singleShot(0, runner, SLOT(init())); + } + } + } + } static QMutex serviceTypeTraderLock; }; QMutex AbstractRunner::Private::serviceTypeTraderLock; -AbstractRunner::AbstractRunner(QObject* parent) +AbstractRunner::AbstractRunner(QObject* parent, const QString& serviceId) : QObject(parent), - d(new Private()) + d(new Private(this, KService::serviceByStorageId(serviceId))) +{ +} + +AbstractRunner::AbstractRunner(QObject* parent, const QVariantList& args) + : QObject(parent), + d(new Private(this, KService::serviceByStorageId(args.count() > 0 ? args[0].toString() : QString()))) { } @@ -139,7 +168,7 @@ void AbstractRunner::setSpeed(Speed speed) // { // return d->tier; // } -// +// // void AbstractRunner::setTier(int tier) // { // d->tier = tier; @@ -163,7 +192,31 @@ KService::List AbstractRunner::serviceQuery(const QString &serviceType, const QS void AbstractRunner::exec(Plasma::SearchMatch *action) { - Q_UNUSED(action) + if (d->script) { + return d->script->exec(action); + } +} + +void AbstractRunner::match(Plasma::SearchContext *search) +{ + if (d->script) { + return d->script->match(search); + } +} + +QString AbstractRunner::runnerName() const +{ + if (!d->runnerDescription.isValid()) { + return QString(); + } + return d->runnerDescription.property("X-Plasma-RunnerName").toString(); +} + +void AbstractRunner::init() +{ + if (d->script) { + d->script->init(); + } } AbstractRunner::List AbstractRunner::loadRunners(QObject* parent, const QStringList& whitelist) @@ -174,9 +227,17 @@ AbstractRunner::List AbstractRunner::loadRunners(QObject* parent, const QStringL KService::List offers = KServiceTypeTrader::self()->query("Plasma/Runner"); QString error; + QVariantList allArgs; foreach (KService::Ptr service, offers) { if( whitelist.empty() || whitelist.contains( service->name() ) ) { - AbstractRunner* runner = service->createInstance(parent, QVariantList(), &error); + allArgs << service->storageId(); + QString language = service->property("X-Plasma-Language").toString(); + AbstractRunner* runner; + if (language.isEmpty()) { + runner = service->createInstance(parent, allArgs, &error); + } else { + runner = new AbstractRunner(parent, service->storageId()); + } if (runner) { //kDebug() << "loaded runner : " << service->name(); QString phase = service->property("X-Plasma-RunnerPhase").toString(); diff --git a/abstractrunner.h b/abstractrunner.h index 6a7119375..99dbd856c 100644 --- a/abstractrunner.h +++ b/abstractrunner.h @@ -35,6 +35,8 @@ class KCompletion; namespace Plasma { +class RunnerScript; + /** * An abstract base class for Plasma Runner plugins * @@ -73,7 +75,8 @@ class PLASMA_EXPORT AbstractRunner : public QObject * this constructor can not be called directly. Rather a subclass must * be created */ - explicit AbstractRunner(QObject* parent = 0); + explicit AbstractRunner(QObject* parent = 0, const QString& serviceId = QString()); + AbstractRunner(QObject* parent, const QVariantList& args); virtual ~AbstractRunner(); /** @@ -94,7 +97,7 @@ class PLASMA_EXPORT AbstractRunner : public QObject * * The match will be activated if the user selects it. * - * If this runner's exact match is selected, it will be passed into + * If this runner's exact match is selected, it will be passed into * the exec method. * @see exec * @@ -102,7 +105,7 @@ class PLASMA_EXPORT AbstractRunner : public QObject * to return from this method right away, nor to create all matches * here. */ - virtual void match(Plasma::SearchContext *search) = 0; + virtual void match(Plasma::SearchContext *search); /** * Triggers a call to match. @@ -166,6 +169,11 @@ class PLASMA_EXPORT AbstractRunner : public QObject */ Priority priority() const; + /** + * Returns the engine name for the Runner + */ + QString runnerName() const; + protected: /** * Sets whether or not the the runner has options for matches @@ -178,9 +186,9 @@ class PLASMA_EXPORT AbstractRunner : public QObject void setIsConfigurable(bool canBeConfigured); /** - * Sets the nominal speed of the runner. Only slow runners need - * to call this within their constructor because the default - * speed is NormalSpeed. Runners that use DBUS should call + * Sets the nominal speed of the runner. Only slow runners need + * to call this within their constructor because the default + * speed is NormalSpeed. Runners that use DBUS should call * this within their constructors. */ void setSpeed(Speed newSpeed); @@ -213,6 +221,9 @@ class PLASMA_EXPORT AbstractRunner : public QObject KService::List serviceQuery(const QString &serviceType, const QString &constraint = QString()) const; + protected slots: + void init(); + private: class Private; Private* const d; diff --git a/dataengine.cpp b/dataengine.cpp index c1ff56ff2..d93c5a0d0 100644 --- a/dataengine.cpp +++ b/dataengine.cpp @@ -26,8 +26,11 @@ #include #include +#include +#include #include "datacontainer.h" +#include "scripting/dataenginescript.h" namespace Plasma { @@ -35,17 +38,31 @@ namespace Plasma class DataEngine::Private { public: - Private(DataEngine* e) + Private(DataEngine* e, KService::Ptr service) : engine(e), ref(0), updateTimerId(0), minUpdateInterval(-1), limit(0), - valid(true) + valid(true), + script(0), + dataEngineDescription(service) { updateTimer = new QTimer(engine); updateTimer->setSingleShot(true); updateTimestamp.start(); + + if (dataEngineDescription.isValid()) { + QString language = dataEngineDescription.property("X-Plasma-Language").toString(); + + if (!language.isEmpty()) { + script = Plasma::loadScriptEngine(language, engine); + if (!script) { + kDebug() << "Could not create a" << language << "ScriptEngine for the" + << dataEngineDescription.name() << "DataEngine."; + } + } + } } DataContainer* source(const QString& sourceName, bool createWhenMissing = true) @@ -167,12 +184,24 @@ class DataEngine::Private QString icon; uint limit; bool valid; + DataEngineScript* script; + KPluginInfo dataEngineDescription; }; -DataEngine::DataEngine(QObject* parent) +DataEngine::DataEngine(QObject* parent, const QString& serviceId) : QObject(parent), - d(new Private(this)) + d(new Private(this, KService::serviceByStorageId(serviceId))) +{ + connect(d->updateTimer, SIGNAL(timeout()), this, SLOT(checkForUpdates())); + //FIXME: we should delay this call; to when is the question. + //Update DataEngine::init() api docu when fixed + QTimer::singleShot(0, this, SLOT(startInit())); +} + +DataEngine::DataEngine(QObject* parent, const QVariantList& args) + : QObject(parent), + d(new Private(this, KService::serviceByStorageId(args.count() > 0 ? args[0].toString() : QString()))) { connect(d->updateTimer, SIGNAL(timeout()), this, SLOT(checkForUpdates())); //FIXME: we should delay this call; to when is the question. @@ -267,22 +296,32 @@ void DataEngine::internalUpdateSource(DataContainer* source) void DataEngine::init() { - // kDebug() << "DataEngine::init() called "; - // default implementation does nothing. this is for engines that have to - // start things in motion external to themselves before they can work + if (d->script) { + d->script->init(); + } else { + // kDebug() << "DataEngine::init() called "; + // default implementation does nothing. this is for engines that have to + // start things in motion external to themselves before they can work + } } bool DataEngine::sourceRequested(const QString &name) { - Q_UNUSED(name) - return false; + if (d->script) { + return d->script->sourceRequested(name); + } else { + return false; + } } bool DataEngine::updateSource(const QString& source) { - Q_UNUSED(source); - //kDebug() << "updateSource source" << endl; - return false; //TODO: should this be true to trigger, even needless, updates on every tick? + if (d->script) { + return d->script->updateSource(source); + } else { + //kDebug() << "updateSource source" << endl; + return false; //TODO: should this be true to trigger, even needless, updates on every tick? + } } void DataEngine::setData(const QString& source, const QVariant& value) @@ -488,6 +527,15 @@ void DataEngine::checkForUpdates() } } +QString DataEngine::engineName() const +{ + if (!d->dataEngineDescription.isValid()) { + return QString(); + } + + return d->dataEngineDescription.property("X-Plasma-EngineName").toString(); +} + } #include "dataengine.moc" diff --git a/dataengine.h b/dataengine.h index 6a1d9e0f1..2132529b5 100644 --- a/dataengine.h +++ b/dataengine.h @@ -33,6 +33,7 @@ namespace Plasma { class DataContainer; +class DataEngineScript; /** * @class DataEngine @@ -50,6 +51,7 @@ class DataContainer; **/ class PLASMA_EXPORT DataEngine : public QObject { + friend class DataEngineScript; Q_OBJECT Q_PROPERTY( QStringList sources READ sources ) Q_PROPERTY( bool valid READ isValid ) @@ -66,7 +68,8 @@ class PLASMA_EXPORT DataEngine : public QObject * * @param parent The parent object. **/ - explicit DataEngine(QObject* parent = 0); + explicit DataEngine(QObject* parent = 0, const QString& serviceId = QString()); + DataEngine(QObject* parent, const QVariantList& args); virtual ~DataEngine(); /** @@ -77,6 +80,11 @@ class PLASMA_EXPORT DataEngine : public QObject **/ virtual QStringList sources() const; + /** + * Returns the engine name for the DataEngine + */ + QString engineName() const; + /** * Connects a source to an object for data updates. The object must * have a slot with the following signature: @@ -135,7 +143,7 @@ class PLASMA_EXPORT DataEngine : public QObject /** * Retrevies a pointer to the DataContainer for a given source. This method - * should not be used if possible. An exception is for script engines that + * should not be used if possible. An exception is for script engines that * can not provide a QMetaObject as required by connectSource for the initial * call to dataUpdated. Using this method, such engines can provide their own * connectSource API. @@ -170,7 +178,7 @@ class PLASMA_EXPORT DataEngine : public QObject void deref(); /** - * Reference counting method. Used to determine if this DataEngine is + * Reference counting method. Used to determine if this DataEngine is * used. * @return true if the reference count is non-zero **/ diff --git a/dataenginemanager.cpp b/dataenginemanager.cpp index a3fa11316..fd44bd0f8 100644 --- a/dataenginemanager.cpp +++ b/dataenginemanager.cpp @@ -18,6 +18,7 @@ */ #include "dataenginemanager.h" +#include "scripting/scriptengine.h" #include #include @@ -119,11 +120,18 @@ Plasma::DataEngine* DataEngineManager::loadDataEngine(const QString& name) KService::List offers = KServiceTypeTrader::self()->query("Plasma/DataEngine", constraint); QString error; + QVariantList allArgs; + allArgs << offers.first()->storageId(); if (offers.isEmpty()) { kDebug() << "offers are empty for " << name << " with constraint " << constraint; } else { - engine = offers.first()->createInstance(0, QVariantList(), &error); + QString language = offers.first()->property("X-Plasma-Language").toString(); + if (language.isEmpty()) { + engine = offers.first()->createInstance(0, allArgs, &error); + } else { + engine = new DataEngine(0, offers.first()->storageId()); + } } if (!engine) { diff --git a/scripting/dataenginescript.cpp b/scripting/dataenginescript.cpp index 9f4f4f532..68c220b9a 100644 --- a/scripting/dataenginescript.cpp +++ b/scripting/dataenginescript.cpp @@ -32,7 +32,7 @@ public: DataEngineScript::DataEngineScript(QObject *parent) : ScriptEngine(parent), - d(0) + d(new Private) { } @@ -51,6 +51,83 @@ DataEngine* DataEngineScript::dataEngine() const return d->dataEngine; } +bool DataEngineScript::sourceRequested(const QString &name) +{ + Q_UNUSED(name) + return false; +} + +bool DataEngineScript::updateSource(const QString& source) +{ + Q_UNUSED(source) + return false; +} + +void DataEngineScript::setData(const QString& source, const QString& key, + const QVariant& value) +{ + if (d->dataEngine) { + d->dataEngine->setData(source, key, value); + } +} + +void DataEngineScript::setData(const QString &source, const QVariant &value) +{ + if (d->dataEngine) { + d->dataEngine->setData(source, value); + } +} + +void DataEngineScript::clearData(const QString& source) +{ + if (d->dataEngine) { + d->dataEngine->clearData(source); + } +} + +void DataEngineScript::removeData(const QString& source, const QString& key) +{ + if (d->dataEngine) { + d->dataEngine->removeData(source, key); + } +} + +void DataEngineScript::setSourceLimit(uint limit) +{ + if (d->dataEngine) { + d->dataEngine->setSourceLimit(limit); + } +} + +void DataEngineScript::setMinimumUpdateInterval(int minimumMs) +{ + if (d->dataEngine) { + d->dataEngine->setMinimumUpdateInterval(minimumMs); + } +} + +int DataEngineScript::minimumUpdateInterval() const +{ + if (d->dataEngine) { + return d->dataEngine->minimumUpdateInterval(); + } + return 0; +} + +void DataEngineScript::setUpdateInterval(uint frequency) +{ + if (d->dataEngine) { + d->dataEngine->setUpdateInterval(frequency); + } +} + +void DataEngineScript::clearSources() +{ + if (d->dataEngine) { + d->dataEngine->clearSources(); + } +} + } // Plasma namespace #include "dataenginescript.moc" diff --git a/scripting/dataenginescript.h b/scripting/dataenginescript.h index d8848c3e7..12acda753 100644 --- a/scripting/dataenginescript.h +++ b/scripting/dataenginescript.h @@ -53,6 +53,37 @@ public: */ DataEngine* dataEngine() const; + /** + * Called when the script should create a source that does not currently + * exist. + * + * @param name the name of the source that should be created + * @return true if a DataContainer was set up, false otherwise + */ + virtual bool sourceRequested(const QString &name); + + /** + * Called when the script should refresh the data contained in a given + * source. + * + * @param source the name of the source that should be updated + * @return true if the data was changed, or false if there was no + * change or if the change will occur later + **/ + virtual bool updateSource(const QString& source); + +protected: + void setData(const QString& source, const QString& key, + const QVariant& value); + void setData(const QString &source, const QVariant &value); + void clearData(const QString& source); + void removeData(const QString& source, const QString& key); + void setSourceLimit(uint limit); + void setMinimumUpdateInterval(int minimumMs); + int minimumUpdateInterval() const; + void setUpdateInterval(uint frequency); + void clearSources(); + private: class Private; Private * const d; diff --git a/scripting/runnerscript.cpp b/scripting/runnerscript.cpp index fe5149d67..0aa6db530 100644 --- a/scripting/runnerscript.cpp +++ b/scripting/runnerscript.cpp @@ -32,7 +32,7 @@ public: RunnerScript::RunnerScript(QObject *parent) : ScriptEngine(parent), - d(0) + d(new Private) { } @@ -51,6 +51,16 @@ AbstractRunner* RunnerScript::runner() const return d->runner; } +void RunnerScript::match(Plasma::SearchContext *search) +{ + Q_UNUSED(search) +} + +void RunnerScript::exec(Plasma::SearchMatch *action) +{ + Q_UNUSED(action) +} + } // Plasma namespace #include "runnerscript.moc" diff --git a/scripting/runnerscript.h b/scripting/runnerscript.h index 6f06fc1f0..b8b621d97 100644 --- a/scripting/runnerscript.h +++ b/scripting/runnerscript.h @@ -27,6 +27,8 @@ namespace Plasma { class AbstractRunner; +class SearchContext; +class SearchMatch; class PLASMA_EXPORT RunnerScript : public ScriptEngine { @@ -53,6 +55,19 @@ public: */ AbstractRunner* runner() const; + /** + * Called when the script should create SearchMatch instances through + * SearchContext::addInformationalMatch, SearchContext::addExactMatch, and + * SearchContext::addPossibleMatch. + */ + virtual void match(Plasma::SearchContext *search); + + /** + * Called whenever an exact or possible match associated with this + * runner is triggered. + */ + virtual void exec(Plasma::SearchMatch *action); + private: class Private; Private * const d; diff --git a/scripting/scriptengine.cpp b/scripting/scriptengine.cpp index deb95bd52..db5933967 100644 --- a/scripting/scriptengine.cpp +++ b/scripting/scriptengine.cpp @@ -177,12 +177,24 @@ AppletScript* loadScriptEngine(const QString &language, Applet *applet) DataEngineScript* loadScriptEngine(const QString &language, DataEngine *dataEngine) { - return static_cast(loadEngine(language, DataEngineComponent, dataEngine)); + DataEngineScript *engine = static_cast(loadEngine(language, DataEngineComponent, dataEngine)); + + if (engine) { + engine->setDataEngine(dataEngine); + } + + return engine; } RunnerScript* loadScriptEngine(const QString &language, AbstractRunner *runner) { - return static_cast(loadEngine(language, RunnerComponent, runner)); + RunnerScript* engine = static_cast(loadEngine(language, RunnerComponent, runner)); + + if (engine) { + engine->setRunner(runner); + } + + return engine; } } // namespace Plasma diff --git a/servicetypes/plasma-runner.desktop b/servicetypes/plasma-runner.desktop index c0387959a..c8c3749dc 100644 --- a/servicetypes/plasma-runner.desktop +++ b/servicetypes/plasma-runner.desktop @@ -54,6 +54,9 @@ Comment[x-test]=xxKRunner pluginxx Comment[zh_CN]=KRunner 插件 Comment[zh_TW]=KRunner 外掛程式 +[PropertyDef::X-Plasma-RunnerName] +Type=QString + [PropertyDef::X-Plasma-RunnerPhase] Type=QString