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 kDebug() << "All runners loaded, total:" << runners.count(); 00256 } 00257 00258 AbstractRunner *loadInstalledRunner(const KService::Ptr service) 00259 { 00260 if (!service) { 00261 return 0; 00262 } 00263 00264 AbstractRunner *runner = PluginLoader::pluginLoader()->loadRunner(service->property("X-KDE-PluginInfo-Name", QVariant::String).toString()); 00265 00266 if (runner) { 00267 runner->setParent(q); 00268 } else { 00269 const QString api = service->property("X-Plasma-API").toString(); 00270 00271 if (api.isEmpty()) { 00272 QVariantList args; 00273 args << service->storageId(); 00274 if (Plasma::isPluginVersionCompatible(KPluginLoader(*service).pluginVersion())) { 00275 QString error; 00276 runner = service->createInstance<AbstractRunner>(q, args, &error); 00277 if (!runner) { 00278 kDebug() << "Failed to load runner:" << service->name() << ". error reported:" << error; 00279 } 00280 } 00281 } else { 00282 //kDebug() << "got a script runner known as" << api; 00283 runner = new AbstractRunner(service, q); 00284 } 00285 } 00286 00287 if (runner) { 00288 kDebug() << "================= loading runner:" << service->name() << "================="; 00289 QObject::connect(runner, SIGNAL(matchingSuspended(bool)), q, SLOT(runnerMatchingSuspended(bool))); 00290 QMetaObject::invokeMethod(runner, "init"); 00291 } 00292 00293 return runner; 00294 } 00295 00296 void jobDone(ThreadWeaver::Job *job) 00297 { 00298 FindMatchesJob *runJob = dynamic_cast<FindMatchesJob *>(job); 00299 00300 if (!runJob) { 00301 return; 00302 } 00303 00304 if (deferredRun.isEnabled() && runJob->runner() == deferredRun.runner()) { 00305 //kDebug() << "job actually done, running now **************"; 00306 QueryMatch tmpRun = deferredRun; 00307 deferredRun = QueryMatch(0); 00308 tmpRun.run(context); 00309 } 00310 00311 searchJobs.remove(runJob); 00312 oldSearchJobs.remove(runJob); 00313 runJob->deleteLater(); 00314 00315 if (searchJobs.isEmpty() && context.matches().isEmpty()) { 00316 // we finished our run, and there are no valid matches, and so no 00317 // signal will have been sent out. so we need to emit the signal 00318 // ourselves here 00319 emit q->matchesChanged(context.matches()); 00320 } 00321 00322 checkTearDown(); 00323 } 00324 00325 void checkTearDown() 00326 { 00327 //kDebug() << prepped << teardownRequested << searchJobs.count() << oldSearchJobs.count(); 00328 00329 if (!prepped || !teardownRequested) { 00330 return; 00331 } 00332 00333 if (Weaver::instance()->isIdle()) { 00334 qDeleteAll(searchJobs); 00335 searchJobs.clear(); 00336 qDeleteAll(oldSearchJobs); 00337 oldSearchJobs.clear(); 00338 } 00339 00340 if (searchJobs.isEmpty() && oldSearchJobs.isEmpty()) { 00341 if (allRunnersPrepped) { 00342 foreach (AbstractRunner *runner, runners) { 00343 emit runner->teardown(); 00344 } 00345 00346 allRunnersPrepped = false; 00347 } 00348 00349 if (singleRunnerPrepped) { 00350 if (currentSingleRunner) { 00351 emit currentSingleRunner->teardown(); 00352 } 00353 00354 singleRunnerPrepped = false; 00355 } 00356 00357 emit q->queryFinished(); 00358 00359 prepped = false; 00360 teardownRequested = false; 00361 } 00362 } 00363 00364 void unblockJobs() 00365 { 00366 // WORKAROUND: Queue an empty job to force ThreadWeaver to awaken threads 00367 if (searchJobs.isEmpty() && Weaver::instance()->isIdle()) { 00368 qDeleteAll(oldSearchJobs); 00369 oldSearchJobs.clear(); 00370 checkTearDown(); 00371 return; 00372 } 00373 00374 DummyJob *dummy = new DummyJob(q); 00375 Weaver::instance()->enqueue(dummy); 00376 QObject::connect(dummy, SIGNAL(done(ThreadWeaver::Job*)), dummy, SLOT(deleteLater())); 00377 } 00378 00379 void runnerMatchingSuspended(bool suspended) 00380 { 00381 if (suspended || !prepped || teardownRequested) { 00382 return; 00383 } 00384 00385 AbstractRunner *runner = qobject_cast<AbstractRunner *>(q->sender()); 00386 00387 if (runner) { 00388 startJob(runner); 00389 } 00390 } 00391 00392 void startJob(AbstractRunner *runner) 00393 { 00394 if ((runner->ignoredTypes() & context.type()) == 0) { 00395 FindMatchesJob *job = new FindMatchesJob(runner, &context, Weaver::instance()); 00396 QObject::connect(job, SIGNAL(done(ThreadWeaver::Job*)), q, SLOT(jobDone(ThreadWeaver::Job*))); 00397 if (runner->speed() == AbstractRunner::SlowSpeed) { 00398 job->setDelayTimer(&delayTimer); 00399 } 00400 Weaver::instance()->enqueue(job); 00401 searchJobs.insert(job); 00402 } 00403 } 00404 00405 // Delay in ms before slow runners are allowed to run 00406 static const int slowRunDelay = 400; 00407 00408 RunnerManager *q; 00409 QueryMatch deferredRun; 00410 RunnerContext context; 00411 QTimer matchChangeTimer; 00412 QTimer delayTimer; // Timer to control when to run slow runners 00413 QHash<QString, AbstractRunner*> runners; 00414 QHash<QString, QString> advertiseSingleRunnerIds; 00415 AbstractRunner* currentSingleRunner; 00416 QSet<FindMatchesJob*> searchJobs; 00417 QSet<FindMatchesJob*> oldSearchJobs; 00418 KConfigGroup conf; 00419 QString singleModeRunnerId; 00420 bool loadAll : 1; 00421 bool prepped : 1; 00422 bool allRunnersPrepped : 1; 00423 bool singleRunnerPrepped : 1; 00424 bool teardownRequested : 1; 00425 bool singleMode : 1; 00426 bool singleRunnerWasLoaded : 1; 00427 }; 00428 00429 /***************************************************** 00430 * RunnerManager::Public class 00431 * 00432 *****************************************************/ 00433 RunnerManager::RunnerManager(QObject *parent) 00434 : QObject(parent), 00435 d(new RunnerManagerPrivate(this)) 00436 { 00437 d->loadConfiguration(); 00438 //ThreadWeaver::setDebugLevel(true, 4); 00439 } 00440 00441 RunnerManager::RunnerManager(KConfigGroup &c, QObject *parent) 00442 : QObject(parent), 00443 d(new RunnerManagerPrivate(this)) 00444 { 00445 // Should this be really needed? Maybe d->loadConfiguration(c) would make 00446 // more sense. 00447 d->conf = KConfigGroup(&c, "PlasmaRunnerManager"); 00448 d->loadConfiguration(); 00449 //ThreadWeaver::setDebugLevel(true, 4); 00450 } 00451 00452 RunnerManager::~RunnerManager() 00453 { 00454 if (!qApp->closingDown() && (!d->searchJobs.isEmpty() || !d->oldSearchJobs.isEmpty())) { 00455 new DelayedJobCleaner(d->searchJobs + d->oldSearchJobs); 00456 } 00457 00458 delete d; 00459 } 00460 00461 void RunnerManager::reloadConfiguration() 00462 { 00463 d->loadConfiguration(); 00464 d->loadRunners(); 00465 } 00466 00467 void RunnerManager::setAllowedRunners(const QStringList &runners) 00468 { 00469 KConfigGroup config = d->configGroup(); 00470 config.writeEntry("pluginWhiteList", runners); 00471 00472 if (!d->runners.isEmpty()) { 00473 // this has been called with runners already created. so let's do an instant reload 00474 d->loadRunners(); 00475 } 00476 } 00477 00478 QStringList RunnerManager::allowedRunners() const 00479 { 00480 KConfigGroup config = d->configGroup(); 00481 return config.readEntry("pluginWhiteList", QStringList()); 00482 } 00483 00484 void RunnerManager::loadRunner(const KService::Ptr service) 00485 { 00486 KPluginInfo description(service); 00487 const QString runnerName = description.pluginName(); 00488 if (!runnerName.isEmpty() && !d->runners.contains(runnerName)) { 00489 AbstractRunner *runner = d->loadInstalledRunner(service); 00490 if (runner) { 00491 d->runners.insert(runnerName, runner); 00492 } 00493 } 00494 } 00495 00496 void RunnerManager::loadRunner(const QString &path) 00497 { 00498 if (!d->runners.contains(path)) { 00499 AbstractRunner *runner = new AbstractRunner(this, path); 00500 connect(runner, SIGNAL(matchingSuspended(bool)), this, SLOT(runnerMatchingSuspended(bool))); 00501 d->runners.insert(path, runner); 00502 } 00503 } 00504 00505 AbstractRunner* RunnerManager::runner(const QString &name) const 00506 { 00507 if (d->runners.isEmpty()) { 00508 d->loadRunners(); 00509 } 00510 00511 return d->runners.value(name, 0); 00512 } 00513 00514 AbstractRunner *RunnerManager::singleModeRunner() const 00515 { 00516 return d->currentSingleRunner; 00517 } 00518 00519 void RunnerManager::setSingleModeRunnerId(const QString &id) 00520 { 00521 d->singleModeRunnerId = id; 00522 d->loadSingleRunner(); 00523 } 00524 00525 QString RunnerManager::singleModeRunnerId() const 00526 { 00527 return d->singleModeRunnerId; 00528 } 00529 00530 bool RunnerManager::singleMode() const 00531 { 00532 return d->singleMode; 00533 } 00534 00535 void RunnerManager::setSingleMode(bool singleMode) 00536 { 00537 if (d->singleMode == singleMode) { 00538 return; 00539 } 00540 00541 00542 Plasma::AbstractRunner *prevSingleRunner = d->currentSingleRunner; 00543 d->singleMode = singleMode; 00544 d->loadSingleRunner(); 00545 d->singleMode = d->currentSingleRunner; 00546 00547 if (prevSingleRunner != d->currentSingleRunner) { 00548 if (d->prepped) { 00549 matchSessionComplete(); 00550 00551 if (d->singleMode) { 00552 setupMatchSession(); 00553 } 00554 } 00555 } 00556 } 00557 00558 QList<AbstractRunner *> RunnerManager::runners() const 00559 { 00560 return d->runners.values(); 00561 } 00562 00563 QStringList RunnerManager::singleModeAdvertisedRunnerIds() const 00564 { 00565 return d->advertiseSingleRunnerIds.keys(); 00566 } 00567 00568 QString RunnerManager::runnerName(const QString &id) const 00569 { 00570 if (runner(id)) { 00571 return runner(id)->name(); 00572 } else { 00573 return d->advertiseSingleRunnerIds.value(id, QString()); 00574 } 00575 } 00576 00577 RunnerContext* RunnerManager::searchContext() const 00578 { 00579 return &d->context; 00580 } 00581 00582 //Reordering is here so data is not reordered till strictly needed 00583 QList<QueryMatch> RunnerManager::matches() const 00584 { 00585 return d->context.matches(); 00586 } 00587 00588 void RunnerManager::run(const QString &id) 00589 { 00590 run(d->context.match(id)); 00591 } 00592 00593 void RunnerManager::run(const QueryMatch &match) 00594 { 00595 if (!match.isEnabled()) { 00596 return; 00597 } 00598 00599 //TODO: this function is not const as it may be used for learning 00600 AbstractRunner *runner = match.runner(); 00601 00602 foreach (FindMatchesJob *job, d->searchJobs) { 00603 if (job->runner() == runner && !job->isFinished()) { 00604 kDebug() << "deferred run"; 00605 d->deferredRun = match; 00606 return; 00607 } 00608 } 00609 00610 if (d->deferredRun.isValid()) { 00611 d->deferredRun = QueryMatch(0); 00612 } 00613 00614 d->context.run(match); 00615 } 00616 00617 QList<QAction*> RunnerManager::actionsForMatch(const QueryMatch &match) 00618 { 00619 AbstractRunner *runner = match.runner(); 00620 if (runner) { 00621 return runner->actionsForMatch(match); 00622 } 00623 00624 return QList<QAction*>(); 00625 } 00626 00627 QMimeData * RunnerManager::mimeDataForMatch(const QString &id) const 00628 { 00629 return mimeDataForMatch(d->context.match(id)); 00630 } 00631 00632 00633 QMimeData * RunnerManager::mimeDataForMatch(const QueryMatch &match) const 00634 { 00635 AbstractRunner *runner = match.runner(); 00636 QMimeData *mimeData; 00637 if (runner && QMetaObject::invokeMethod( 00638 runner, 00639 "mimeDataForMatch", Qt::DirectConnection, 00640 Q_RETURN_ARG(QMimeData*, mimeData), 00641 Q_ARG(const Plasma::QueryMatch *, &match) 00642 )) { 00643 return mimeData; 00644 } 00645 00646 return 0; 00647 } 00648 00649 KPluginInfo::List RunnerManager::listRunnerInfo(const QString &parentApp) 00650 { 00651 return PluginLoader::pluginLoader()->listRunnerInfo(parentApp); 00652 } 00653 00654 void RunnerManager::setupMatchSession() 00655 { 00656 d->teardownRequested = false; 00657 00658 if (d->prepped) { 00659 return; 00660 } 00661 00662 d->prepped = true; 00663 if (d->singleMode) { 00664 if (d->currentSingleRunner) { 00665 emit d->currentSingleRunner->prepare(); 00666 d->singleRunnerPrepped = true; 00667 } 00668 } else { 00669 foreach (AbstractRunner *runner, d->runners) { 00670 #ifdef MEASURE_PREPTIME 00671 QTime t; 00672 t.start(); 00673 #endif 00674 emit runner->prepare(); 00675 #ifdef MEASURE_PREPTIME 00676 kDebug() << t.elapsed() << runner->name(); 00677 #endif 00678 } 00679 00680 d->allRunnersPrepped = true; 00681 } 00682 } 00683 00684 void RunnerManager::matchSessionComplete() 00685 { 00686 if (!d->prepped) { 00687 return; 00688 } 00689 00690 d->teardownRequested = true; 00691 d->checkTearDown(); 00692 } 00693 00694 void RunnerManager::launchQuery(const QString &term) 00695 { 00696 launchQuery(term, QString()); 00697 } 00698 00699 void RunnerManager::launchQuery(const QString &untrimmedTerm, const QString &runnerName) 00700 { 00701 setupMatchSession(); 00702 QString term = untrimmedTerm.trimmed(); 00703 00704 setSingleModeRunnerId(runnerName); 00705 setSingleMode(!runnerName.isEmpty()); 00706 00707 if (term.isEmpty()) { 00708 if (d->singleMode && d->currentSingleRunner && d->currentSingleRunner->defaultSyntax()) { 00709 term = d->currentSingleRunner->defaultSyntax()->exampleQueries().first().remove(QRegExp(":q:")); 00710 } else { 00711 reset(); 00712 return; 00713 } 00714 } 00715 00716 if (d->context.query() == term) { 00717 // we already are searching for this! 00718 return; 00719 } 00720 00721 if (d->singleMode && !d->currentSingleRunner) { 00722 reset(); 00723 return; 00724 } 00725 00726 if (d->runners.isEmpty()) { 00727 d->loadRunners(); 00728 } 00729 00730 reset(); 00731 // kDebug() << "runners searching for" << term << "on" << runnerName; 00732 d->context.setQuery(term); 00733 00734 QHash<QString, AbstractRunner*> runable; 00735 00736 //if the name is not empty we will launch only the specified runner 00737 if (d->singleMode && d->currentSingleRunner) { 00738 runable.insert(QString(), d->currentSingleRunner); 00739 d->context.setSingleRunnerQueryMode(true); 00740 } else { 00741 runable = d->runners; 00742 } 00743 00744 foreach (Plasma::AbstractRunner *r, runable) { 00745 if (r->isMatchingSuspended()) { 00746 continue; 00747 } 00748 00749 d->startJob(r); 00750 } 00751 00752 // Start timer to unblock slow runners 00753 d->delayTimer.start(RunnerManagerPrivate::slowRunDelay); 00754 } 00755 00756 bool RunnerManager::execQuery(const QString &term) 00757 { 00758 return execQuery(term, QString()); 00759 } 00760 00761 bool RunnerManager::execQuery(const QString &untrimmedTerm, const QString &runnerName) 00762 { 00763 QString term = untrimmedTerm.trimmed(); 00764 00765 if (term.isEmpty()) { 00766 reset(); 00767 return false; 00768 } 00769 00770 if (d->runners.isEmpty()) { 00771 d->loadRunners(); 00772 } 00773 00774 if (d->context.query() == term) { 00775 // we already are searching for this! 00776 emit matchesChanged(d->context.matches()); 00777 return false; 00778 } 00779 00780 reset(); 00781 //kDebug() << "executing query about " << term << "on" << runnerName; 00782 d->context.setQuery(term); 00783 AbstractRunner *r = runner(runnerName); 00784 00785 if (!r) { 00786 //kDebug() << "failed to find the runner"; 00787 return false; 00788 } 00789 00790 if ((r->ignoredTypes() & d->context.type()) != 0) { 00791 //kDebug() << "ignored!"; 00792 return false; 00793 } 00794 00795 r->performMatch(d->context); 00796 //kDebug() << "succeeded with" << d->context.matches().count() << "results"; 00797 emit matchesChanged(d->context.matches()); 00798 return true; 00799 } 00800 00801 QString RunnerManager::query() const 00802 { 00803 return d->context.query(); 00804 } 00805 00806 void RunnerManager::reset() 00807 { 00808 // If ThreadWeaver is idle, it is safe to clear previous jobs 00809 if (Weaver::instance()->isIdle()) { 00810 qDeleteAll(d->searchJobs); 00811 qDeleteAll(d->oldSearchJobs); 00812 d->oldSearchJobs.clear(); 00813 } else { 00814 Weaver::instance()->dequeue(); 00815 d->oldSearchJobs += d->searchJobs; 00816 } 00817 00818 d->searchJobs.clear(); 00819 00820 if (d->deferredRun.isEnabled()) { 00821 //kDebug() << "job actually done, running now **************"; 00822 QueryMatch tmpRun = d->deferredRun; 00823 d->deferredRun = QueryMatch(0); 00824 tmpRun.run(d->context); 00825 } 00826 00827 d->context.reset(); 00828 } 00829 00830 } // Plasma namespace 00831 00832 #include "runnermanager.moc"
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Thu May 10 2012 20:51:37 by doxygen 1.8.0 written by Dimitri van Heesch, © 1997-2006
Documentation copyright © 1996-2012 The KDE developers.
Generated on Thu May 10 2012 20:51:37 by doxygen 1.8.0 written by Dimitri van Heesch, © 1997-2006
KDE's Doxygen guidelines are available online.