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