diff --git a/querymatch.cpp b/querymatch.cpp index d8fe800ed..9bf7f855a 100644 --- a/querymatch.cpp +++ b/querymatch.cpp @@ -98,7 +98,7 @@ QueryMatch::Type QueryMatch::type() const void QueryMatch::setRelevance(qreal relevance) { - d->relevance = qMax(qreal(0.0), qMin(qreal(1.0), relevance)); + d->relevance = qMax(qreal(0.0), relevance); } qreal QueryMatch::relevance() const diff --git a/runnercontext.cpp b/runnercontext.cpp index 6ee96206d..0df148c34 100644 --- a/runnercontext.cpp +++ b/runnercontext.cpp @@ -27,6 +27,7 @@ #include #include +#include #include #include #include @@ -157,6 +158,7 @@ class RunnerContextPrivate : public QSharedData RunnerContextPrivate(const RunnerContextPrivate &p) : QSharedData(), + launchCounts(p.launchCounts), type(RunnerContext::None), q(p.q) { @@ -218,6 +220,7 @@ class RunnerContextPrivate : public QSharedData QReadWriteLock lock; QList matches; QMap matchesById; + QHash launchCounts; QString term; QString mimeType; RunnerContext::Type type; @@ -323,7 +326,12 @@ bool RunnerContext::addMatches(const QString &term, const QList &mat } LOCK_FOR_WRITE(this) - foreach (const QueryMatch &match, matches) { + foreach (QueryMatch match, matches) { + // Give previously launched matches a slight boost in relevance + if (int count = d->launchCounts.value(match.id())) { + match.setRelevance(match.relevance() + 0.05 * count); + } + d->matches.append(match); #ifndef NDEBUG if (d->matchesById.contains(match.id())) { @@ -351,9 +359,16 @@ bool RunnerContext::addMatch(const QString &term, const QueryMatch &match) return false; } + QueryMatch m(match); // match must be non-const to modify relevance + LOCK_FOR_WRITE(this) - d->matches.append(match); - d->matchesById.insert(match.id(), &d->matches.at(d->matches.size() - 1)); + + if (int count = d->launchCounts.value(m.id())) { + m.setRelevance(m.relevance() + 0.05 * count); + } + + d->matches.append(m); + d->matchesById.insert(m.id(), &d->matches.at(d->matches.size() - 1)); UNLOCK(this); //kDebug()<< "added match" << match->text(); emit d->q->matchesChanged(); @@ -382,6 +397,39 @@ QueryMatch RunnerContext::match(const QString &id) const return QueryMatch(0); } +void RunnerContext::restore(const KConfigGroup &config) +{ + QStringList cfgList = config.readEntry("LaunchCounts", QStringList()); + + QRegExp r("(\\d*) (.*)"); + foreach (QString entry, cfgList) { + r.indexIn(entry); + int count = r.cap(1).toInt(); + QString id = r.cap(2); + d->launchCounts[id] = count; + } +} + +void RunnerContext::save(KConfigGroup &config) +{ + QStringList countList; + + typedef QHash::const_iterator Iterator; + Iterator end = d->launchCounts.constEnd(); + for (Iterator i = d->launchCounts.constBegin(); i != end; ++i) { + countList << QString("%2 %1").arg(i.key()).arg(i.value()); + } + + config.writeEntry("LaunchCounts", countList); + config.sync(); +} + +void RunnerContext::run(const QueryMatch &match) +{ + ++d->launchCounts[match.id()]; + match.run(*this); +} + } // Plasma namespace #include "runnercontext.moc" diff --git a/runnercontext.h b/runnercontext.h index 0a31f0b1f..d862f5a22 100644 --- a/runnercontext.h +++ b/runnercontext.h @@ -27,6 +27,7 @@ #include class KCompletion; +class KConfigGroup; namespace Plasma { @@ -163,6 +164,33 @@ class PLASMA_EXPORT RunnerContext : public QObject */ QueryMatch match(const QString &id) const; + /** + * Sets the launch counts for the associated match ids + * + * If a runner adds a match to this context, the context will check if the + * match id has been launched before and increase the matches relevance + * correspondingly. In this manner, any front end can implement adaptive search + * by sorting items according to relevance. + * + * @param config the config group where launch data was stored + */ + void restore(const KConfigGroup &config); + + /** + * @param config the config group where launch data should be stored + */ + void save(KConfigGroup &config); + + /** + * Run a match using the information from this context + * + * The context will also keep track of the number of times the match was + * launched to sort future matches according to user habits + * + * @param match the match to run + */ + void run(const QueryMatch &match); + Q_SIGNALS: void matchesChanged(); diff --git a/runnermanager.cpp b/runnermanager.cpp index 4b319299a..205f54934 100644 --- a/runnermanager.cpp +++ b/runnermanager.cpp @@ -66,6 +66,11 @@ public: QObject::connect(&delayTimer, SIGNAL(timeout()), q, SLOT(unblockJobs())); } + ~RunnerManagerPrivate() + { + context.saveLaunchCounts(config); + } + void scheduleMatchesChanged() { matchChangeTimer.start(50); @@ -95,8 +100,7 @@ public: const int cap = qMax(2, numThreads/2); DefaultRunnerPolicy::instance().setCap(cap); - //If set, this list defines which runners won't be used at runtime - //blacklist = config.readEntry("blacklist", QStringList()); + context.restoreLaunchCounts(config); } void loadRunners() @@ -308,7 +312,7 @@ void RunnerManager::run(const QueryMatch &match) d->deferredRun = QueryMatch(0); } - match.run(d->context); + d->context.run(match); } QList RunnerManager::actionsForMatch(const QueryMatch &match)