• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.9.5 API Reference
  • KDE Home
  • Contact Us
 

Plasma

runnermanager.cpp
Go to the documentation of this file.
00001 /*
00002  *   Copyright (C) 2006 Aaron Seigo <aseigo@kde.org>
00003  *   Copyright (C) 2007, 2009 Ryan P. Bitanga <ryan.bitanga@gmail.com>
00004  *   Copyright (C) 2008 Jordi Polo <mumismo@gmail.com>
00005  *
00006  *   This program is free software; you can redistribute it and/or modify
00007  *   it under the terms of the GNU Library General Public License as
00008  *   published by the Free Software Foundation; either version 2, or
00009  *   (at your option) any later version.
00010  *
00011  *   This program is distributed in the hope that it will be useful,
00012  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  *   GNU General Public License for more details
00015  *
00016  *   You should have received a copy of the GNU Library General Public
00017  *   License along with this program; if not, write to the
00018  *   Free Software Foundation, Inc.,
00019  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00020  */
00021 
00022 #include "runnermanager.h"
00023 
00024 #include "config-plasma.h"
00025 
00026 #include <QMutex>
00027 #include <QTimer>
00028 #include <QCoreApplication>
00029 
00030 #include <kdebug.h>
00031 #include <kplugininfo.h>
00032 #include <kservicetypetrader.h>
00033 #include <kstandarddirs.h>
00034 
00035 #ifndef PLASMA_NO_SOLID
00036 #include <solid/device.h>
00037 #include <solid/deviceinterface.h>
00038 #endif
00039 
00040 #include <Weaver/DebuggingAids.h>
00041 #include <Weaver/State.h>
00042 #include <Weaver/Thread.h>
00043 #include <Weaver/ThreadWeaver.h>
00044 
00045 #include "private/runnerjobs_p.h"
00046 #include "pluginloader.h"
00047 #include "querymatch.h"
00048 
00049 using ThreadWeaver::Weaver;
00050 using ThreadWeaver::Job;
00051 
00052 //#define MEASURE_PREPTIME
00053 
00054 namespace Plasma
00055 {
00056 
00057 /*****************************************************
00058 *  RunnerManager::Private class
00059 *
00060 *****************************************************/
00061 class RunnerManagerPrivate
00062 {
00063 public:
00064 
00065     RunnerManagerPrivate(RunnerManager *parent)
00066       : q(parent),
00067         deferredRun(0),
00068         currentSingleRunner(0),
00069         prepped(false),
00070         allRunnersPrepped(false),
00071         singleRunnerPrepped(false),
00072         teardownRequested(false),
00073         singleMode(false),
00074         singleRunnerWasLoaded(false)
00075     {
00076         matchChangeTimer.setSingleShot(true);
00077         delayTimer.setSingleShot(true);
00078 
00079         QObject::connect(&matchChangeTimer, SIGNAL(timeout()), q, SLOT(matchesChanged()));
00080         QObject::connect(&context, SIGNAL(matchesChanged()), q, SLOT(scheduleMatchesChanged()));
00081         QObject::connect(&delayTimer, SIGNAL(timeout()), q, SLOT(unblockJobs()));
00082     }
00083 
00084     ~RunnerManagerPrivate()
00085     {
00086         KConfigGroup config = configGroup();
00087         context.save(config);
00088     }
00089 
00090     void scheduleMatchesChanged()
00091     {
00092         matchChangeTimer.start(100);
00093     }
00094 
00095     void matchesChanged()
00096     {
00097         emit q->matchesChanged(context.matches());
00098     }
00099 
00100     void loadConfiguration()
00101     {
00102         KConfigGroup config = configGroup();
00103 
00104         //The number of threads used scales with the number of processors.
00105 #ifndef PLASMA_NO_SOLID
00106         const int numProcs =
00107             qMax(Solid::Device::listFromType(Solid::DeviceInterface::Processor).count(), 1);
00108 #else
00109         const int numProcs = 1;
00110 #endif
00111         //This entry allows to define a hard upper limit independent of the number of processors.
00112         const int maxThreads = config.readEntry("maxThreads", 16);
00113         const int numThreads = qMin(maxThreads, 2 + ((numProcs - 1) * 2));
00114         //kDebug() << "setting up" << numThreads << "threads for" << numProcs << "processors";
00115         if (numThreads > Weaver::instance()->maximumNumberOfThreads()) {
00116             Weaver::instance()->setMaximumNumberOfThreads(numThreads);
00117         }
00118         // Limit the number of instances of a single normal speed runner and all of the slow runners
00119         // to half the number of threads
00120         const int cap = qMax(2, numThreads/2);
00121         DefaultRunnerPolicy::instance().setCap(cap);
00122 
00123         context.restore(config);
00124     }
00125 
00126     KConfigGroup configGroup()
00127     {
00128         return conf.isValid() ? conf : KConfigGroup(KGlobal::config(), "PlasmaRunnerManager");
00129     }
00130 
00131     void clearSingleRunner()
00132     {
00133         if (singleRunnerWasLoaded) {
00134             delete currentSingleRunner;
00135         }
00136 
00137         currentSingleRunner = 0;
00138     }
00139 
00140     void loadSingleRunner()
00141     {
00142         if (!singleMode || singleModeRunnerId.isEmpty()) {
00143             clearSingleRunner();
00144             return;
00145         }
00146 
00147         if (currentSingleRunner) {
00148             if (currentSingleRunner->id() == singleModeRunnerId) {
00149                 return;
00150             }
00151 
00152             clearSingleRunner();
00153         }
00154 
00155         AbstractRunner *loadedRunner = q->runner(singleModeRunnerId);
00156         if (loadedRunner) {
00157             singleRunnerWasLoaded = false;
00158             currentSingleRunner = loadedRunner;
00159             return;
00160         }
00161 
00162         KService::List offers = KServiceTypeTrader::self()->query("Plasma/Runner", QString("[X-KDE-PluginInfo-Name] == '%1'").arg(singleModeRunnerId));
00163         if (!offers.isEmpty()) {
00164             const KService::Ptr &service = offers[0];
00165             currentSingleRunner = loadInstalledRunner(service);
00166 
00167             if (currentSingleRunner) {
00168                 emit currentSingleRunner->prepare();
00169                 singleRunnerWasLoaded = true;
00170             }
00171         }
00172     }
00173 
00174     void loadRunners()
00175     {
00176         KConfigGroup config = configGroup();
00177         KPluginInfo::List offers = RunnerManager::listRunnerInfo();
00178 
00179         const bool loadAll = config.readEntry("loadAll", false);
00180         const QStringList whiteList = config.readEntry("pluginWhiteList", QStringList());
00181         const bool noWhiteList = whiteList.isEmpty();
00182         KConfigGroup pluginConf;
00183         if (conf.isValid()) {
00184             pluginConf = KConfigGroup(&conf, "Plugins");
00185         } else {
00186             pluginConf = KConfigGroup(KGlobal::config(), "Plugins");
00187         }
00188 
00189         advertiseSingleRunnerIds.clear();
00190 
00191         QSet<AbstractRunner *> deadRunners;
00192         QMutableListIterator<KPluginInfo> it(offers);
00193         while (it.hasNext()) {
00194             KPluginInfo &description = it.next();
00195             //kDebug() << "Loading runner: " << service->name() << service->storageId();
00196             QString tryExec = description.property("TryExec").toString();
00197             //kDebug() << "TryExec is" << tryExec;
00198             if (!tryExec.isEmpty() && KStandardDirs::findExe(tryExec).isEmpty()) {
00199                 // we don't actually have this application!
00200                 continue;
00201             }
00202 
00203             const QString runnerName = description.pluginName();
00204             description.load(pluginConf);
00205 
00206             const bool loaded = runners.contains(runnerName);
00207             const bool selected = loadAll || (description.isPluginEnabled() && (noWhiteList || whiteList.contains(runnerName)));
00208 
00209             const bool singleQueryModeEnabled = description.property("X-Plasma-AdvertiseSingleRunnerQueryMode").toBool();
00210 
00211             if (singleQueryModeEnabled) {
00212                 advertiseSingleRunnerIds.insert(runnerName, description.name());
00213             }
00214 
00215             //kDebug() << loadAll << description.isPluginEnabled() << noWhiteList << whiteList.contains(runnerName);
00216             if (selected) {
00217                 if (!loaded) {
00218                     AbstractRunner *runner = loadInstalledRunner(description.service());
00219 
00220                     if (runner) {
00221                         runners.insert(runnerName, runner);
00222                     }
00223                 }
00224             } else if (loaded) {
00225                 //Remove runner
00226                 deadRunners.insert(runners.take(runnerName));
00227                 kDebug() << "Removing runner: " << runnerName;
00228             }
00229         }
00230 
00231         if (!deadRunners.isEmpty()) {
00232                 QSet<FindMatchesJob *> deadJobs;
00233                 foreach (FindMatchesJob *job, searchJobs) {
00234                     if (deadRunners.contains(job->runner())) {
00235                         QObject::disconnect(job, SIGNAL(done(ThreadWeaver::Job*)), q, SLOT(jobDone(ThreadWeaver::Job*)));
00236                         searchJobs.remove(job);
00237                         deadJobs.insert(job);
00238                     }
00239                 }
00240 
00241                 foreach (FindMatchesJob *job, oldSearchJobs) {
00242                     if (deadRunners.contains(job->runner())) {
00243                         oldSearchJobs.remove(job);
00244                         deadJobs.insert(job);
00245                     }
00246                 }
00247 
00248             if (deadJobs.isEmpty()) {
00249                 qDeleteAll(deadRunners);
00250             } else {
00251                 new DelayedJobCleaner(deadJobs, deadRunners);
00252             }
00253         }
00254 
00255         if (!singleRunnerWasLoaded) {
00256             // in case we deleted it up above
00257             clearSingleRunner();
00258         }
00259 
00260         kDebug() << "All runners loaded, total:" << runners.count();
00261     }
00262 
00263     AbstractRunner *loadInstalledRunner(const KService::Ptr service)
00264     {
00265         if (!service) {
00266             return 0;
00267         }
00268 
00269         AbstractRunner *runner = PluginLoader::pluginLoader()->loadRunner(service->property("X-KDE-PluginInfo-Name", QVariant::String).toString());
00270 
00271         if (runner) {
00272             runner->setParent(q);
00273         } else {
00274             const QString api = service->property("X-Plasma-API").toString();
00275 
00276             if (api.isEmpty()) {
00277                 QVariantList args;
00278                 args << service->storageId();
00279                 if (Plasma::isPluginVersionCompatible(KPluginLoader(*service).pluginVersion())) {
00280                     QString error;
00281                     runner = service->createInstance<AbstractRunner>(q, args, &error);
00282                     if (!runner) {
00283                         kDebug() << "Failed to load runner:" << service->name() << ". error reported:" << error;
00284                     }
00285                 }
00286             } else {
00287                 //kDebug() << "got a script runner known as" << api;
00288                 runner = new AbstractRunner(service, q);
00289             }
00290         }
00291 
00292         if (runner) {
00293             kDebug() << "================= loading runner:" << service->name() << "=================";
00294             QObject::connect(runner, SIGNAL(matchingSuspended(bool)), q, SLOT(runnerMatchingSuspended(bool)));
00295             QMetaObject::invokeMethod(runner, "init");
00296         }
00297 
00298         return runner;
00299     }
00300 
00301     void jobDone(ThreadWeaver::Job *job)
00302     {
00303         FindMatchesJob *runJob = dynamic_cast<FindMatchesJob *>(job);
00304 
00305         if (!runJob) {
00306             return;
00307         }
00308 
00309         if (deferredRun.isEnabled() && runJob->runner() == deferredRun.runner()) {
00310             //kDebug() << "job actually done, running now **************";
00311             QueryMatch tmpRun = deferredRun;
00312             deferredRun = QueryMatch(0);
00313             tmpRun.run(context);
00314         }
00315 
00316         searchJobs.remove(runJob);
00317         oldSearchJobs.remove(runJob);
00318         runJob->deleteLater();
00319 
00320         if (searchJobs.isEmpty() && context.matches().isEmpty()) {
00321             // we finished our run, and there are no valid matches, and so no
00322             // signal will have been sent out. so we need to emit the signal
00323             // ourselves here
00324             emit q->matchesChanged(context.matches());
00325         }
00326 
00327         checkTearDown();
00328     }
00329 
00330     void checkTearDown()
00331     {
00332         //kDebug() << prepped << teardownRequested << searchJobs.count() << oldSearchJobs.count();
00333 
00334         if (!prepped || !teardownRequested) {
00335             return;
00336         }
00337 
00338         if (Weaver::instance()->isIdle()) {
00339             qDeleteAll(searchJobs);
00340             searchJobs.clear();
00341             qDeleteAll(oldSearchJobs);
00342             oldSearchJobs.clear();
00343         }
00344 
00345         if (searchJobs.isEmpty() && oldSearchJobs.isEmpty()) {
00346             if (allRunnersPrepped) {
00347                 foreach (AbstractRunner *runner, runners) {
00348                     emit runner->teardown();
00349                 }
00350 
00351                 allRunnersPrepped = false;
00352             }
00353 
00354             if (singleRunnerPrepped) {
00355                 if (currentSingleRunner) {
00356                     emit currentSingleRunner->teardown();
00357                 }
00358 
00359                 singleRunnerPrepped = false;
00360             }
00361 
00362             emit q->queryFinished();
00363 
00364             prepped = false;
00365             teardownRequested = false;
00366         }
00367     }
00368 
00369     void unblockJobs()
00370     {
00371         // WORKAROUND: Queue an empty job to force ThreadWeaver to awaken threads
00372         if (searchJobs.isEmpty() && Weaver::instance()->isIdle()) {
00373             qDeleteAll(oldSearchJobs);
00374             oldSearchJobs.clear();
00375             checkTearDown();
00376             return;
00377         }
00378 
00379         DummyJob *dummy = new DummyJob(q);
00380         Weaver::instance()->enqueue(dummy);
00381         QObject::connect(dummy, SIGNAL(done(ThreadWeaver::Job*)), dummy, SLOT(deleteLater()));
00382     }
00383 
00384     void runnerMatchingSuspended(bool suspended)
00385     {
00386         if (suspended || !prepped || teardownRequested) {
00387             return;
00388         }
00389 
00390         AbstractRunner *runner = qobject_cast<AbstractRunner *>(q->sender());
00391 
00392         if (runner) {
00393             startJob(runner);
00394         }
00395     }
00396 
00397     void startJob(AbstractRunner *runner)
00398     {
00399         if ((runner->ignoredTypes() & context.type()) == 0) {
00400             FindMatchesJob *job = new FindMatchesJob(runner, &context, Weaver::instance());
00401             QObject::connect(job, SIGNAL(done(ThreadWeaver::Job*)), q, SLOT(jobDone(ThreadWeaver::Job*)));
00402             if (runner->speed() == AbstractRunner::SlowSpeed) {
00403                 job->setDelayTimer(&delayTimer);
00404             }
00405             Weaver::instance()->enqueue(job);
00406             searchJobs.insert(job);
00407         }
00408     }
00409 
00410     // Delay in ms before slow runners are allowed to run
00411     static const int slowRunDelay = 400;
00412 
00413     RunnerManager *q;
00414     QueryMatch deferredRun;
00415     RunnerContext context;
00416     QTimer matchChangeTimer;
00417     QTimer delayTimer; // Timer to control when to run slow runners
00418     QHash<QString, AbstractRunner*> runners;
00419     QHash<QString, QString> advertiseSingleRunnerIds;
00420     AbstractRunner* currentSingleRunner;
00421     QSet<FindMatchesJob*> searchJobs;
00422     QSet<FindMatchesJob*> oldSearchJobs;
00423     KConfigGroup conf;
00424     QString singleModeRunnerId;
00425     bool loadAll : 1;
00426     bool prepped : 1;
00427     bool allRunnersPrepped : 1;
00428     bool singleRunnerPrepped : 1;
00429     bool teardownRequested : 1;
00430     bool singleMode : 1;
00431     bool singleRunnerWasLoaded : 1;
00432 };
00433 
00434 /*****************************************************
00435 *  RunnerManager::Public class
00436 *
00437 *****************************************************/
00438 RunnerManager::RunnerManager(QObject *parent)
00439     : QObject(parent),
00440       d(new RunnerManagerPrivate(this))
00441 {
00442     d->loadConfiguration();
00443     //ThreadWeaver::setDebugLevel(true, 4);
00444 }
00445 
00446 RunnerManager::RunnerManager(KConfigGroup &c, QObject *parent)
00447     : QObject(parent),
00448       d(new RunnerManagerPrivate(this))
00449 {
00450     // Should this be really needed? Maybe d->loadConfiguration(c) would make
00451     // more sense.
00452     d->conf = KConfigGroup(&c, "PlasmaRunnerManager");
00453     d->loadConfiguration();
00454     //ThreadWeaver::setDebugLevel(true, 4);
00455 }
00456 
00457 RunnerManager::~RunnerManager()
00458 {
00459     if (!qApp->closingDown() && (!d->searchJobs.isEmpty() || !d->oldSearchJobs.isEmpty())) {
00460         new DelayedJobCleaner(d->searchJobs + d->oldSearchJobs);
00461     }
00462 
00463     delete d;
00464 }
00465 
00466 void RunnerManager::reloadConfiguration()
00467 {
00468     d->loadConfiguration();
00469     d->loadRunners();
00470 }
00471 
00472 void RunnerManager::setAllowedRunners(const QStringList &runners)
00473 {
00474     KConfigGroup config = d->configGroup();
00475     config.writeEntry("pluginWhiteList", runners);
00476 
00477     if (!d->runners.isEmpty()) {
00478         // this has been called with runners already created. so let's do an instant reload
00479         d->loadRunners();
00480     }
00481 }
00482 
00483 QStringList RunnerManager::allowedRunners() const
00484 {
00485     KConfigGroup config = d->configGroup();
00486     return config.readEntry("pluginWhiteList", QStringList());
00487 }
00488 
00489 void RunnerManager::loadRunner(const KService::Ptr service)
00490 {
00491     KPluginInfo description(service);
00492     const QString runnerName = description.pluginName();
00493     if (!runnerName.isEmpty() && !d->runners.contains(runnerName)) {
00494         AbstractRunner *runner = d->loadInstalledRunner(service);
00495         if (runner) {
00496             d->runners.insert(runnerName, runner);
00497         }
00498     }
00499 }
00500 
00501 void RunnerManager::loadRunner(const QString &path)
00502 {
00503     if (!d->runners.contains(path)) {
00504         AbstractRunner *runner = new AbstractRunner(this, path);
00505         connect(runner, SIGNAL(matchingSuspended(bool)), this, SLOT(runnerMatchingSuspended(bool)));
00506         d->runners.insert(path, runner);
00507     }
00508 }
00509 
00510 AbstractRunner* RunnerManager::runner(const QString &name) const
00511 {
00512     if (d->runners.isEmpty()) {
00513         d->loadRunners();
00514     }
00515 
00516     return d->runners.value(name, 0);
00517 }
00518 
00519 AbstractRunner *RunnerManager::singleModeRunner() const
00520 {
00521     return d->currentSingleRunner;
00522 }
00523 
00524 void RunnerManager::setSingleModeRunnerId(const QString &id)
00525 {
00526     d->singleModeRunnerId = id;
00527     d->loadSingleRunner();
00528 }
00529 
00530 QString RunnerManager::singleModeRunnerId() const
00531 {
00532     return d->singleModeRunnerId;
00533 }
00534 
00535 bool RunnerManager::singleMode() const
00536 {
00537     return d->singleMode;
00538 }
00539 
00540 void RunnerManager::setSingleMode(bool singleMode)
00541 {
00542     if (d->singleMode == singleMode) {
00543         return;
00544     }
00545 
00546 
00547     Plasma::AbstractRunner *prevSingleRunner = d->currentSingleRunner;
00548     d->singleMode = singleMode;
00549     d->loadSingleRunner();
00550     d->singleMode = d->currentSingleRunner;
00551 
00552     if (prevSingleRunner != d->currentSingleRunner) {
00553         if (d->prepped) {
00554             matchSessionComplete();
00555 
00556             if (d->singleMode) {
00557                 setupMatchSession();
00558             }
00559         }
00560     }
00561 }
00562 
00563 QList<AbstractRunner *> RunnerManager::runners() const
00564 {
00565     return d->runners.values();
00566 }
00567 
00568 QStringList RunnerManager::singleModeAdvertisedRunnerIds() const
00569 {
00570     return d->advertiseSingleRunnerIds.keys();
00571 }
00572 
00573 QString RunnerManager::runnerName(const QString &id) const
00574 {
00575     if (runner(id)) {
00576         return runner(id)->name();
00577     } else {
00578         return d->advertiseSingleRunnerIds.value(id, QString());
00579     }
00580 }
00581 
00582 RunnerContext* RunnerManager::searchContext() const
00583 {
00584     return &d->context;
00585 }
00586 
00587 //Reordering is here so data is not reordered till strictly needed
00588 QList<QueryMatch> RunnerManager::matches() const
00589 {
00590     return d->context.matches();
00591 }
00592 
00593 void RunnerManager::run(const QString &id)
00594 {
00595     run(d->context.match(id));
00596 }
00597 
00598 void RunnerManager::run(const QueryMatch &match)
00599 {
00600     if (!match.isEnabled()) {
00601         return;
00602     }
00603 
00604     //TODO: this function is not const as it may be used for learning
00605     AbstractRunner *runner = match.runner();
00606 
00607     foreach (FindMatchesJob *job, d->searchJobs) {
00608         if (job->runner() == runner && !job->isFinished()) {
00609             kDebug() << "deferred run";
00610             d->deferredRun = match;
00611             return;
00612         }
00613     }
00614 
00615     if (d->deferredRun.isValid()) {
00616         d->deferredRun = QueryMatch(0);
00617     }
00618 
00619     d->context.run(match);
00620 }
00621 
00622 QList<QAction*> RunnerManager::actionsForMatch(const QueryMatch &match)
00623 {
00624     AbstractRunner *runner = match.runner();
00625     if (runner) {
00626         return runner->actionsForMatch(match);
00627     }
00628 
00629     return QList<QAction*>();
00630 }
00631 
00632 QMimeData * RunnerManager::mimeDataForMatch(const QString &id) const
00633 {
00634     return mimeDataForMatch(d->context.match(id));
00635 }
00636 
00637 
00638 QMimeData * RunnerManager::mimeDataForMatch(const QueryMatch &match) const
00639 {
00640     AbstractRunner *runner = match.runner();
00641     QMimeData *mimeData;
00642     if (runner && QMetaObject::invokeMethod(
00643             runner,
00644             "mimeDataForMatch", Qt::DirectConnection,
00645             Q_RETURN_ARG(QMimeData*, mimeData),
00646             Q_ARG(const Plasma::QueryMatch *, &match)
00647     )) {
00648         return mimeData;
00649     }
00650 
00651     return 0;
00652 }
00653 
00654 KPluginInfo::List RunnerManager::listRunnerInfo(const QString &parentApp)
00655 {
00656     return PluginLoader::pluginLoader()->listRunnerInfo(parentApp);
00657 }
00658 
00659 void RunnerManager::setupMatchSession()
00660 {
00661     d->teardownRequested = false;
00662 
00663     if (d->prepped) {
00664         return;
00665     }
00666 
00667     d->prepped = true;
00668     if (d->singleMode) {
00669         if (d->currentSingleRunner) {
00670             emit d->currentSingleRunner->prepare();
00671             d->singleRunnerPrepped = true;
00672         }
00673     } else {
00674         foreach (AbstractRunner *runner, d->runners) {
00675 #ifdef MEASURE_PREPTIME
00676             QTime t;
00677             t.start();
00678 #endif
00679             emit runner->prepare();
00680 #ifdef MEASURE_PREPTIME
00681             kDebug() << t.elapsed() << runner->name();
00682 #endif
00683         }
00684 
00685         d->allRunnersPrepped = true;
00686     }
00687 }
00688 
00689 void RunnerManager::matchSessionComplete()
00690 {
00691     if (!d->prepped) {
00692         return;
00693     }
00694 
00695     d->teardownRequested = true;
00696     d->checkTearDown();
00697 }
00698 
00699 void RunnerManager::launchQuery(const QString &term)
00700 {
00701     launchQuery(term, QString());
00702 }
00703 
00704 void RunnerManager::launchQuery(const QString &untrimmedTerm, const QString &runnerName)
00705 {
00706     setupMatchSession();
00707     QString term = untrimmedTerm.trimmed();
00708 
00709     setSingleModeRunnerId(runnerName);
00710     setSingleMode(!runnerName.isEmpty());
00711 
00712     if (term.isEmpty()) {
00713         if (d->singleMode && d->currentSingleRunner && d->currentSingleRunner->defaultSyntax()) {
00714             term = d->currentSingleRunner->defaultSyntax()->exampleQueries().first().remove(QRegExp(":q:"));
00715         } else {
00716             reset();
00717             return;
00718         }
00719     }
00720 
00721     if (d->context.query() == term) {
00722         // we already are searching for this!
00723         return;
00724     }
00725 
00726     if (d->singleMode && !d->currentSingleRunner) {
00727         reset();
00728         return;
00729     }
00730 
00731     if (d->runners.isEmpty()) {
00732         d->loadRunners();
00733     }
00734 
00735     reset();
00736 //    kDebug() << "runners searching for" << term << "on" << runnerName;
00737     d->context.setQuery(term);
00738 
00739     QHash<QString, AbstractRunner*> runable;
00740 
00741     //if the name is not empty we will launch only the specified runner
00742     if (d->singleMode && d->currentSingleRunner) {
00743         runable.insert(QString(), d->currentSingleRunner);
00744         d->context.setSingleRunnerQueryMode(true);
00745     } else {
00746         runable = d->runners;
00747     }
00748 
00749     foreach (Plasma::AbstractRunner *r, runable) {
00750         if (r->isMatchingSuspended()) {
00751             continue;
00752         }
00753 
00754         d->startJob(r);
00755     }
00756 
00757     // Start timer to unblock slow runners
00758     d->delayTimer.start(RunnerManagerPrivate::slowRunDelay);
00759 }
00760 
00761 bool RunnerManager::execQuery(const QString &term)
00762 {
00763     return execQuery(term, QString());
00764 }
00765 
00766 bool RunnerManager::execQuery(const QString &untrimmedTerm, const QString &runnerName)
00767 {
00768     QString term = untrimmedTerm.trimmed();
00769 
00770     if (term.isEmpty()) {
00771         reset();
00772         return false;
00773     }
00774 
00775     if (d->runners.isEmpty()) {
00776         d->loadRunners();
00777     }
00778 
00779     if (d->context.query() == term) {
00780         // we already are searching for this!
00781         emit matchesChanged(d->context.matches());
00782         return false;
00783     }
00784 
00785     reset();
00786     //kDebug() << "executing query about " << term << "on" << runnerName;
00787     d->context.setQuery(term);
00788     AbstractRunner *r = runner(runnerName);
00789 
00790     if (!r) {
00791         //kDebug() << "failed to find the runner";
00792         return false;
00793     }
00794 
00795     if ((r->ignoredTypes() & d->context.type()) != 0) {
00796         //kDebug() << "ignored!";
00797         return false;
00798     }
00799 
00800     r->performMatch(d->context);
00801     //kDebug() << "succeeded with" << d->context.matches().count() << "results";
00802     emit matchesChanged(d->context.matches());
00803     return true;
00804 }
00805 
00806 QString RunnerManager::query() const
00807 {
00808     return d->context.query();
00809 }
00810 
00811 void RunnerManager::reset()
00812 {
00813     // If ThreadWeaver is idle, it is safe to clear previous jobs
00814     if (Weaver::instance()->isIdle()) {
00815         qDeleteAll(d->searchJobs);
00816         qDeleteAll(d->oldSearchJobs);
00817         d->oldSearchJobs.clear();
00818     } else {
00819         Q_FOREACH(FindMatchesJob *job, d->searchJobs) {
00820             Weaver::instance()->dequeue(job);
00821         }
00822         d->oldSearchJobs += d->searchJobs;
00823     }
00824 
00825     d->searchJobs.clear();
00826 
00827     if (d->deferredRun.isEnabled()) {
00828         //kDebug() << "job actually done, running now **************";
00829         QueryMatch tmpRun = d->deferredRun;
00830         d->deferredRun = QueryMatch(0);
00831         tmpRun.run(d->context);
00832     }
00833 
00834     d->context.reset();
00835 }
00836 
00837 } // Plasma namespace
00838 
00839 #include "runnermanager.moc"
This file is part of the KDE documentation.
Documentation copyright © 1996-2019 The KDE developers.
Generated on Mon Jan 21 2019 12:30:44 by doxygen 1.7.5.1 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

Plasma

Skip menu "Plasma"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdelibs-4.9.5 API Reference

Skip menu "kdelibs-4.9.5 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal