Big patch with several internal changes to krunner:
-New RunnerManager class, it manages runners at high level and gives a simple API for interfaces to use. - AbstractRunners gains description, setIgnoredTypes, ignoredTypes methods. Now runners can specify what SearchContext::Types they are not going to process. - SearchContext tries shared data between the original context and any local context. It doesn't have its own completer no more. - SearchMatch has a new type of match, CompleterMatch. Instead of using a hard coded completer in SearchContext - Interface class on krunner has its own completer and other changes done to accomodate the above changes in libplasma. -A new configuration option blacklist for runnermanager and krunner instead of the whitelist of krunner. svn path=/trunk/KDE/kdebase/workspace/libs/plasma/; revision=802903
This commit is contained in:
parent
207968b217
commit
95157e20c4
@ -41,6 +41,7 @@ set(plasma_LIB_SRCS
|
||||
packages.cpp
|
||||
plasma.cpp
|
||||
plasma_export.h
|
||||
runnermanager.cpp
|
||||
searchmatch.cpp
|
||||
searchcontext.cpp
|
||||
shadowitem.cpp
|
||||
@ -77,7 +78,8 @@ endif(QT_QTOPENGL_FOUND AND OPENGL_FOUND)
|
||||
|
||||
kde4_add_library(plasma SHARED ${plasma_LIB_SRCS})
|
||||
|
||||
target_link_libraries(plasma ${KDE4_KIO_LIBS} ${KDE4_KFILE_LIBS} ${QT_QTUITOOLS_LIBRARY} ${QT_QTWEBKIT_LIBRARY})
|
||||
target_link_libraries(plasma ${KDE4_KIO_LIBS} ${KDE4_KFILE_LIBS}
|
||||
${QT_QTUITOOLS_LIBRARY} ${QT_QTWEBKIT_LIBRARY} ${KDE4_THREADWEAVER_LIBRARIES})
|
||||
|
||||
if(QT_QTOPENGL_FOUND AND OPENGL_FOUND)
|
||||
target_link_libraries(plasma ${QT_QTOPENGL_LIBRARY} ${OPENGL_gl_LIBRARY})
|
||||
@ -112,6 +114,7 @@ set(plasma_LIB_INCLUDES
|
||||
dialog.h
|
||||
plasma.h
|
||||
plasma_export.h
|
||||
runnermanager.h
|
||||
searchmatch.h
|
||||
searchcontext.h
|
||||
shadowitem_p.h
|
||||
|
@ -28,8 +28,11 @@
|
||||
#include <KStandardDirs>
|
||||
#include <QTimer>
|
||||
|
||||
#include "package.h"
|
||||
#include <plasma/searchmatch.h>
|
||||
#include <plasma/package.h>
|
||||
|
||||
#include "scripting/runnerscript.h"
|
||||
|
||||
#include "searchcontext.h"
|
||||
|
||||
namespace Plasma
|
||||
@ -41,6 +44,7 @@ public:
|
||||
Private(AbstractRunner* r, KService::Ptr service)
|
||||
: priority(NormalPriority),
|
||||
speed(NormalSpeed),
|
||||
blackListed(0),
|
||||
script(0),
|
||||
runnerDescription(service),
|
||||
runner(r),
|
||||
@ -73,6 +77,7 @@ public:
|
||||
bool hasConfig;
|
||||
Priority priority;
|
||||
Speed speed;
|
||||
SearchContext::Types blackListed;
|
||||
RunnerScript* script;
|
||||
KPluginInfo runnerDescription;
|
||||
AbstractRunner* runner;
|
||||
@ -119,10 +124,9 @@ void AbstractRunner::performMatch( Plasma::SearchContext &globalContext )
|
||||
static const int fastEnoughTime = 250;
|
||||
|
||||
d->runtime.restart();
|
||||
SearchContext localContext(0, globalContext);
|
||||
|
||||
//TODO :this is a copy ctor
|
||||
SearchContext localContext(globalContext,0);
|
||||
match(&localContext);
|
||||
|
||||
// automatically rate limit runners that become slooow
|
||||
const int runtime = d->runtime.elapsed();
|
||||
bool slowed = speed() == SlowSpeed;
|
||||
@ -136,8 +140,7 @@ void AbstractRunner::performMatch( Plasma::SearchContext &globalContext )
|
||||
}
|
||||
|
||||
//If matches were not added, delete items on the heap
|
||||
if (localContext.moveMatchesTo(globalContext) &&
|
||||
slowed && runtime < fastEnoughTime) {
|
||||
if (slowed && runtime < fastEnoughTime) {
|
||||
++d->fastRuns;
|
||||
|
||||
if (d->fastRuns > 2) {
|
||||
@ -199,6 +202,18 @@ void AbstractRunner::setPriority(Priority priority)
|
||||
d->priority = priority;
|
||||
}
|
||||
|
||||
SearchContext::Types AbstractRunner::ignoredTypes() const
|
||||
{
|
||||
return d->blackListed;
|
||||
}
|
||||
|
||||
void AbstractRunner::setIgnoredTypes(SearchContext::Types types)
|
||||
{
|
||||
d->blackListed = types;
|
||||
}
|
||||
|
||||
|
||||
|
||||
KService::List AbstractRunner::serviceQuery(const QString &serviceType, const QString &constraint) const
|
||||
{
|
||||
QMutexLocker lock(&Private::bigLock);
|
||||
@ -232,6 +247,15 @@ QString AbstractRunner::name() const
|
||||
return d->runnerDescription.property("X-Plasma-RunnerName").toString();
|
||||
}
|
||||
|
||||
QString AbstractRunner::description() const
|
||||
{
|
||||
if (!d->runnerDescription.isValid()) {
|
||||
return objectName();
|
||||
}
|
||||
return d->runnerDescription.property("Comment").toString();
|
||||
}
|
||||
|
||||
|
||||
const Package* AbstractRunner::package() const
|
||||
{
|
||||
return d->package;
|
||||
@ -244,47 +268,6 @@ void AbstractRunner::init()
|
||||
}
|
||||
}
|
||||
|
||||
AbstractRunner::List AbstractRunner::loadAll(QObject* parent, const QStringList& whitelist)
|
||||
{
|
||||
List firstRunners;
|
||||
List runners;
|
||||
List lastRunners;
|
||||
|
||||
KService::List offers = KServiceTypeTrader::self()->query("Plasma/Runner");
|
||||
QString error;
|
||||
foreach (const KService::Ptr &service, offers) {
|
||||
if (whitelist.empty() || whitelist.contains(service->name())) {
|
||||
QString api = service->property("X-Plasma-API").toString();
|
||||
AbstractRunner* runner = 0;
|
||||
|
||||
if (api.isEmpty()) {
|
||||
QVariantList args;
|
||||
args << service->storageId();
|
||||
runner = service->createInstance<AbstractRunner>(parent, args, &error);
|
||||
} else {
|
||||
runner = new AbstractRunner(parent, service->storageId());
|
||||
}
|
||||
|
||||
if (runner) {
|
||||
//kDebug() << "loaded runner : " << service->name();
|
||||
QString phase = service->property("X-Plasma-RunnerPhase").toString();
|
||||
if (phase == "last") {
|
||||
lastRunners.append(runner);
|
||||
} else if (phase == "first") {
|
||||
firstRunners.append(runner);
|
||||
} else {
|
||||
runners.append(runner);
|
||||
}
|
||||
} else {
|
||||
kDebug() << "failed to load runner : " << service->name() << ". error reported: " << error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
firstRunners << runners << lastRunners;
|
||||
return firstRunners;
|
||||
}
|
||||
|
||||
} // Plasma namespace
|
||||
|
||||
#include "abstractrunner.moc"
|
||||
|
@ -28,9 +28,8 @@
|
||||
#include <KDE/KService>
|
||||
|
||||
#include <plasma/plasma_export.h>
|
||||
#include <plasma/package.h>
|
||||
#include <plasma/searchmatch.h>
|
||||
#include <plasma/searchcontext.h>
|
||||
#include <plasma/searchmatch.h>
|
||||
|
||||
class KCompletion;
|
||||
|
||||
@ -39,6 +38,7 @@ namespace Plasma
|
||||
|
||||
class Package;
|
||||
class RunnerScript;
|
||||
class SearchMatch;
|
||||
|
||||
/**
|
||||
* An abstract base class for Plasma Runner plugins
|
||||
@ -66,13 +66,6 @@ class PLASMA_EXPORT AbstractRunner : public QObject
|
||||
|
||||
typedef QList<AbstractRunner*> List;
|
||||
|
||||
/**
|
||||
* Static method is called to load and get a list available of Runners.
|
||||
*
|
||||
* @param whitelist An optional whitelist of runners to load
|
||||
*/
|
||||
static List loadAll(QObject* parent, const QStringList& whitelist = QStringList());
|
||||
|
||||
virtual ~AbstractRunner();
|
||||
|
||||
/**
|
||||
@ -153,11 +146,29 @@ class PLASMA_EXPORT AbstractRunner : public QObject
|
||||
*/
|
||||
Priority priority() const;
|
||||
|
||||
/**
|
||||
* Returns the OR'ed value of all the Information types (as defined in SearchContext::Type)
|
||||
* this runner is not interested in.
|
||||
* @return OR'ed value of black listed types
|
||||
*/
|
||||
SearchContext::Types ignoredTypes() const;
|
||||
|
||||
/**
|
||||
* Sets the types this runner will ignore
|
||||
* @param types OR'ed listed of ignored types
|
||||
*/
|
||||
void setIgnoredTypes(SearchContext::Types types);
|
||||
|
||||
/**
|
||||
* Returns the engine name for the Runner
|
||||
*/
|
||||
QString name() const;
|
||||
|
||||
/**
|
||||
* Returns the description of this Runner
|
||||
*/
|
||||
QString description() const;
|
||||
|
||||
/**
|
||||
* Accessor for the associated Package object if any.
|
||||
*
|
||||
|
431
runnermanager.cpp
Normal file
431
runnermanager.cpp
Normal file
@ -0,0 +1,431 @@
|
||||
/*
|
||||
* Copyright (C) 2006-2007 Ryan P. Bitanga <ryan.bitanga@gmail.com>
|
||||
* Copyright (C) 2006 Aaron Seigo <aseigo@kde.org>
|
||||
* Copyright 2008 Jordi Polo <mumismo@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Library General Public License as
|
||||
* published by the Free Software Foundation; either version 2, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <KServiceTypeTrader>
|
||||
#include <KPluginInfo>
|
||||
#include <KDebug>
|
||||
|
||||
#include <Solid/Device>
|
||||
#include <Solid/DeviceInterface>
|
||||
|
||||
#include <threadweaver/DebuggingAids.h>
|
||||
#include <ThreadWeaver/Thread>
|
||||
#include <ThreadWeaver/Job>
|
||||
#include <ThreadWeaver/State>
|
||||
#include <ThreadWeaver/QueuePolicy>
|
||||
#include <ThreadWeaver/Weaver>
|
||||
#include <ThreadWeaver/WeaverObserver>
|
||||
#include <QMutex>
|
||||
#include <QTimer>
|
||||
#include <QCoreApplication>
|
||||
|
||||
#include <Plasma/SearchMatch>
|
||||
|
||||
#include "runnermanager.h"
|
||||
|
||||
using ThreadWeaver::Weaver;
|
||||
using ThreadWeaver::Job;
|
||||
|
||||
|
||||
namespace Plasma
|
||||
{
|
||||
|
||||
|
||||
/*****************************************************
|
||||
* RunnerRestrictionPolicy class
|
||||
* Restricts simultaneous jobs of the same type
|
||||
* Similar to ResourceRestrictionPolicy but check the object type first
|
||||
******************************************************/
|
||||
class RunnerRestrictionPolicy : public ThreadWeaver::QueuePolicy
|
||||
{
|
||||
public:
|
||||
~RunnerRestrictionPolicy();
|
||||
|
||||
static RunnerRestrictionPolicy& instance();
|
||||
|
||||
void setCap(int cap)
|
||||
{
|
||||
m_cap = cap;
|
||||
}
|
||||
int cap() const
|
||||
{
|
||||
return m_cap;
|
||||
}
|
||||
|
||||
bool canRun(Job* job);
|
||||
void free(Job* job);
|
||||
void release(Job* job);
|
||||
void destructed(Job* job);
|
||||
private:
|
||||
RunnerRestrictionPolicy();
|
||||
|
||||
// QHash<QString, int> m_runCounts;
|
||||
int m_count;
|
||||
int m_cap;
|
||||
QMutex m_mutex;
|
||||
};
|
||||
|
||||
RunnerRestrictionPolicy::RunnerRestrictionPolicy()
|
||||
: QueuePolicy(),
|
||||
m_cap(2)
|
||||
{
|
||||
}
|
||||
|
||||
RunnerRestrictionPolicy::~RunnerRestrictionPolicy()
|
||||
{
|
||||
}
|
||||
|
||||
RunnerRestrictionPolicy& RunnerRestrictionPolicy::instance()
|
||||
{
|
||||
static RunnerRestrictionPolicy policy;
|
||||
return policy;
|
||||
}
|
||||
|
||||
bool RunnerRestrictionPolicy::canRun(Job* job)
|
||||
{
|
||||
Q_UNUSED(job)
|
||||
QMutexLocker l(&m_mutex);
|
||||
// QString type = job->objectName();
|
||||
if (m_count/*m_runCounts.value(type)*/ > m_cap) {
|
||||
// kDebug() << "Denying job " << type << " because of " << m_count/*m_runCounts[type]*/ << " current jobs" << endl;
|
||||
return false;
|
||||
} else {
|
||||
// m_runCounts[type]++;
|
||||
++m_count;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void RunnerRestrictionPolicy::free(Job* job)
|
||||
{
|
||||
Q_UNUSED(job)
|
||||
QMutexLocker l(&m_mutex);
|
||||
// QString type = job->objectName();
|
||||
--m_count;
|
||||
// if (m_runCounts.value(type)) {
|
||||
// m_runCounts[type]--;
|
||||
// }
|
||||
}
|
||||
|
||||
void RunnerRestrictionPolicy::release(Job* job)
|
||||
{
|
||||
free(job);
|
||||
}
|
||||
|
||||
void RunnerRestrictionPolicy::destructed(Job* job)
|
||||
{
|
||||
Q_UNUSED(job)
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
* FindMatchesJob class
|
||||
* Class to run queries in different threads
|
||||
******************************************************/
|
||||
class FindMatchesJob : public Job
|
||||
{
|
||||
public:
|
||||
FindMatchesJob(const QString& term, Plasma::AbstractRunner* runner, Plasma::SearchContext* context, QObject* parent = 0);
|
||||
|
||||
int priority() const;
|
||||
|
||||
protected:
|
||||
void run();
|
||||
private:
|
||||
QString m_term;
|
||||
Plasma::SearchContext* m_context;
|
||||
Plasma::AbstractRunner* m_runner;
|
||||
};
|
||||
|
||||
FindMatchesJob::FindMatchesJob( const QString& term, Plasma::AbstractRunner* runner,
|
||||
Plasma::SearchContext* context, QObject* parent )
|
||||
: ThreadWeaver::Job(parent),
|
||||
m_term(term),
|
||||
m_context(context),
|
||||
m_runner(runner)
|
||||
{
|
||||
// setObjectName( runner->objectName() );
|
||||
if (runner->speed() == Plasma::AbstractRunner::SlowSpeed) {
|
||||
assignQueuePolicy(&RunnerRestrictionPolicy::instance());
|
||||
}
|
||||
}
|
||||
|
||||
void FindMatchesJob::run()
|
||||
{
|
||||
// kDebug() << "Running match for " << m_runner->objectName() << " in Thread " << thread()->id() << endl;
|
||||
m_runner->performMatch(*m_context);
|
||||
}
|
||||
|
||||
int FindMatchesJob::priority() const
|
||||
{
|
||||
return m_runner->priority();
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
* RunnerManager::Private class
|
||||
*
|
||||
*****************************************************/
|
||||
class RunnerManager::Private
|
||||
{
|
||||
public:
|
||||
|
||||
Private(RunnerManager *parent)
|
||||
: q(parent)
|
||||
{
|
||||
connect(&context, SIGNAL(matchesChanged()), q, SIGNAL(matchesChanged()));
|
||||
connect(Weaver::instance(), SIGNAL(finished()), q, SIGNAL(matchesCompleted()));
|
||||
}
|
||||
|
||||
void configure(KConfigGroup& conf)
|
||||
{
|
||||
config=conf;
|
||||
|
||||
//The number of threads used scales with the number of processors.
|
||||
const int numProcs = qMax(Solid::Device::listFromType(Solid::DeviceInterface::Processor).count(), 1);
|
||||
//This entry allows to define a hard upper limit independent of the number of processors.
|
||||
const int maxThreads = config.readEntry("maxThreads",16);
|
||||
const int numThreads = qMin(maxThreads, 2 + ((numProcs - 1) * 2));
|
||||
// kDebug() << "setting up" << numThreads << "threads for" << numProcs << "processors";
|
||||
Weaver::instance()->setMaximumNumberOfThreads(numThreads);
|
||||
|
||||
//Preferred order of execution of runners
|
||||
//prioritylist = config.readEntry("priority", QStringList());
|
||||
|
||||
//If set, this list defines which runners won't be used at runtime
|
||||
blacklist = config.readEntry("blacklist", QStringList());
|
||||
|
||||
}
|
||||
|
||||
void loadAll()
|
||||
{
|
||||
AbstractRunner::List firstRunners;
|
||||
AbstractRunner::List normalRunners;
|
||||
AbstractRunner::List lastRunners;
|
||||
|
||||
KService::List offers = KServiceTypeTrader::self()->query("Plasma/Runner");
|
||||
QString error;
|
||||
foreach (const KService::Ptr &service, offers) {
|
||||
KPluginInfo description(service);
|
||||
QString runnerName = description.property("X-Plasma-RunnerName").toString();
|
||||
if (blacklist.contains(runnerName)) {
|
||||
kDebug() << "The plugin" << service->name() << "was blackListed and will not load";
|
||||
continue;
|
||||
}
|
||||
QString api = service->property("X-Plasma-API").toString();
|
||||
AbstractRunner* runner = 0;
|
||||
|
||||
if (api.isEmpty()) {
|
||||
QVariantList args;
|
||||
args << service->storageId();
|
||||
runner = service->createInstance<AbstractRunner>(q, args, &error);
|
||||
} else {
|
||||
//FIXME: this line should be uncommented, but the constructor is protected
|
||||
//runner = new AbstractRunner(q, service->storageId());
|
||||
}
|
||||
|
||||
if (runner) {
|
||||
// kDebug() << "loading runner: " << service->name();
|
||||
QString phase = service->property("X-Plasma-RunnerPhase").toString();
|
||||
if (phase == "last") {
|
||||
lastRunners.append(runner);
|
||||
} else if (phase == "first") {
|
||||
firstRunners.append(runner);
|
||||
} else {
|
||||
normalRunners.append(runner);
|
||||
}
|
||||
} else {
|
||||
kDebug() << "failed to load runner : " << service->name() << ". error reported: " << error;
|
||||
}
|
||||
}
|
||||
|
||||
firstRunners << normalRunners << lastRunners;
|
||||
runners.clear();
|
||||
runners = firstRunners;
|
||||
kDebug() << "All runners loaded, total:" << runners.count();
|
||||
}
|
||||
|
||||
RunnerManager *q;
|
||||
SearchContext context;
|
||||
AbstractRunner::List runners;
|
||||
QList<SearchMatch *> matches;
|
||||
QList<ThreadWeaver::Job*> searchJobs;
|
||||
QStringList prioritylist;
|
||||
QStringList blacklist;
|
||||
KConfigGroup config;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*****************************************************
|
||||
* RunnerManager::Public class
|
||||
*
|
||||
*****************************************************/
|
||||
RunnerManager::RunnerManager(QObject *parent)
|
||||
: QObject(parent),
|
||||
d(new Private(this))
|
||||
{
|
||||
KConfigGroup config(KGlobal::config(), "PlasmaRunnerManager");
|
||||
d->configure(config);
|
||||
d->loadAll();
|
||||
//ThreadWeaver::setDebugLevel(true, 4);
|
||||
|
||||
}
|
||||
|
||||
|
||||
RunnerManager::RunnerManager(KConfigGroup& config, QObject *parent)
|
||||
: QObject(parent),
|
||||
d(new Private(this))
|
||||
{
|
||||
d->configure(config);
|
||||
d->loadAll();
|
||||
//ThreadWeaver::setDebugLevel(true, 4);
|
||||
}
|
||||
|
||||
|
||||
RunnerManager::~RunnerManager()
|
||||
{
|
||||
d->context.removeAllMatches();
|
||||
}
|
||||
|
||||
|
||||
AbstractRunner* RunnerManager::runner(const QString &name) const
|
||||
{
|
||||
//TODO: using a list of runners, if this gets slow, switch to hash
|
||||
foreach (Plasma::AbstractRunner* runner, d->runners) {
|
||||
if (name == runner->name()) {
|
||||
return runner;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
SearchContext* RunnerManager::searchContext() const
|
||||
{
|
||||
return &d->context;
|
||||
}
|
||||
|
||||
//Reordering is here so data is not reordered till strictly needed
|
||||
QList<SearchMatch *> RunnerManager::matches() const
|
||||
{
|
||||
return d->context.matches();
|
||||
}
|
||||
|
||||
void RunnerManager::run(const SearchMatch *match)
|
||||
{
|
||||
//TODO: this function is not const as it may be used for learning
|
||||
match->run(&d->context);
|
||||
}
|
||||
|
||||
|
||||
void RunnerManager::launchQuery (const QString & term, const QString & runnerName)
|
||||
{
|
||||
if (term.isEmpty()) {
|
||||
reset();
|
||||
return;
|
||||
}
|
||||
|
||||
if (d->context.searchTerm() == term) {
|
||||
// we already are searching for this!
|
||||
return;
|
||||
}
|
||||
|
||||
reset();
|
||||
// kDebug() << "runners searching for" << term << "on" << runnerName;
|
||||
d->context.setSearchTerm(term);
|
||||
|
||||
AbstractRunner::List runable;
|
||||
|
||||
//if the name is not empty we will launch only the specified runner
|
||||
if (!runnerName.isEmpty()) {
|
||||
runable.append(runner(runnerName));
|
||||
} else {
|
||||
runable = d->runners;
|
||||
}
|
||||
bool jobsLaunched=false;
|
||||
foreach (Plasma::AbstractRunner* r, runable) {
|
||||
if ((r->ignoredTypes() & d->context.type()) == 0) {
|
||||
// kDebug() << "launching" << r->name();
|
||||
jobsLaunched=true;
|
||||
Job *job = new FindMatchesJob(term, r, &d->context, this);
|
||||
Weaver::instance()->enqueue( job );
|
||||
d->searchJobs.append( job );
|
||||
}
|
||||
}
|
||||
if (!jobsLaunched) {
|
||||
emit matchesCompleted();
|
||||
}
|
||||
}
|
||||
|
||||
bool RunnerManager::execQuery (const QString & term, const QString & runnerName)
|
||||
{
|
||||
if (term.isEmpty()) {
|
||||
reset();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (d->context.searchTerm() == term) {
|
||||
// we already are searching for this!
|
||||
return 0;
|
||||
}
|
||||
|
||||
reset();
|
||||
// kDebug() << "executing query about " << term << "on" << runnerName;
|
||||
d->context.setSearchTerm(term);
|
||||
|
||||
AbstractRunner *r = runner(runnerName);
|
||||
|
||||
if (!r) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((r->ignoredTypes() & d->context.type()) != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
r->performMatch(d->context);
|
||||
emit matchesCompleted();
|
||||
return 1;
|
||||
}
|
||||
|
||||
void RunnerManager::reset()
|
||||
{
|
||||
// If ThreadWeaver is idle, it is safe to clear previous jobs
|
||||
if ( Weaver::instance()->isIdle() ) {
|
||||
qDeleteAll( d->searchJobs );
|
||||
d->searchJobs.clear();
|
||||
}
|
||||
else {
|
||||
Weaver::instance()->dequeue();
|
||||
}
|
||||
d->context.reset();
|
||||
|
||||
//FIXME: if the weaver is not idle we have a number of jobs that
|
||||
// will eventually return their matches
|
||||
// we need a way to stop them (Weaver::requestAbort() Job::requestAbort )
|
||||
// or discard results
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#include "runnermanager.moc"
|
124
runnermanager.h
Normal file
124
runnermanager.h
Normal file
@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright (C) 2006-2007 Ryan P. Bitanga <ryan.bitanga@gmail.com>
|
||||
* Copyright (C) 2006 Aaron Seigo <aseigo@kde.org>
|
||||
* Copyright 2008 Jordi Polo <mumismo@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Library General Public License as
|
||||
* published by the Free Software Foundation; either version 2, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef RUNNERMANAGER_H
|
||||
#define RUNNERMANAGER_H
|
||||
|
||||
#include <QtCore/QList>
|
||||
#include <QtCore/QObject>
|
||||
|
||||
#include <plasma/plasma_export.h>
|
||||
#include "abstractrunner.h"
|
||||
|
||||
namespace Plasma
|
||||
{
|
||||
class SearchMatch;
|
||||
class AbstractRunner;
|
||||
class SearchContext;
|
||||
|
||||
/**
|
||||
* @short The RunnerManager class decides what installed runners are runnable,
|
||||
* and their ratings. It is the main proxy to the runners.
|
||||
*/
|
||||
class PLASMA_EXPORT RunnerManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
||||
public:
|
||||
|
||||
explicit RunnerManager(QObject *parent=0);
|
||||
explicit RunnerManager(KConfigGroup& config, QObject *parent=0);
|
||||
~RunnerManager();
|
||||
|
||||
/**
|
||||
* Finds and returns a loaded runner or NULL
|
||||
* @arg name the name of the runner
|
||||
* @return Pointer to the runner
|
||||
*/
|
||||
AbstractRunner* runner(const QString &name) const;
|
||||
|
||||
/**
|
||||
* Retrieves the current context
|
||||
* @return pointer to the current context
|
||||
*/
|
||||
SearchContext* searchContext() const;
|
||||
|
||||
/**
|
||||
* Retrieves all available matches found so far for the previously launched query
|
||||
* @return List of matches
|
||||
*/
|
||||
QList<SearchMatch *> matches() const;
|
||||
|
||||
/**
|
||||
* Runs a given match
|
||||
* @arg pointer to the match to be executed
|
||||
*/
|
||||
void run(const SearchMatch *match);
|
||||
|
||||
public Q_SLOTS:
|
||||
|
||||
/**
|
||||
* Launch a query, this will create threads and return inmediately.
|
||||
* When the information will be available can be known using the
|
||||
* matchesChanged, matchesUpdated, matchesCompleted signals
|
||||
* The information can be retrieved calling matches
|
||||
* @arg term the term we want to find matches for
|
||||
* @arg runner optional, if only one specific runner is to be used
|
||||
*/
|
||||
void launchQuery(const QString &term, const QString & runnerName=QString());
|
||||
|
||||
/**
|
||||
* Execute a query, this method will only return when the query is executed
|
||||
* This means that the method may be dangerous as it wait a variable amount
|
||||
* of time for the runner to finish.
|
||||
* The runner parameter is mandatory, to avoid launching unwanted runners.
|
||||
* @arg term the term we want to find matches for
|
||||
* @arg runner the runner we will use, it is mandatory
|
||||
* @return 0 if nothing was launched, 1 if launched.
|
||||
*/
|
||||
bool execQuery(const QString &term, const QString & runnerName);
|
||||
|
||||
/**
|
||||
* Reset the current data and stops the query
|
||||
*/
|
||||
void reset();
|
||||
|
||||
Q_SIGNALS:
|
||||
|
||||
/**
|
||||
* Emited each time a new match is added to the list
|
||||
*/
|
||||
void matchesChanged();
|
||||
|
||||
/**
|
||||
* Emited when all the matches have been found
|
||||
*/
|
||||
void matchesCompleted();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
Private * const d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -23,6 +23,7 @@
|
||||
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QSharedData>
|
||||
|
||||
#include <KCompletion>
|
||||
#include <KDebug>
|
||||
@ -36,34 +37,31 @@
|
||||
namespace Plasma
|
||||
{
|
||||
|
||||
class SearchContext::Private
|
||||
class SearchContext::Private : public QSharedData
|
||||
{
|
||||
public:
|
||||
Private(SearchContext::DataPolicy p)
|
||||
Private(SearchContext *context, SearchContext::DataPolicy p)
|
||||
: type(SearchContext::UnknownType),
|
||||
completer(0),
|
||||
q(context),
|
||||
policy(p)
|
||||
{
|
||||
}
|
||||
|
||||
Private(const SearchContext::Private& p)
|
||||
: term(p.term),
|
||||
mimeType(p.mimeType),
|
||||
type(p.type),
|
||||
q(p.q),
|
||||
policy(p.policy)
|
||||
{
|
||||
}
|
||||
|
||||
~Private()
|
||||
{
|
||||
lockForWrite();
|
||||
qDeleteAll(matches);
|
||||
matches.clear();
|
||||
delete completer;
|
||||
}
|
||||
|
||||
void resetState()
|
||||
{
|
||||
}
|
||||
|
||||
KCompletion* completionObject()
|
||||
{
|
||||
if (!completer) {
|
||||
completer = new KCompletion;
|
||||
}
|
||||
|
||||
return completer;
|
||||
unlock();
|
||||
}
|
||||
|
||||
void lockForRead()
|
||||
@ -87,61 +85,90 @@ class SearchContext::Private
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines type of query
|
||||
*/
|
||||
void determineType()
|
||||
{
|
||||
lockForWrite();
|
||||
QString path = KShell::tildeExpand(term);
|
||||
|
||||
int space = term.indexOf(' ');
|
||||
if (space > 0) {
|
||||
if (!KStandardDirs::findExe(path.left(space)).isEmpty()) {
|
||||
type = ShellCommand;
|
||||
}
|
||||
} else if (!KStandardDirs::findExe(path.left(space)).isEmpty()) {
|
||||
type = Executable;
|
||||
} else {
|
||||
KUrl url(term);
|
||||
if (!url.protocol().isEmpty() && !url.host().isEmpty()) {
|
||||
type = NetworkLocation;
|
||||
} else if (QFile::exists(path)) {
|
||||
QFileInfo info(path);
|
||||
if (info.isDir()) {
|
||||
type = Directory;
|
||||
mimeType = "inode/folder";
|
||||
} else {
|
||||
type = File;
|
||||
KMimeType::Ptr mimeTypePtr = KMimeType::findByPath(path);
|
||||
if (mimeTypePtr) {
|
||||
mimeType = mimeTypePtr->name();
|
||||
}
|
||||
}
|
||||
} else if (term.contains('.')) {
|
||||
// default to a network location so we can can do things like www.kde.org
|
||||
type = NetworkLocation;
|
||||
}
|
||||
}
|
||||
unlock();
|
||||
}
|
||||
|
||||
QReadWriteLock lock;
|
||||
QList<SearchMatch *> matches;
|
||||
QList<SearchMatch*> matches;
|
||||
QString term;
|
||||
QString mimeType;
|
||||
SearchContext::Type type;
|
||||
KCompletion *completer;
|
||||
SearchContext * q;
|
||||
const SearchContext::DataPolicy policy;
|
||||
};
|
||||
|
||||
|
||||
SearchContext::SearchContext(QObject *parent, DataPolicy policy)
|
||||
: QObject(parent),
|
||||
d(new Private(policy))
|
||||
d(new Private(this, policy))
|
||||
{
|
||||
}
|
||||
|
||||
SearchContext::SearchContext(QObject *parent, const SearchContext &other)
|
||||
: QObject(parent),
|
||||
d(new Private(SingleConsumer))
|
||||
//copy ctor
|
||||
SearchContext::SearchContext(SearchContext &other, QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
other.d->lockForRead();
|
||||
d->term = other.d->term;
|
||||
d->mimeType = other.d->mimeType;
|
||||
d->type = other.d->type;
|
||||
d=other.d;
|
||||
other.d->unlock();
|
||||
}
|
||||
|
||||
SearchContext::~SearchContext()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
void SearchContext::reset()
|
||||
{
|
||||
d->lockForWrite();
|
||||
QList<SearchMatch*> matches = d->matches;
|
||||
// Locks are needed as other contexts can be copied of this one
|
||||
|
||||
d->matches.clear();
|
||||
// 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 SearchContext makes all the copies oneobsolete.
|
||||
d.detach();
|
||||
|
||||
//kDebug() << "reset searchContext";
|
||||
d->lockForWrite();
|
||||
d->type = SearchContext::UnknownType;
|
||||
d->term.clear();
|
||||
d->mimeType.clear();
|
||||
|
||||
if (d->completer) {
|
||||
d->completer->clear();
|
||||
}
|
||||
|
||||
d->unlock();
|
||||
|
||||
emit matchesChanged();
|
||||
|
||||
// in case someone is still holding on to the Matches
|
||||
// when we emit the matchesChanged() signal, we don't
|
||||
// delete the matches until after the signal is handled.
|
||||
// a bit safer.
|
||||
qDeleteAll(matches);
|
||||
removeAllMatches();
|
||||
}
|
||||
|
||||
void SearchContext::setSearchTerm(const QString &term)
|
||||
@ -153,46 +180,9 @@ void SearchContext::setSearchTerm(const QString &term)
|
||||
d->lockForWrite();
|
||||
d->term = term;
|
||||
d->unlock();
|
||||
determineType();
|
||||
d->determineType();
|
||||
}
|
||||
|
||||
void SearchContext::determineType()
|
||||
{
|
||||
d->lockForWrite();
|
||||
QString term = d->term;
|
||||
QString path = KShell::tildeExpand(term);
|
||||
|
||||
int space = term.indexOf(' ');
|
||||
if (space > 0) {
|
||||
if (!KStandardDirs::findExe(path.left(space)).isEmpty()) {
|
||||
d->type = ShellCommand;
|
||||
}
|
||||
} else if (!KStandardDirs::findExe(path.left(space)).isEmpty()) {
|
||||
d->type = Executable;
|
||||
} else {
|
||||
KUrl url(term);
|
||||
|
||||
if (!url.protocol().isEmpty() && !url.host().isEmpty()) {
|
||||
d->type = NetworkLocation;
|
||||
} else if (QFile::exists(path)) {
|
||||
QFileInfo info(path);
|
||||
if (info.isDir()) {
|
||||
d->type = Directory;
|
||||
d->mimeType = "inode/folder";
|
||||
} else {
|
||||
d->type = File;
|
||||
KMimeType::Ptr mimeType = KMimeType::findByPath(path);
|
||||
if (mimeType) {
|
||||
d->mimeType = mimeType->name();
|
||||
}
|
||||
}
|
||||
} else if (term.contains('.')) {
|
||||
// default to a network location so we can can do things like www.kde.org
|
||||
d->type = NetworkLocation;
|
||||
}
|
||||
}
|
||||
d->unlock();
|
||||
}
|
||||
|
||||
QString SearchContext::searchTerm() const
|
||||
{
|
||||
@ -212,40 +202,6 @@ QString SearchContext::mimeType() const
|
||||
return d->mimeType;
|
||||
}
|
||||
|
||||
KCompletion* SearchContext::completionObject() const
|
||||
{
|
||||
d->lockForRead();
|
||||
KCompletion* comp = d->completionObject();
|
||||
d->unlock();
|
||||
return comp;
|
||||
}
|
||||
|
||||
void SearchContext::addStringCompletion(const QString &completion)
|
||||
{
|
||||
d->lockForWrite();
|
||||
if (!d->completer) {
|
||||
d->unlock();
|
||||
// if the completion object isn't actually used, don't bother
|
||||
return;
|
||||
}
|
||||
|
||||
d->completer->addItem(completion);
|
||||
d->unlock();
|
||||
}
|
||||
|
||||
void SearchContext::addStringCompletions(const QStringList &completion)
|
||||
{
|
||||
d->lockForWrite();
|
||||
if (!d->completer) {
|
||||
d->unlock();
|
||||
// if the completion object isn't actually used, don't bother
|
||||
return;
|
||||
}
|
||||
|
||||
d->completer->insertItems(completion);
|
||||
d->unlock();
|
||||
}
|
||||
|
||||
bool SearchContext::addMatches(const QString& term, const QList<SearchMatch*> &matches)
|
||||
{
|
||||
if (searchTerm() != term || matches.isEmpty()) {
|
||||
@ -255,12 +211,11 @@ bool SearchContext::addMatches(const QString& term, const QList<SearchMatch*> &m
|
||||
d->lockForWrite();
|
||||
d->matches << matches;
|
||||
d->unlock();
|
||||
|
||||
// TODO: perhaps queue this signal so that it is only emitted after a small delay?
|
||||
// currently we do this in krunner's Interface class, but it would probably
|
||||
// be better to move that detail to SearchContext so that other apps that
|
||||
// use SearchContext can also benefit from it
|
||||
emit matchesChanged();
|
||||
//kDebug()<< "add matches";
|
||||
// A copied searchContext may share the d pointer,
|
||||
// we always want to sent the signal of the object that created
|
||||
// the d pointer
|
||||
emit d->q->matchesChanged();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -273,30 +228,12 @@ bool SearchContext::addMatch(const QString &term, SearchMatch *match)
|
||||
d->lockForWrite();
|
||||
d->matches << match;
|
||||
d->unlock();
|
||||
emit matchesChanged();
|
||||
//kDebug()<< "added match" << match->text();
|
||||
emit d->q->matchesChanged();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SearchContext::moveMatchesTo(SearchContext &other)
|
||||
{
|
||||
//NOTE: we have moveMatchesTo instead of the more 'natural' addMatches
|
||||
// because we can get away with one write lock on the local object
|
||||
// this way, otherwise we'd need to lock once for searchTerm, once
|
||||
// for matches() and again for removeAllMatches() (2 read, one write)
|
||||
d->lockForWrite();
|
||||
|
||||
const bool success = other.addMatches(d->term, d->matches);
|
||||
|
||||
if (success) {
|
||||
// the matches no longer belong to this SearchContext,
|
||||
// so remove them from the data
|
||||
d->matches.clear();
|
||||
}
|
||||
|
||||
d->unlock();
|
||||
return success;
|
||||
}
|
||||
|
||||
QList<SearchMatch *> SearchContext::matches() const
|
||||
{
|
||||
@ -309,18 +246,19 @@ QList<SearchMatch *> SearchContext::matches() const
|
||||
void SearchContext::removeAllMatches()
|
||||
{
|
||||
d->lockForWrite();
|
||||
|
||||
QList<SearchMatch*> matches = d->matches;
|
||||
bool emptyMatches = d->matches.isEmpty();
|
||||
if (!emptyMatches) {
|
||||
d->matches.clear();
|
||||
d->unlock();
|
||||
|
||||
emit matchesChanged();
|
||||
|
||||
emit d->q->matchesChanged();
|
||||
// in case someone is still holding on to the Matches
|
||||
// when we emit the matchesChanged() signal, we don't
|
||||
// delete the matches until after the signal is handled.
|
||||
// a bit safer.
|
||||
qDeleteAll(matches);
|
||||
d->lockForWrite();
|
||||
qDeleteAll(d->matches);
|
||||
}
|
||||
d->unlock();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -22,6 +22,8 @@
|
||||
|
||||
#include <QtCore/QList>
|
||||
#include <QtCore/QObject>
|
||||
#include <QSharedDataPointer>
|
||||
#include <QFlags>
|
||||
|
||||
#include <plasma/plasma_export.h>
|
||||
|
||||
@ -43,15 +45,18 @@ class PLASMA_EXPORT SearchContext : public QObject
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum Type { UnknownType = 0,
|
||||
Directory,
|
||||
File,
|
||||
NetworkLocation,
|
||||
Executable,
|
||||
ShellCommand,
|
||||
Help
|
||||
enum Type { None = 0,
|
||||
UnknownType = 1,
|
||||
Directory = 2,
|
||||
File = 4,
|
||||
NetworkLocation = 8,
|
||||
Executable = 16,
|
||||
ShellCommand = 32,
|
||||
Help = 64
|
||||
};
|
||||
|
||||
Q_DECLARE_FLAGS(Types, Type)
|
||||
|
||||
enum DataPolicy { Shared = 0,
|
||||
SingleConsumer
|
||||
};
|
||||
@ -64,7 +69,8 @@ class PLASMA_EXPORT SearchContext : public QObject
|
||||
* matches) from the passed in SearchContext. Primarily useful for creating
|
||||
* a thread-local copy of a Shared SearchContext.
|
||||
*/
|
||||
SearchContext(QObject *parent, const SearchContext& other);
|
||||
explicit SearchContext(SearchContext& other, QObject *parent = 0);
|
||||
|
||||
~SearchContext();
|
||||
|
||||
|
||||
@ -100,21 +106,6 @@ class PLASMA_EXPORT SearchContext : public QObject
|
||||
*/
|
||||
QString mimeType() const;
|
||||
|
||||
/**
|
||||
* @return a completion object that can be used with UI elements
|
||||
*/
|
||||
KCompletion* completionObject() const;
|
||||
|
||||
/**
|
||||
* Adds an item to the completion object.
|
||||
*/
|
||||
void addStringCompletion(const QString& completion);
|
||||
|
||||
/**
|
||||
* Adds multiple items to the completion object.
|
||||
*/
|
||||
void addStringCompletions(const QStringList& completions);
|
||||
|
||||
/**
|
||||
* Appends lists of matches to the list of matches.
|
||||
* The SearchContext takes over ownership of the matches on successful addition.
|
||||
@ -154,11 +145,6 @@ class PLASMA_EXPORT SearchContext : public QObject
|
||||
*/
|
||||
QList<SearchMatch *> matches() const;
|
||||
|
||||
/**
|
||||
* Determines type of query
|
||||
*/
|
||||
void determineType();
|
||||
|
||||
/**
|
||||
* Removes all matches from this SearchContext.
|
||||
*/
|
||||
@ -169,9 +155,11 @@ class PLASMA_EXPORT SearchContext : public QObject
|
||||
|
||||
private:
|
||||
class Private;
|
||||
Private * const d;
|
||||
QExplicitlySharedDataPointer<Private> d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS (Plasma::SearchContext::Types)
|
||||
|
||||
#endif
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
#include "searchmatch.h"
|
||||
|
||||
#include <QPointer>
|
||||
#include <QVariant>
|
||||
#include <QStringList>
|
||||
#include <QIcon>
|
||||
@ -41,7 +42,7 @@ class SearchMatch::Private
|
||||
{
|
||||
}
|
||||
|
||||
AbstractRunner *runner;
|
||||
QPointer<AbstractRunner> runner;
|
||||
SearchMatch::Type type;
|
||||
QString text;
|
||||
QString subtext;
|
||||
@ -55,6 +56,7 @@ class SearchMatch::Private
|
||||
SearchMatch::SearchMatch(AbstractRunner *runner)
|
||||
: d(new Private(runner))
|
||||
{
|
||||
// kDebug() << "new match created";
|
||||
}
|
||||
|
||||
SearchMatch::~SearchMatch()
|
||||
@ -146,7 +148,7 @@ void SearchMatch::run(const SearchContext *context) const
|
||||
{
|
||||
Q_ASSERT(context);
|
||||
|
||||
//kDebug() << "we have" << context->searchTerm() << context->mimetype();
|
||||
//kDebug() << "we run the term" << context->searchTerm() << "whose type is" << context->mimetype();
|
||||
if (d->runner) {
|
||||
//TODO: this could be dangerous if the runner is deleted behind our backs.
|
||||
d->runner->run(context, this);
|
||||
|
@ -38,7 +38,8 @@ class PLASMA_EXPORT SearchMatch
|
||||
/**
|
||||
* The type of match. Value is important here as it is used for sorting
|
||||
*/
|
||||
enum Type { PossibleMatch = 0 /**< Something that may match the query */,
|
||||
enum Type { CompletionMatch = 10 /**< Possible completion for the data of the query */,
|
||||
PossibleMatch = 30 /**< Something that may match the query */,
|
||||
InformationalMatch = 50 /**< A purely informational, non-actionable match,
|
||||
such as the answer to a question or calculation*/,
|
||||
HelperMatch = 70 /**< A match that represents an action not directly related
|
||||
@ -51,6 +52,7 @@ class PLASMA_EXPORT SearchMatch
|
||||
an action to be triggered. */,
|
||||
ExactMatch = 100 /**< An exact match to the query */};
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a PossibleMatch associated with a given SearchContext
|
||||
* and runner.
|
||||
|
Loading…
Reference in New Issue
Block a user