Add adaptive search for KRunner

svn path=/trunk/KDE/kdelibs/; revision=967705
This commit is contained in:
Ryan P. Bitanga 2009-05-13 19:18:30 +00:00
parent 4ea997a9f1
commit 9b6304fcde
4 changed files with 87 additions and 7 deletions

View File

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

View File

@ -27,6 +27,7 @@
#include <QSharedData>
#include <kcompletion.h>
#include <kconfiggroup.h>
#include <kdebug.h>
#include <kmimetype.h>
#include <kshell.h>
@ -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<QueryMatch> matches;
QMap<QString, const QueryMatch*> matchesById;
QHash<QString, int> launchCounts;
QString term;
QString mimeType;
RunnerContext::Type type;
@ -323,7 +326,12 @@ bool RunnerContext::addMatches(const QString &term, const QList<QueryMatch> &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<QString, int>::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"

View File

@ -27,6 +27,7 @@
#include <plasma/plasma_export.h>
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();

View File

@ -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<QAction*> RunnerManager::actionsForMatch(const QueryMatch &match)