diff --git a/runnercontext.cpp b/runnercontext.cpp index 6eb8e35dc..f7a83d0ed 100644 --- a/runnercontext.cpp +++ b/runnercontext.cpp @@ -110,6 +110,11 @@ class RunnerContextPrivate : public QSharedData } } + void invalidate() + { + q = &s_dummyContext; + } + QReadWriteLock lock; QList matches; QMap matchesById; @@ -117,8 +122,11 @@ class RunnerContextPrivate : public QSharedData QString mimeType; RunnerContext::Type type; RunnerContext * q; + static RunnerContext s_dummyContext; }; +RunnerContext RunnerContextPrivate::s_dummyContext; + RunnerContext::RunnerContext(QObject *parent) : QObject(parent), d(new RunnerContextPrivate(this)) @@ -143,14 +151,17 @@ void RunnerContext::reset() // We will detach if we are a copy of someone. But we will reset // if we are the 'main' context others copied from. Resetting // one RunnerContext makes all the copies obsolete. - - d->q = 0; //we need to mark the q pointer of the detached RunnerContextPrivate - //as dirty on detach to avoid receiving results for old queries + + // We need to invalidate the RunnerContextPrivate before detaching + // to avoid receiving results for old queries. + + d->invalidate(); d.detach(); - - d->q = this; //now that we detached the d pointer we need to mark its q pointer as - //this to receive the signals + + // Now that we detached the d pointer we need to reset its q pointer + + d->q = this; // we still have to remove all the matches, since if the // ref count was 1 (e.g. only the RunnerContext is using @@ -197,11 +208,18 @@ QString RunnerContext::mimeType() const return d->mimeType; } +bool RunnerContext::isValid() +{ + // if our qptr is dirty, we aren't useful anymore + return (d->q != &(d->s_dummyContext)); +} + bool RunnerContext::addMatches(const QString &term, const QList &matches) { Q_UNUSED(term) - if (matches.isEmpty() || (!d->q)) { //Bail out if the query is empty or the qptr is dirty + if (matches.isEmpty() || (!isValid())) { + //Bail out if the query is empty or the qptr is dirty return false; } @@ -221,7 +239,7 @@ bool RunnerContext::addMatches(const QString &term, const QList &mat // we always want to sent the signal of the object that created // the d pointer emit d->q->matchesChanged(); - + return true; } @@ -229,17 +247,18 @@ bool RunnerContext::addMatch(const QString &term, const QueryMatch &match) { Q_UNUSED(term) - if (!d->q) { // Bail out if the qptr is dirty + if (!isValid()) { + // Bail out if the qptr is dirty return false; } - + LOCK_FOR_WRITE(this) d->matches.append(match); d->matchesById.insert(match.id(), &d->matches.at(d->matches.size() - 1)); UNLOCK(this); //kDebug()<< "added match" << match->text(); - emit d->q->matchesChanged(); - + emit d->q->matchesChanged(); + return true; } diff --git a/runnercontext.h b/runnercontext.h index baa2112fd..ab68fd0c6 100644 --- a/runnercontext.h +++ b/runnercontext.h @@ -102,6 +102,26 @@ class PLASMA_EXPORT RunnerContext : public QObject */ QString mimeType() const; + /** + * @returns true if this context is no longer valid and therefore + * matching using it should abort. Most useful as an optimization technique + * inside of AbstractRunner subclasses in the match method, e.g.: + * + * while (.. a possibly large iteration) { + * if (!context.isValid()) { + * return; + * } + * + * ... some processing ... + * } + * + * While not required to be used within runners, it provies a nice way + * to avoid unecessary processing in runners that may run for an extended + * period (as measured in 10s of ms) and therefore improve the user experience. @since 4.2.3 + */ + bool isValid(); + + /** * Appends lists of matches to the list of matches. * diff --git a/runnermanager.cpp b/runnermanager.cpp index f52c42a69..5962077a4 100644 --- a/runnermanager.cpp +++ b/runnermanager.cpp @@ -161,7 +161,7 @@ void FindMatchesJob::run() { // kDebug() << "Running match for " << m_runner->objectName() // << " in Thread " << thread()->id() << endl; - m_runner->performMatch(m_context); + if (m_context.isValid()) m_runner->performMatch(m_context); } int FindMatchesJob::priority() const @@ -349,7 +349,7 @@ public: if (deferredRun.isEnabled() && runJob->runner() == deferredRun.runner()) { //kDebug() << "job actually done, running now **************"; QueryMatch tmpRun = deferredRun; - deferredRun = QueryMatch(0); + deferredRun = QueryMatch(0); tmpRun.run(context); } @@ -484,7 +484,7 @@ void RunnerManager::launchQuery(const QString &term) void RunnerManager::launchQuery(const QString &untrimmedTerm, const QString &runnerName) { QString term = untrimmedTerm.trimmed(); - + if (d->runners.isEmpty()) { d->loadRunners(); } @@ -534,7 +534,7 @@ bool RunnerManager::execQuery(const QString &term) bool RunnerManager::execQuery(const QString &untrimmedTerm, const QString &runnerName) { QString term = untrimmedTerm.trimmed(); - + if (d->runners.isEmpty()) { d->loadRunners(); }