diff --git a/plasma/abstractrunner.cpp b/plasma/abstractrunner.cpp index 966ddaf42b..69cbfcf2bf 100644 --- a/plasma/abstractrunner.cpp +++ b/plasma/abstractrunner.cpp @@ -1,203 +1,264 @@ /* * Copyright 2006-2007 Aaron Seigo * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "abstractrunner.h" #include #include #include +#include #include +#include +#include "scripting/runnerscript.h" #include "searchcontext.h" namespace Plasma { class AbstractRunner::Private { public: bool hasMatchOptions; bool hasConfig; 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(this, KService::serviceByStorageId(serviceId))) +{ +} + +AbstractRunner::AbstractRunner(QObject* parent, const QVariantList& args) : QObject(parent), - d(new Private()) + d(new Private(this, KService::serviceByStorageId(args.count() > 0 ? args[0].toString() : QString()))) { } AbstractRunner::~AbstractRunner() { delete d; } KConfigGroup AbstractRunner::config() const { QString group = objectName(); if (group.isEmpty()) { group = "UnnamedRunner"; } KConfigGroup runners(KGlobal::config(), "Runners"); return KConfigGroup(&runners, group); } void AbstractRunner::performMatch( Plasma::SearchContext &globalContext ) { Plasma::SearchContext localContext( 0, globalContext ); //Keep track of global context list sizes so we know which pointers are our responsibility to delete int exactEnd = localContext.exactMatches().count(); int possibleEnd = localContext.possibleMatches().count(); int infoEnd = localContext.informationalMatches().count(); match( &localContext ); QList exact = localContext.exactMatches().mid(exactEnd); QList possible = localContext.possibleMatches().mid(possibleEnd); QList info = localContext.informationalMatches().mid(infoEnd); //If matches were not added, delete items on the heap if (!globalContext.addMatches(localContext.searchTerm(), exact, possible, info)) { qDeleteAll(exact); qDeleteAll(possible); qDeleteAll(info); } } bool AbstractRunner::hasMatchOptions() { return d->hasMatchOptions; } void AbstractRunner::setHasMatchOptions(bool hasMatchOptions) { d->hasMatchOptions = hasMatchOptions; } void AbstractRunner::createMatchOptions(QWidget *parent) { Q_UNUSED(parent) } bool AbstractRunner::isConfigurable() { return d->hasConfig; } void AbstractRunner::setIsConfigurable(bool hasConfig) { d->hasConfig = hasConfig; } void AbstractRunner::createConfigurationInterface(QWidget *widget) { Q_UNUSED(widget) } AbstractRunner::Speed AbstractRunner::speed() const { return d->speed; } void AbstractRunner::setSpeed(Speed speed) { d->speed = speed; } // For 4.1: // int AbstractRunner::tier() const // { // return d->tier; // } -// +// // void AbstractRunner::setTier(int tier) // { // d->tier = tier; // } AbstractRunner::Priority AbstractRunner::priority() const { return d->priority; } void AbstractRunner::setPriority(Priority priority) { d->priority = priority; } KService::List AbstractRunner::serviceQuery(const QString &serviceType, const QString &constraint) const { QMutexLocker lock(&Private::serviceTypeTraderLock); return KServiceTypeTrader::self()->query(serviceType, constraint); } 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) { List firstRunners; List runners; List lastRunners; 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(); if (phase == "last") { lastRunners.append(runner); } else if (phase == "first") { firstRunners.append(runner); } else { runners.append(runner); } } else { kDebug() << "failed to load runner : " << service->name() << ". error reported: " << error; } } } firstRunners << runners << lastRunners; return firstRunners; } } // Plasma namespace #include "abstractrunner.moc" diff --git a/plasma/abstractrunner.h b/plasma/abstractrunner.h index 6a7119375e..99dbd856c6 100644 --- a/plasma/abstractrunner.h +++ b/plasma/abstractrunner.h @@ -1,227 +1,238 @@ /* * Copyright 2006-2007 Aaron Seigo * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef RUNNER_H #define RUNNER_H #include #include #include #include #include #include #include class KCompletion; namespace Plasma { +class RunnerScript; + /** * An abstract base class for Plasma Runner plugins * * Be aware that runners have to be thread-safe. This is due to * the fact that each runner is executed in its own thread for * each new term. Thus, a runner may be executed more than once * at the same time. */ class PLASMA_EXPORT AbstractRunner : public QObject { Q_OBJECT public: enum Speed { NormalSpeed, SlowSpeed }; enum Priority { LowestPriority = 0, LowPriority, NormalPriority, HighPriority, HighestPriority }; typedef QList List; /** * Static method is called to load and get a list available of Runners. * * @param whitelist An optional whitelist of runners to load */ static List loadRunners(QObject* parent, const QStringList& whitelist = QStringList() ); /** * Constructs a Runner object. Since AbstractRunner has pure virtuals, * 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(); /** * Provides access to the runner's configuration object. */ KConfigGroup config() const; /** * This is the main query method. It should trigger creation of * SearchMatch instances through SearchContext::addInformationalMatch, * SearchContext::addExactMatch, and SearchContext::addPossibleMatch. * * If the runner can run precisely the requested term (SearchContext::searchTerm), * it should create an exact match (SearchContext::addExactMatch). * The first runner that creates a SearchMatch will be the * default runner. Other runner's matches will be suggested in the * interface. Non-exact matches should be offered via SearchContext::addPossibleMatch. * * 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 * * Since each runner is executed in its own thread there is no need * 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. * * @arg globalContext the search context used in executing this match. */ void performMatch(Plasma::SearchContext &globalContext); /** * If the runner has options that the user can interact with to modify * what happens when exec or one of the actions created in fillMatches * is called, the runner should return true */ bool hasMatchOptions(); /** * If hasMatchOptions() returns true, this method may be called to get * a widget displaying the options the user can interact with to modify * the behaviour of what happens when a given match is selected. * * @param widget the parent of the options widgets. */ virtual void createMatchOptions(QWidget *widget); /** * If the runner itself has configuration options, this method returns true */ bool isConfigurable(); /** * If isConfigurable() returns true, this method may to get * a widget displaying the options the user can interact with to modify * the behaviour of what happens when a given match is selected. * * @param widget the parent of the options widgets. */ virtual void createConfigurationInterface(QWidget *widget); /** * Called whenever an exact or possible match associated with this * runner is triggered. */ virtual void exec(Plasma::SearchMatch *action); /** * The nominal speed of the runner. * @see setSpeed */ Speed speed() const; // For 4.1 // /** // * The tier of the runner. // * @see setTier // */ // int tier() const; /** * The priority of the runner. * @see setPriority */ 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 */ void setHasMatchOptions(bool hasMatchOptions); /** * Sets whether or not the runner has configuration options itself */ 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); //For 4.1 // /** // * Sets the run tier of the runner. Higher tier runners execute only // * after all lower-level runners execute. Call this method if your runner // * depends on the output of previous runners. // */ // void setTier(int tier); /** * Sets the priority of the runner. Lower priority runners are executed * only after higher priority runners. */ void setPriority(Priority newPriority); /** * A blocking method to do queries of installed Services which can provide * a measure of safety for runners running their own threads. This should * be used instead of calling KServiceTypeTrader::query(..) directly. * * @arg serviceType a service type like "Plasma/Applet" or "KFilePlugin" * @arg constraint a constraint to limit the the choices returned. * @see KServiceTypeTrader::query(const QString&, const QString&) * * @return a list of services that satisfy the query. */ KService::List serviceQuery(const QString &serviceType, const QString &constraint = QString()) const; + protected slots: + void init(); + private: class Private; Private* const d; }; } // Plasma namespace #define K_EXPORT_PLASMA_RUNNER( libname, classname ) \ K_PLUGIN_FACTORY(factory, registerPlugin();) \ K_EXPORT_PLUGIN(factory("plasma_runner_" #libname)) #endif diff --git a/plasma/dataengine.cpp b/plasma/dataengine.cpp index c1ff56ff2a..d93c5a0d05 100644 --- a/plasma/dataengine.cpp +++ b/plasma/dataengine.cpp @@ -1,493 +1,541 @@ /* * Copyright 2006-2007 Aaron Seigo * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "dataengine.h" #include #include #include #include #include #include +#include +#include #include "datacontainer.h" +#include "scripting/dataenginescript.h" 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) { DataEngine::SourceDict::const_iterator it = sources.find(sourceName); if (it != sources.constEnd()) { DataContainer* s = it.value(); if (limit > 0) { QQueue::iterator it = sourceQueue.begin(); while (it != sourceQueue.end()) { if (*it == s) { sourceQueue.erase(it); break; } ++it; } sourceQueue.enqueue(s); } return it.value(); } if (!createWhenMissing) { return 0; } /*kDebug() << "DataEngine " << engine->objectName() << ": could not find DataContainer " << sourceName << ", creating" << endl;*/ DataContainer* s = new DataContainer(engine); s->setObjectName(sourceName); sources.insert(sourceName, s); connect(s, SIGNAL(requestUpdate(DataContainer*)), engine, SLOT(internalUpdateSource(DataContainer*))); if (limit > 0) { trimQueue(); sourceQueue.enqueue(s); } emit engine->newSource(sourceName); return s; } void connectSource(DataContainer* s, QObject* visualization, uint updateInterval, Plasma::IntervalAlignment align, bool immediateCall = true) { //kDebug() << "connect source called with interval" << updateInterval; if (updateInterval > 0) { // never more frequently than allowed, never more than 20 times per second uint min = qMax(50, minUpdateInterval); // for qMin below updateInterval = qMax(min, updateInterval); // align on the 50ms updateInterval = updateInterval - (updateInterval % 50); } s->connectVisualization(visualization, updateInterval, align); if (immediateCall) { QMetaObject::invokeMethod(visualization, "dataUpdated", Q_ARG(QString, s->objectName()), Q_ARG(Plasma::DataEngine::Data, s->data())); } } DataContainer* requestSource(const QString& sourceName, bool* newSource = 0) { if (newSource) { *newSource = false; } //kDebug() << "requesting source " << sourceName; DataContainer* s = source(sourceName, false); if (!s) { // we didn't find a data source, so give the engine an opportunity to make one /*kDebug() << "DataEngine " << engine->objectName() << ": could not find DataContainer " << sourceName << " will create on request" << endl;*/ if (engine->sourceRequested(sourceName)) { s = source(sourceName, false); if (s) { // now we have a source; since it was created on demand, assume // it should be removed when not used if (newSource) { *newSource = true; } connect(s, SIGNAL(unused(QString)), engine, SLOT(removeSource(QString))); } } } return s; } void trimQueue() { uint queueCount = sourceQueue.count(); while (queueCount >= limit) { DataContainer* punted = sourceQueue.dequeue(); engine->removeSource(punted->objectName()); } } void queueUpdate() { if (updateTimer->isActive()) { return; } updateTimer->start(0); } DataEngine* engine; int ref; int updateTimerId; int minUpdateInterval; QTime updateTimestamp; DataEngine::SourceDict sources; QQueue sourceQueue; QTimer* updateTimer; 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, 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)) + 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. //Update DataEngine::init() api docu when fixed QTimer::singleShot(0, this, SLOT(startInit())); } DataEngine::~DataEngine() { //kDebug() << objectName() << ": bye bye birdy! "; delete d; } QStringList DataEngine::sources() const { return d->sources.keys(); } void DataEngine::connectSource(const QString& source, QObject* visualization, uint updateInterval, Plasma::IntervalAlignment intervalAlignment) const { //kDebug() << "connectSource" << source; bool newSource; DataContainer* s = d->requestSource(source, &newSource); if (s) { // we suppress the immediate invocation of dataUpdated here if the source was prexisting and they // don't request delayed updates (we want to do an immediate update in that case so they // don't have to wait for the first time out) d->connectSource(s, visualization, updateInterval, intervalAlignment, !newSource || updateInterval > 0); //kDebug() << " ==> source connected"; } } void DataEngine::connectAllSources(QObject* visualization, uint updateInterval, Plasma::IntervalAlignment intervalAlignment) const { foreach (DataContainer* s, d->sources) { d->connectSource(s, visualization, updateInterval, intervalAlignment); } } void DataEngine::disconnectSource(const QString& source, QObject* visualization) const { DataContainer* s = d->source(source, false); if (s) { s->disconnectVisualization(visualization); } } DataContainer* DataEngine::containerForSource(const QString &source) { return d->source(source, false); } DataEngine::Data DataEngine::query(const QString& source) const { DataContainer* s = d->requestSource(source); if (!s) { return DataEngine::Data(); } DataEngine::Data data = s->data(); s->checkUsage(); return data; } void DataEngine::startInit() { init(); } void DataEngine::internalUpdateSource(DataContainer* source) { if (d->minUpdateInterval > 0 && source->timeSinceLastUpdate() < d->minUpdateInterval) { // skip updating this source; it's been too soon //kDebug() << "internal update source is delaying" << source->timeSinceLastUpdate() << d->minUpdateInterval; //but fake an update so that the signalrelay that triggered this gets the data from the //recent update. this way we don't have to worry about queuing - the relay will send a //signal immediately and everyone else is undisturbed. source->setNeedsUpdate(); return; } if (updateSource(source->objectName())) { d->queueUpdate(); } } 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) { setData(source, source, value); } void DataEngine::setData(const QString& source, const QString& key, const QVariant& value) { DataContainer* s = d->source(source); s->setData(key, value); d->queueUpdate(); } void DataEngine::setData(const QString &source, const Data &data) { DataContainer *s = d->source(source); Data::const_iterator it = data.constBegin(); while (it != data.constEnd()) { s->setData(it.key(), it.value()); ++it; } d->queueUpdate(); } void DataEngine::clearData(const QString& source) { DataContainer* s = d->source(source, false); if (s) { s->clearData(); d->queueUpdate(); } } void DataEngine::removeData(const QString& source, const QString& key) { DataContainer* s = d->source(source, false); if (s) { s->setData(key, QVariant()); d->queueUpdate(); } } void DataEngine::addSource(DataContainer* source) { SourceDict::const_iterator it = d->sources.find(source->objectName()); if (it != d->sources.constEnd()) { kDebug() << "source named \"" << source->objectName() << "\" already exists."; return; } d->sources.insert(source->objectName(), source); emit newSource(source->objectName()); } void DataEngine::setSourceLimit(uint limit) { if (d->limit == limit) { return; } d->limit = limit; if (d->limit > 0) { d->trimQueue(); } else { d->sourceQueue.clear(); } } void DataEngine::setMinimumUpdateInterval(int minimumMs) { d->minUpdateInterval = minimumMs; } int DataEngine::minimumUpdateInterval() const { return d->minUpdateInterval; } void DataEngine::setUpdateInterval(uint frequency) { killTimer(d->updateTimerId); d->updateTimerId = 0; if (frequency > 0) { d->updateTimerId = startTimer(frequency); } } /* NOTE: This is not implemented to prevent having to store the value internally. When there is a good use case for needing access to this value, we can add another member to the Private class and add this method. void DataEngine::updateInterval() { return d->updateInterval; } */ void DataEngine::removeSource(const QString& source) { //kDebug() << "removing source " << source; SourceDict::iterator it = d->sources.find(source); if (it != d->sources.end()) { emit sourceRemoved(it.key()); it.value()->deleteLater(); d->sources.erase(it); } } void DataEngine::clearSources() { QMutableHashIterator it(d->sources); while (it.hasNext()) { it.next(); emit sourceRemoved(it.key()); delete it.value(); it.remove(); } } void DataEngine::ref() { --d->ref; } void DataEngine::deref() { ++d->ref; } bool DataEngine::isUsed() const { return d->ref != 0; } bool DataEngine::isValid() const { return d->valid; } bool DataEngine::isEmpty() const { return d->sources.isEmpty(); } void DataEngine::setValid(bool valid) { d->valid = valid; } DataEngine::SourceDict DataEngine::sourceDict() const { return d->sources; } void DataEngine::timerEvent(QTimerEvent *event) { if (event->timerId() != d->updateTimerId) { return; } event->accept(); // if the freq update is less than 0, don't bother if (d->minUpdateInterval < 0) { return; } // minUpdateInterval if (d->updateTimestamp.elapsed() < d->minUpdateInterval) { return; } d->updateTimestamp.restart(); QHashIterator it(d->sources); while (it.hasNext()) { it.next(); updateSource(it.key()); } checkForUpdates(); } void DataEngine::setIcon(const QString& icon) { d->icon = icon; } QString DataEngine::icon() const { return d->icon; } void DataEngine::checkForUpdates() { QHashIterator it(d->sources); while (it.hasNext()) { it.next(); it.value()->checkForUpdate(); } } +QString DataEngine::engineName() const +{ + if (!d->dataEngineDescription.isValid()) { + return QString(); + } + + return d->dataEngineDescription.property("X-Plasma-EngineName").toString(); +} + } #include "dataengine.moc" diff --git a/plasma/dataengine.h b/plasma/dataengine.h index 6a1d9e0f10..2132529b51 100644 --- a/plasma/dataengine.h +++ b/plasma/dataengine.h @@ -1,411 +1,419 @@ /* * Copyright 2006-2007 Aaron Seigo * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef PLASMA_DATAENGINE_H #define PLASMA_DATAENGINE_H #include #include #include #include #include #include namespace Plasma { class DataContainer; +class DataEngineScript; /** * @class DataEngine * @brief Data provider for plasmoids (Plasma plugins) * * This is the base class for DataEngines, which provide access to bodies of * data via a common and consistent interface. The common use of a DataEngine * is to provide data to a widget for display. This allows a user interface * element to show all sorts of data: as long as there is a DataEngine, the * data is retrievable. * * DataEngines are loaded as plugins on demand and provide zero, one or more * data sources which are identified by name. For instance, a network * DataEngine might provide a data source for each network interface. **/ class PLASMA_EXPORT DataEngine : public QObject { + friend class DataEngineScript; Q_OBJECT Q_PROPERTY( QStringList sources READ sources ) Q_PROPERTY( bool valid READ isValid ) Q_PROPERTY( QString icon READ icon WRITE setIcon ) public: typedef QHash Dict; typedef QHash Data; typedef QHashIterator DataIterator; typedef QHash SourceDict; /** * Default constructor. * * @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(); /** * @return a list of all the data sources available via this DataEngine * Whether these sources are currently available (which is what * the default implementation provides) or not is up to the * DataEngine to decide. **/ 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: * * dataUpdated(const QString &sourceName, const Plasma::DataEngine::Data &data) * * The data is a QHash of QVariants keyed by QString names, allowing * one data source to provide sets of related data. * * @param source the name of the data source * @param visualization the object to connect the data source to * @param updateInterval the frequency, in milliseconds, with which to signal updates; * a value of 0 (the default) means to update only * when there is new data spontaneously generated * (e.g. by the engine); any other value results in * periodic updates from this source. This value is * per-visualization and can be handy for items that require * constant updates such as scrolling graphs or clocks. * @param intervalAlignedTo the number of ms to aling the interval to **/ Q_INVOKABLE void connectSource(const QString& source, QObject* visualization, uint updateInterval = 0, Plasma::IntervalAlignment intervalAlignment = NoAlignment) const; /** * Connects all sources to an object for data updates. The object must * have a slot with the following signature: * * SLOT(dataUpdated(QString, Plasma::DataEngine::Data)) * * The data is a QHash of QVariants keyed by QString names, allowing * one data source to provide sets of related data. * * This method may be called multiple times for the same visualization * without side-effects. This can be useful to change the updateInterval. * * @param visualization the object to connect the data source to * @param updateInterval the frequency, in milliseconds, with which to signal updates; * a value of 0 (the default) means to update only * when there is new data spontaneously generated * (e.g. by the engine); any other value results in * periodic updates from this source. This value is * per-visualization and can be handy for items that require * constant updates such as scrolling graphs or clocks. **/ Q_INVOKABLE void connectAllSources(QObject* viualization, uint updateInterval = 0, Plasma::IntervalAlignment intervalAlignment = NoAlignment) const; /** * Disconnects a source to an object that was receiving data updates. * * @param source the name of the data source * @param visualization the object to connect the data source to **/ Q_INVOKABLE void disconnectSource(const QString& source, QObject* visualization) const; /** * 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. * * @arg source the name of the source. * @return pointer to a DataContainer, or zero on failure **/ Q_INVOKABLE DataContainer* containerForSource(const QString &source); /** * Gets the Data associated with a data source. * * The data is a QHash of QVariants keyed by QString names, allowing * one data source to provide sets of related data. * * @param source the data source to retrieve the data for * @return the Data associated with the source; if the source doesn't * exist an empty data set is returned **/ Q_INVOKABLE DataEngine::Data query(const QString& source) const; /** * Reference counting method. Calling this method increases the count * by one. **/ void ref(); /** * Reference counting method. Calling this method decreases the count * by one. **/ 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 **/ bool isUsed() const; /** * Returns true if this engine is valid, otherwise returns false **/ bool isValid() const; /** * Returns true if the data engine is empty, which is to say that it has no * data sources currently. */ bool isEmpty() const; /** * Sets the icon for this data engine **/ void setIcon(const QString& icon); /** * @return the name of the icon for this data engine; and empty string * is returned if there is no associated icon. **/ QString icon() const; Q_SIGNALS: /** * Emitted when a new data source is created * @param source the name of the new data source **/ void newSource(const QString& source); /** * Emitted when a data source is removed. * @param source the name of the data source that was removed **/ void sourceRemoved(const QString& source); protected: /** * This method is called when the DataEngine is started. When this * method is called the DataEngine is fully constructed and ready to be * used. This method should be reimplemented by DataEngine subclasses * which have the need to perform a startup routine. **/ virtual void init(); /** * When a source that does not currently exist is requested by the * consumer, this method is called to give the DataEngine the * opportunity to create one. * * The name of the data source (e.g. the source parameter passed into * setData) it must be the same as the name passed to sourceRequested * otherwise the requesting visualization may not receive notice of a * data update. * * If the source can not be populated with data immediately (e.g. due to * an asynchronous data acquisition method such as an HTTP request) * the source must still be created, even if it is empty. This can * be accomplished in these cases with the follow line: * * setData(name, DataEngine::Data()); * * @return true if a DataContainer was set up, false otherwise */ virtual bool sourceRequested(const QString &name); /** * Called by internal updating mechanisms to trigger the engine * to refresh the data contained in a given source. Reimplement this * method when using facilities such as setUpdateInterval. * @see setUpdateInterval * * @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); /** * Sets a value for a data source. If the source * doesn't exist then it is created. * * @param source the name of the data source * @param value the data to associated with the source **/ void setData(const QString &source, const QVariant &value); /** * Sets a value for a data source. If the source * doesn't exist then it is created. * * @param source the name of the data source * @param key the key to use for the data * @param value the data to associated with the source **/ void setData(const QString& source, const QString& key, const QVariant& value); /** * Adds a set of data to a data source. If the source * doesn't exist then it is created. * * @param source the name of the data source * @param data the data to add to the source **/ void setData(const QString &source, const Data &data); /** * Clears all the data associated with a data source. * * @param source the name of the data source **/ void clearData(const QString& source); /** * Removes a data entry from a source * * @param source the name of the data source * @param key the data entry to remove **/ void removeData(const QString& source, const QString& key); /** * Adds an already constructed data source. The DataEngine takes * ownership of the DataContainer object. * @param source the DataContainer to add to the DataEngine **/ void addSource(DataContainer* source); /** * Sets an upper limit on the number of data sources to keep in this engine. * If the limit is exceeded, then the oldest data source, as defined by last * update, is dropped. * * @param limit the maximum number of sources to keep active **/ void setSourceLimit(uint limit); /** * Sets the minimum amount of time, in milliseconds, that must pass between * successive updates of data. This can help prevent too many updates happening * due to multiple update requests coming in, which can be useful for * expensive (time- or resource-wise) update mechanisms. * * @arg minimumMs the minimum time lapse, in milliseconds, between updates. * A value less than 0 means to never perform automatic updates, * a value of 0 means update immediately on every update request, * a value >0 will result in a minimum time lapse being enforced. **/ void setMinimumUpdateInterval(int minimumMs); /** * @return the minimum time between updates. @see setMinimumupdateInterval **/ int minimumUpdateInterval() const; /** * Sets up an internal update tick for all data sources. On every update, * updateSource will be called for each applicable source. * @see updateSource * * @param frequency the time, in milliseconds, between updates. A value of 0 * will stop internally triggered updates. **/ void setUpdateInterval(uint frequency); /** * Returns the current update frequency. * @see setUpdateInterval NOTE: This is not implemented to prevent having to store the value internally. When there is a good use case for needing access to this value, we can add another member to the Private class and add this method. uint updateInterval(); **/ /** * Removes all data sources **/ void clearSources(); /** * Sets whether or not this engine is valid, e.g. can be used. * In practice, only the internal fall-back engine, the NullEngine * should have need for this. * * @param valid whether or not the engine is valid **/ void setValid(bool valid); /** * @return the list of active DataContainers. */ SourceDict sourceDict() const; /** * Reimplemented from QObject **/ void timerEvent(QTimerEvent *event); protected Q_SLOTS: /** * Call this method when you call setData directly on a DataContainer instead * of using the DataEngine::setData methods. * If this method is not called, no dataUpdated(..) signals will be emitted! */ void checkForUpdates(); /** * Removes a data source. * @param source the name of the data source to remove **/ void removeSource(const QString& source); /** * @internal **/ void startInit(); /** * @internal **/ void internalUpdateSource(DataContainer* source); private: class Private; Private* const d; }; } // Plasma namespace #define K_EXPORT_PLASMA_DATAENGINE(libname, classname) \ K_PLUGIN_FACTORY(factory, registerPlugin();) \ K_EXPORT_PLUGIN(factory("plasma_engine_" #libname)) #endif // multiple inclusion guard diff --git a/plasma/dataenginemanager.cpp b/plasma/dataenginemanager.cpp index a3fa113161..fd44bd0f80 100644 --- a/plasma/dataenginemanager.cpp +++ b/plasma/dataenginemanager.cpp @@ -1,169 +1,177 @@ /* * Copyright 2006-2007 Aaron Seigo * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "dataenginemanager.h" +#include "scripting/scriptengine.h" #include #include namespace Plasma { class NullEngine : public DataEngine { public: NullEngine(QObject* parent = 0) : DataEngine(parent) { setObjectName(i18n("Null Engine")); setValid(false); // ref() ourselves to ensure we never get deleted ref(); } }; class DataEngineManager::Private { public: Private() : nullEng(0) {} ~Private() { foreach (Plasma::DataEngine* engine, engines) { delete engine; } engines.clear(); delete nullEng; } DataEngine* nullEngine() { if (!nullEng) { nullEng = new NullEngine; } return nullEng; } DataEngine::Dict engines; DataEngine* nullEng; }; class DataEngineManagerSingleton { public: DataEngineManager self; }; K_GLOBAL_STATIC(DataEngineManagerSingleton, privateDataEngineManagerSelf) DataEngineManager* DataEngineManager::self() { return &privateDataEngineManagerSelf->self; } DataEngineManager::DataEngineManager() : d(new Private()) { } DataEngineManager::~DataEngineManager() { delete d; } Plasma::DataEngine* DataEngineManager::dataEngine(const QString& name) const { Plasma::DataEngine::Dict::const_iterator it = d->engines.find(name); if (it != d->engines.end()) { // ref and return the engine //Plasma::DataEngine *engine = *it; return *it; } return d->nullEngine(); } Plasma::DataEngine* DataEngineManager::loadDataEngine(const QString& name) { Plasma::DataEngine* engine = 0; Plasma::DataEngine::Dict::const_iterator it = d->engines.find(name); if (it != d->engines.end()) { engine = *it; engine->ref(); return engine; } // load the engine, add it to the engines QString constraint = QString("[X-Plasma-EngineName] == '%1'").arg(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) { kDebug() << "Couldn't load engine \"" << name << "\". Error given: " << error; return d->nullEngine(); } engine->ref(); engine->setObjectName(offers.first()->name()); engine->setIcon(offers.first()->icon()); d->engines[name] = engine; return engine; } void DataEngineManager::unloadDataEngine(const QString& name) { Plasma::DataEngine::Dict::iterator it = d->engines.find(name); if (it != d->engines.end()) { Plasma::DataEngine* engine = *it; engine->deref(); if (!engine->isUsed()) { d->engines.erase(it); delete engine; } } } QStringList DataEngineManager::knownEngines() { QStringList engines; KService::List offers = KServiceTypeTrader::self()->query("Plasma/DataEngine"); foreach (KService::Ptr service, offers) { engines.append(service->property("X-Plasma-EngineName").toString()); } return engines; } } // namespace Plasma #include "dataenginemanager.moc" diff --git a/plasma/scripting/dataenginescript.cpp b/plasma/scripting/dataenginescript.cpp index 9f4f4f532a..68c220b9a8 100644 --- a/plasma/scripting/dataenginescript.cpp +++ b/plasma/scripting/dataenginescript.cpp @@ -1,56 +1,133 @@ /* * Copyright 2007 by Aaron Seigo * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "dataenginescript.h" #include "dataengine.h" namespace Plasma { class DataEngineScript::Private { public: DataEngine* dataEngine; }; DataEngineScript::DataEngineScript(QObject *parent) : ScriptEngine(parent), - d(0) + d(new Private) { } DataEngineScript::~DataEngineScript() { // delete d; } void DataEngineScript::setDataEngine(DataEngine *dataEngine) { d->dataEngine = dataEngine; } 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/plasma/scripting/dataenginescript.h b/plasma/scripting/dataenginescript.h index d8848c3e76..12acda753a 100644 --- a/plasma/scripting/dataenginescript.h +++ b/plasma/scripting/dataenginescript.h @@ -1,67 +1,98 @@ /* * Copyright 2007 by Aaron Seigo * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef PLASMA_DATAENGINESCRIPT_H #define PLASMA_DATAENGINESCRIPT_H #include #include namespace Plasma { class DataEngine; class PLASMA_EXPORT DataEngineScript : public ScriptEngine { Q_OBJECT public: /** * Default constructor for a DataEngineScript. * Subclasses should not attempt to access the Plasma::DataEngine * associated with this DataEngineScript in the constructor. All * such set up that requires the DataEngine itself should be done * in the init() method. */ explicit DataEngineScript(QObject *parent = 0); ~DataEngineScript(); /** * Sets the Plasma::DataEngine associated with this DataEngineScript */ void setDataEngine(DataEngine *dataEngine); /** * Returns the Plasma::DataEngine associated with this script component */ 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; }; #define K_EXPORT_PLASMA_DATAENGINESCRIPTENGINE(libname, classname) \ K_PLUGIN_FACTORY(factory, registerPlugin();) \ K_EXPORT_PLUGIN(factory("plasma_dataenginescriptengine_" #libname)) } //Plasma namespace #endif diff --git a/plasma/scripting/runnerscript.cpp b/plasma/scripting/runnerscript.cpp index fe5149d675..0aa6db5301 100644 --- a/plasma/scripting/runnerscript.cpp +++ b/plasma/scripting/runnerscript.cpp @@ -1,56 +1,66 @@ /* * Copyright 2007 by Aaron Seigo * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "runnerscript.h" #include "abstractrunner.h" namespace Plasma { class RunnerScript::Private { public: AbstractRunner* runner; }; RunnerScript::RunnerScript(QObject *parent) : ScriptEngine(parent), - d(0) + d(new Private) { } RunnerScript::~RunnerScript() { // delete d; } void RunnerScript::setRunner(AbstractRunner *runner) { d->runner = runner; } 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/plasma/scripting/runnerscript.h b/plasma/scripting/runnerscript.h index 6f06fc1f04..b8b621d97e 100644 --- a/plasma/scripting/runnerscript.h +++ b/plasma/scripting/runnerscript.h @@ -1,67 +1,82 @@ /* * Copyright 2007 by Aaron Seigo * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef PLASMA_RUNNERSCRIPT_H #define PLASMA_RUNNERSCRIPT_H #include #include namespace Plasma { class AbstractRunner; +class SearchContext; +class SearchMatch; class PLASMA_EXPORT RunnerScript : public ScriptEngine { Q_OBJECT public: /** * Default constructor for a RunnerScript. * Subclasses should not attempt to access the Plasma::AbstractRunner * associated with this RunnerScript in the constructor. All * such set up that requires the AbstractRunner itself should be done * in the init() method. */ explicit RunnerScript(QObject *parent = 0); ~RunnerScript(); /** * Sets the Plasma::AbstractRunner associated with this RunnerScript */ void setRunner(AbstractRunner *runner); /** * Returns the Plasma::AbstractRunner associated with this script component */ 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; }; #define K_EXPORT_PLASMA_RUNNERSCRIPTENGINE(libname, classname) \ K_PLUGIN_FACTORY(factory, registerPlugin();) \ K_EXPORT_PLUGIN(factory("plasma_runnerscriptengine_" #libname)) } //Plasma namespace #endif diff --git a/plasma/scripting/scriptengine.cpp b/plasma/scripting/scriptengine.cpp index deb95bd521..db59339678 100644 --- a/plasma/scripting/scriptengine.cpp +++ b/plasma/scripting/scriptengine.cpp @@ -1,191 +1,203 @@ /* * Copyright 2007 by Aaron Seigo * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "scripting/scriptengine.h" #include #include #include #include "abstractrunner.h" #include "applet.h" #include "dataengine.h" #include "package.h" #include "scripting/appletscript.h" #include "scripting/dataenginescript.h" #include "scripting/runnerscript.h" namespace Plasma { ScriptEngine::ScriptEngine(QObject *parent) : QObject(parent), d(0) { } ScriptEngine::~ScriptEngine() { // delete d; } bool ScriptEngine::init() { return true; } QStringList knownLanguages(ComponentTypes types) { QString constraintTemplate = "'%1' in [X-Plasma-ComponentTypes]"; QString constraint; if (types & AppletComponent) { // currently this if statement is not needed, but this future proofs // the code against someone initializing constraint to something // before we get here. if (!constraint.isEmpty()) { constraint.append(" or "); } constraint.append(constraintTemplate.arg("Applet")); } if (types & DataEngineComponent) { if (!constraint.isEmpty()) { constraint.append(" or "); } constraint.append(constraintTemplate.arg("DataEngine")); } if (types & RunnerComponent) { if (!constraint.isEmpty()) { constraint.append(" or "); } constraint.append(constraintTemplate.arg("Runner")); } KService::List offers = KServiceTypeTrader::self()->query("Plasma/ScriptEngine", constraint); //kDebug() << "Applet::knownApplets constraint was '" << constraint << "' which got us " << offers.count() << " matches"; QStringList languages; foreach (KService::Ptr service, offers) { QString language = service->property("X-Plasma-Language").toString(); if (!languages.contains(language)) { languages.append(language); } } return languages; } ScriptEngine* loadEngine(const QString &language, ComponentType type, QObject *parent) { if (language.isEmpty()) { return 0; } QRegExp re("[^a-zA-Z0-9\\-_]"); if (re.indexIn(language) != -1) { kDebug() << "invalid language attempted:" << language; return 0; } QString component; switch (type) { case AppletComponent: component = "Applet"; break; case DataEngineComponent: component = "DataEngine"; break; case RunnerComponent: component = "Runner"; break; default: return 0; break; } QString constraint = QString("[X-Plasma-Language] == '%1' and " "'%2' in [X-Plasma-ComponentTypes]").arg(language, component); KService::List offers = KServiceTypeTrader::self()->query("Plasma/ScriptEngine", constraint); /* kDebug() << "********************* loadingApplet with Plasma/ScriptEngine" << constraint << "resulting in" << offers.count() << "results";*/ if (offers.isEmpty()) { kDebug() << "ScriptEngine::load: no offers for \"" << language << "\""; return 0; } QVariantList args; QString error; ScriptEngine *engine = 0; foreach (KService::Ptr service, offers) { switch (type) { case AppletComponent: engine = service->createInstance(parent, args, &error); break; case DataEngineComponent: engine = service->createInstance(parent, args, &error); break; case RunnerComponent: engine = service->createInstance(parent, args, &error); break; default: return 0; break; } if (engine) { return engine; } kDebug() << "Couldn't load script engine for language " << language << "! error reported: " << error; } return 0; } AppletScript* loadScriptEngine(const QString &language, Applet *applet) { AppletScript *engine = static_cast(loadEngine(language, AppletComponent, applet)); if (engine) { engine->setApplet(applet); } return engine; } 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 #include diff --git a/plasma/servicetypes/plasma-runner.desktop b/plasma/servicetypes/plasma-runner.desktop index c0387959a5..c8c3749dc3 100644 --- a/plasma/servicetypes/plasma-runner.desktop +++ b/plasma/servicetypes/plasma-runner.desktop @@ -1,59 +1,62 @@ [Desktop Entry] Type=ServiceType X-KDE-ServiceType=Plasma/Runner Comment=KRunner plugin Comment[ar]=KRunner ملحق Comment[be]=Утулка Krunner Comment[bg]=Приставка за KRunner Comment[ca]=Connectors per al KRunner Comment[csb]=Wtëkôcze zrëszôcza KRunner Comment[da]=KRunner-plugin Comment[de]=Programmstarter-Modul Comment[el]=Πρόσθετο του KRunner Comment[eo]=KRunner-kromprogramo Comment[es]=Complemento de KRunner Comment[et]=KRunneri plugin Comment[eu]=KRunner plugin-a Comment[fa]=وصلۀ KRunner Comment[fi]=KRunner-liitännäinen Comment[fr]=Module externe de KRunner Comment[ga]=Breiseán KRunner Comment[gl]=Extensión de KRunner Comment[he]=תוסף של KRunner Comment[hi]=के-रनर प्लगइन Comment[hu]=KRunner-bővítőmodul Comment[is]=KRunner íforrit Comment[it]=Plugin di KRunner Comment[ja]=KRunner プラグイン Comment[kk]=KRunner плагин модулі Comment[km]=កម្មវិធី​ជំនួយ KRunner Comment[ko]=KRunner 플러그인 Comment[lv]=KRunner spraudnis Comment[nb]=KRunner-programtillegg Comment[nds]=KRunner-Moduul Comment[ne]=केडीई रनर प्लगइन Comment[nl]=KRunner-plugin Comment[nn]=KRunner-tillegg Comment[pa]=ਕੇ-ਰਨਰ ਪਲੱਗਇਨ Comment[pl]=Wtyczki KRunnera Comment[pt]='Plugin' do KRunner Comment[pt_BR]=Plugin do KRunner Comment[ro]=Modul KRunner Comment[se]=KRunner-lassemodula Comment[sl]=Vstavek za KRunner Comment[sr]=Прикључак за К‑извођач Comment[sr@latin]=Priključak za K‑izvođač Comment[sv]=Krunner-insticksprogram Comment[th]=ปลั๊กอินของ KRunner Comment[tr]=KRunner eklentisi Comment[uk]=Втулка KRunner Comment[vi]=Bổ sung KRunner Comment[wa]=Tchôke-divins KRunner 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