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
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.