massive change to AbstractRunner API, but now at least it is hopefully future proof and we won't have to change it in BIC ways after 4.0
introduces two new classes: Plasma::SearchContext and Plasma::SearchAction benefits include: - well, future proofing =) - the ability to eventually allow runners that mutate the search - multiple exact matches per runner - 'executing' of informational runners (useful for, e.g., the calculator) - being able to centralize expensive operations such a KUriFilter actions - simplifies writing runners *dramatically* svn path=/trunk/KDE/kdebase/workspace/libs/plasma/; revision=731253
This commit is contained in:
parent
14ce8b1669
commit
e099821b71
@ -19,34 +19,249 @@
|
||||
|
||||
#include "abstractrunner.h"
|
||||
|
||||
#include <QAction>
|
||||
#include <KActionCollection>
|
||||
#include <KServiceTypeTrader>
|
||||
#include <KDebug>
|
||||
#include <KMimeType>
|
||||
#include <KServiceTypeTrader>
|
||||
#include <KUriFilterData>
|
||||
|
||||
|
||||
namespace Plasma
|
||||
{
|
||||
|
||||
class SearchContext::Private
|
||||
{
|
||||
public:
|
||||
Private()
|
||||
: type(SearchContext::UnknownType)
|
||||
{
|
||||
}
|
||||
|
||||
void resetState()
|
||||
{
|
||||
qDeleteAll(info);
|
||||
info.clear();
|
||||
qDeleteAll(exact);
|
||||
exact.clear();
|
||||
qDeleteAll(possible);
|
||||
possible.clear();
|
||||
type = SearchContext::UnknownType;
|
||||
term.clear();
|
||||
mimetype.clear();
|
||||
}
|
||||
|
||||
QList<SearchAction *> info;
|
||||
QList<SearchAction *> exact;
|
||||
QList<SearchAction *> possible;
|
||||
QString term;
|
||||
QString mimetype;
|
||||
SearchContext::Type type;
|
||||
};
|
||||
|
||||
class SearchAction::Private
|
||||
{
|
||||
public:
|
||||
Private(SearchContext* s, AbstractRunner *r)
|
||||
: search(s),
|
||||
runner(r),
|
||||
type(SearchAction::ExactMatch),
|
||||
relevance(1)
|
||||
{
|
||||
}
|
||||
|
||||
SearchContext *search;
|
||||
AbstractRunner *runner;
|
||||
SearchAction::Type type;
|
||||
QString mimetype;
|
||||
qreal relevance;
|
||||
};
|
||||
|
||||
class AbstractRunner::Private
|
||||
{
|
||||
public:
|
||||
Private( AbstractRunner* runner ) :
|
||||
exactMatch( 0 ),
|
||||
actions( new KActionCollection( runner ) )
|
||||
{
|
||||
delete exactMatch;
|
||||
actions->clear();
|
||||
}
|
||||
|
||||
QAction* exactMatch;
|
||||
KActionCollection* actions;
|
||||
// FIXME: it's a bit lame to keep a copy of the term in each runner
|
||||
QString term;
|
||||
bool hasMatchOptions;
|
||||
bool hasConfig;
|
||||
};
|
||||
|
||||
AbstractRunner::AbstractRunner( QObject* parent )
|
||||
: QObject( parent ),
|
||||
d( new Private( this ) )
|
||||
SearchContext::SearchContext(QObject *parent)
|
||||
: QObject(parent),
|
||||
d(new Private)
|
||||
{
|
||||
}
|
||||
|
||||
SearchContext::~SearchContext()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
void SearchContext::setTerm(const QString &term)
|
||||
{
|
||||
d->resetState();
|
||||
|
||||
if (term.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
d->term = term;
|
||||
//FIXME: this is insanely slow =/
|
||||
KUriFilterData filter(term);
|
||||
bool filtered = KUriFilter::self()->filterUri(filter);
|
||||
|
||||
if (filtered) {
|
||||
switch (filter.uriType()) {
|
||||
case KUriFilterData::LocalDir:
|
||||
d->type = Directory;
|
||||
d->mimetype = "inode/folder";
|
||||
break;
|
||||
case KUriFilterData::LocalFile: {
|
||||
d->type = File;
|
||||
KMimeType::Ptr mimetype = KMimeType::findByPath(filter.uri().path());
|
||||
if (mimetype) {
|
||||
d->mimetype = mimetype->name();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case KUriFilterData::NetProtocol:
|
||||
kDebug() << "term is a network protocol?" << term << filter.uriType();
|
||||
d->type = NetworkLocation;
|
||||
break;
|
||||
case KUriFilterData::Executable:
|
||||
d->type = Executable;
|
||||
break;
|
||||
case KUriFilterData::Shell:
|
||||
d->type = ShellCommand;
|
||||
break;
|
||||
case KUriFilterData::Help:
|
||||
d->type = Help;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString SearchContext::term() const
|
||||
{
|
||||
return d->term;
|
||||
}
|
||||
|
||||
SearchContext::Type SearchContext::type() const
|
||||
{
|
||||
return d->type;
|
||||
}
|
||||
|
||||
QString SearchContext::mimetype() const
|
||||
{
|
||||
return d->mimetype;
|
||||
}
|
||||
|
||||
SearchAction* SearchContext::addInformationalMatch(AbstractRunner *runner)
|
||||
{
|
||||
SearchAction *action = new SearchAction(this, runner);
|
||||
action->setType(SearchAction::InformationalMatch);
|
||||
d->info.append(action);
|
||||
return action;
|
||||
}
|
||||
|
||||
SearchAction* SearchContext::addExactMatch(AbstractRunner *runner)
|
||||
{
|
||||
SearchAction *action = new SearchAction(this, runner);
|
||||
action->setType(SearchAction::ExactMatch);
|
||||
d->exact.append(action);
|
||||
return action;
|
||||
}
|
||||
|
||||
SearchAction* SearchContext::addPossibleMatch(AbstractRunner *runner)
|
||||
{
|
||||
SearchAction *action = new SearchAction(this, runner);
|
||||
action->setType(SearchAction::PossibleMatch);
|
||||
d->possible.append(action);
|
||||
return action;
|
||||
}
|
||||
|
||||
QList<SearchAction *> SearchContext::informationalMatches() const
|
||||
{
|
||||
return d->info;
|
||||
}
|
||||
|
||||
QList<SearchAction *> SearchContext::exactMatches() const
|
||||
{
|
||||
return d->exact;
|
||||
}
|
||||
|
||||
QList<SearchAction *> SearchContext::possibleMatches() const
|
||||
{
|
||||
return d->possible;
|
||||
}
|
||||
|
||||
|
||||
|
||||
SearchAction::SearchAction(SearchContext *search, AbstractRunner *runner)
|
||||
: QAction(search),
|
||||
d(new Private(search, runner))
|
||||
{
|
||||
connect(this, SIGNAL(triggered(bool)), this, SLOT(exec()));
|
||||
}
|
||||
|
||||
SearchAction::~SearchAction()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
void SearchAction::setType(Type type)
|
||||
{
|
||||
d->type = type;
|
||||
}
|
||||
|
||||
SearchAction::Type SearchAction::type() const
|
||||
{
|
||||
return d->type;
|
||||
}
|
||||
|
||||
void SearchAction::setMimetype(const QString &mimetype)
|
||||
{
|
||||
d->mimetype = mimetype;
|
||||
}
|
||||
|
||||
QString SearchAction::mimetype() const
|
||||
{
|
||||
return d->mimetype.isEmpty() ? d->search->mimetype() : d->mimetype;
|
||||
}
|
||||
|
||||
QString SearchAction::term() const
|
||||
{
|
||||
return d->search->term();
|
||||
}
|
||||
|
||||
void SearchAction::setRelevance(qreal relevance)
|
||||
{
|
||||
d->relevance = qMax(0.0, qMin(1.0, relevance));
|
||||
}
|
||||
|
||||
qreal SearchAction::relevance() const
|
||||
{
|
||||
return d->relevance;
|
||||
}
|
||||
|
||||
AbstractRunner* SearchAction::runner() const
|
||||
{
|
||||
return d->runner;
|
||||
}
|
||||
|
||||
bool SearchAction::operator<(const SearchAction& other) const
|
||||
{
|
||||
return d->relevance < other.d->relevance;
|
||||
}
|
||||
|
||||
void SearchAction::exec()
|
||||
{
|
||||
//TODO: this could be dangerous if the runner is deleted behind our backs.
|
||||
d->runner->exec(this);
|
||||
}
|
||||
|
||||
|
||||
AbstractRunner::AbstractRunner(QObject* parent)
|
||||
: QObject(parent),
|
||||
d(new Private())
|
||||
{
|
||||
}
|
||||
|
||||
@ -55,63 +270,37 @@ AbstractRunner::~AbstractRunner()
|
||||
delete d;
|
||||
}
|
||||
|
||||
bool AbstractRunner::hasOptions()
|
||||
bool AbstractRunner::hasMatchOptions()
|
||||
{
|
||||
return false;
|
||||
return d->hasMatchOptions;
|
||||
}
|
||||
|
||||
QWidget* AbstractRunner::options()
|
||||
void AbstractRunner::setHasMatchOptions(bool hasMatchOptions)
|
||||
{
|
||||
return 0;
|
||||
d->hasMatchOptions = hasMatchOptions;
|
||||
}
|
||||
|
||||
QAction* AbstractRunner::exactMatch( )
|
||||
void AbstractRunner::createMatchOptions(QWidget* parent)
|
||||
{
|
||||
return d->exactMatch;
|
||||
Q_UNUSED(parent)
|
||||
}
|
||||
|
||||
QAction* AbstractRunner::exactMatch( const QString& term )
|
||||
bool AbstractRunner::canBeConfigured()
|
||||
{
|
||||
delete d->exactMatch;
|
||||
d->term.clear();
|
||||
|
||||
d->exactMatch = accepts( term );
|
||||
if ( d->exactMatch ) {
|
||||
d->term = term;
|
||||
connect( d->exactMatch, SIGNAL( triggered() ),
|
||||
this, SLOT( runExactMatch() ) );
|
||||
}
|
||||
|
||||
return d->exactMatch;
|
||||
return d->hasConfig;
|
||||
}
|
||||
|
||||
KActionCollection* AbstractRunner::matches( const QString& term, int max, int offset )
|
||||
void AbstractRunner::setCanBeConfigured(bool hasConfig)
|
||||
{
|
||||
d->actions->clear();
|
||||
fillMatches( d->actions, term, max, offset );
|
||||
return d->actions;
|
||||
d->hasConfig = hasConfig;
|
||||
}
|
||||
|
||||
void AbstractRunner::fillMatches( KActionCollection* matches,
|
||||
const QString& term,
|
||||
int max, int offset )
|
||||
void AbstractRunner::exec(Plasma::SearchAction *action)
|
||||
{
|
||||
Q_UNUSED( matches );
|
||||
Q_UNUSED( term );
|
||||
Q_UNUSED( max );
|
||||
Q_UNUSED( offset );
|
||||
Q_UNUSED(action)
|
||||
}
|
||||
|
||||
void AbstractRunner::runExactMatch()
|
||||
{
|
||||
if (!d->exactMatch) {
|
||||
return;
|
||||
}
|
||||
|
||||
exec(d->exactMatch, d->term);
|
||||
}
|
||||
|
||||
AbstractRunner::List AbstractRunner::loadRunners( QWidget* parent )
|
||||
AbstractRunner::List AbstractRunner::loadRunners(QObject* parent)
|
||||
{
|
||||
List firstRunners;
|
||||
List runners;
|
||||
@ -122,7 +311,7 @@ AbstractRunner::List AbstractRunner::loadRunners( QWidget* parent )
|
||||
foreach (KService::Ptr service, offers) {
|
||||
AbstractRunner* runner = service->createInstance<AbstractRunner>(parent, QVariantList(), &error);
|
||||
if (runner) {
|
||||
kDebug() << "loaded runner : " << service->name();
|
||||
//kDebug() << "loaded runner : " << service->name();
|
||||
QString phase = service->property("X-Plasma-RunnerPhase").toString();
|
||||
if (phase == "last") {
|
||||
lastRunners.append(runner);
|
||||
|
207
abstractrunner.h
207
abstractrunner.h
@ -20,8 +20,9 @@
|
||||
#ifndef RUNNER_H
|
||||
#define RUNNER_H
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QList>
|
||||
#include <QAction>
|
||||
#include <QList>
|
||||
#include <QObject>
|
||||
|
||||
#include <plasma/plasma_export.h>
|
||||
|
||||
@ -31,6 +32,114 @@ class QAction;
|
||||
namespace Plasma
|
||||
{
|
||||
|
||||
class AbstractRunner;
|
||||
class SearchAction;
|
||||
|
||||
class PLASMA_EXPORT SearchContext : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum Type { UnknownType = 0,
|
||||
Directory,
|
||||
File,
|
||||
NetworkLocation,
|
||||
Executable,
|
||||
ShellCommand,
|
||||
Help
|
||||
};
|
||||
|
||||
explicit SearchContext(QObject *parent = 0);
|
||||
~SearchContext();
|
||||
|
||||
void setTerm(const QString&);
|
||||
QString term() const;
|
||||
Type type() const;
|
||||
QString mimetype() const;
|
||||
|
||||
SearchAction* addInformationalMatch(AbstractRunner *runner);
|
||||
SearchAction* addExactMatch(AbstractRunner *runner);
|
||||
SearchAction* addPossibleMatch(AbstractRunner *runner);
|
||||
|
||||
QList<SearchAction *> informationalMatches() const;
|
||||
QList<SearchAction *> exactMatches() const;
|
||||
QList<SearchAction *> possibleMatches() const;
|
||||
|
||||
private:
|
||||
class Private;
|
||||
Private * const d;
|
||||
};
|
||||
|
||||
class PLASMA_EXPORT SearchAction : public QAction
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum Type { InformationalMatch,
|
||||
ExactMatch,
|
||||
PossibleMatch };
|
||||
|
||||
SearchAction(SearchContext *search, AbstractRunner *runner);
|
||||
~SearchAction();
|
||||
|
||||
/**
|
||||
* Sets the type of match this action represents.
|
||||
*/
|
||||
void setType(Type type);
|
||||
|
||||
/**
|
||||
* The type of action this is. Defaults to ExactMatch.
|
||||
*/
|
||||
Type type() const;
|
||||
|
||||
/**
|
||||
* Sets the mimetype, if any, associated with this match
|
||||
*
|
||||
* @arg mimetype the mimetype
|
||||
*/
|
||||
void setMimetype(const QString &mimetype);
|
||||
|
||||
/**
|
||||
* The mimetype associated with this action, if any
|
||||
*/
|
||||
QString mimetype() const;
|
||||
|
||||
/**
|
||||
* The search term that triggered this action
|
||||
*/
|
||||
QString term() const;
|
||||
|
||||
/**
|
||||
* Sets the relevance of this action for the search
|
||||
* it was created for.
|
||||
*
|
||||
* @param relevance a number between 0 and 1.
|
||||
*/
|
||||
void setRelevance(qreal relevance);
|
||||
|
||||
/**
|
||||
* The relevance of this action to the search. By default,
|
||||
* the relevance is 1.
|
||||
*
|
||||
* @return a number between 0 and 1
|
||||
*/
|
||||
qreal relevance() const;
|
||||
|
||||
/**
|
||||
* The runner associated with this action
|
||||
*/
|
||||
AbstractRunner* runner() const;
|
||||
|
||||
bool operator<(const SearchAction& other) const;
|
||||
|
||||
protected Q_SLOTS:
|
||||
void exec();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
Private * const d;
|
||||
};
|
||||
|
||||
/**
|
||||
* A abstract super-class for Plasma Runners
|
||||
*/
|
||||
@ -41,12 +150,17 @@ class PLASMA_EXPORT AbstractRunner : public QObject
|
||||
public:
|
||||
typedef QList<AbstractRunner*> List;
|
||||
|
||||
/**
|
||||
* Static method is called to load and get a list available of Runners.
|
||||
*/
|
||||
static List loadRunners(QObject* parent);
|
||||
|
||||
/**
|
||||
* Constrcuts an Runner object. Since AbstractRunner has pure virtuals,
|
||||
* this constructor can not be called directly. Rather a subclass must
|
||||
* be created
|
||||
*/
|
||||
explicit AbstractRunner( QObject* parent = 0 );
|
||||
explicit AbstractRunner(QObject* parent = 0);
|
||||
virtual ~AbstractRunner();
|
||||
|
||||
/**
|
||||
@ -64,101 +178,50 @@ class PLASMA_EXPORT AbstractRunner : public QObject
|
||||
*
|
||||
* Ownership of the action passes to the AbstractRunner class.
|
||||
*/
|
||||
QAction* exactMatch(const QString& command);
|
||||
|
||||
/**
|
||||
* @return the last action generated by exactMatch( const QString& )
|
||||
*/
|
||||
QAction* exactMatch();
|
||||
|
||||
/**
|
||||
* Requests the runner to find possible matches for the search term.
|
||||
* Includes basic results paging controls via max and offset.
|
||||
*
|
||||
* @param term the search string to use
|
||||
* @param max maximum number of matches to return
|
||||
* @param offset the offset into the matched set to start at
|
||||
*
|
||||
* @return the collection of actions representing the potential matches
|
||||
**/
|
||||
KActionCollection* matches( const QString& term, int max, int offset );
|
||||
virtual void match(Plasma::SearchContext *search) = 0;
|
||||
|
||||
/**
|
||||
* If the runner has options that the user can interact with to modify
|
||||
* what happens when exec or one of the actions created in fillMatches
|
||||
* is called, the runner should return true
|
||||
*/
|
||||
virtual bool hasOptions( );
|
||||
bool hasMatchOptions();
|
||||
|
||||
/**
|
||||
* If the hasOptions() returns true, this method will be called to get
|
||||
* the widget displaying the options the user can interact with.
|
||||
* If the hasMatchOptions() returns true, this method will be called to get
|
||||
* the widget displaying the options the user can interact with to modify
|
||||
* the behaviour of what happens when a given match is selected.
|
||||
*
|
||||
* @param widget the parent of the options widgets.
|
||||
*/
|
||||
virtual QWidget* options();
|
||||
virtual void createMatchOptions(QWidget* widget);
|
||||
|
||||
/**
|
||||
* Static method is called to load and get a list available of Runners.
|
||||
* If the runner itself has configuration options, this method returns true
|
||||
*/
|
||||
static List loadRunners( QWidget* parent );
|
||||
bool canBeConfigured();
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* When emitted, the interface will update itself to show the new
|
||||
* matches. This is meant to be used by asynchronous runners that will
|
||||
* only be able to start a query on fillMatches being called with
|
||||
* response (and therefore matches) coming later
|
||||
* Called whenever an exact or possible match associated with this
|
||||
* runner is triggered.
|
||||
*/
|
||||
void matchesUpdated( KActionCollection* matches );
|
||||
virtual void exec(Plasma::SearchAction *action);
|
||||
|
||||
|
||||
protected:
|
||||
/**
|
||||
* This method is called when there is text input to match. The runner
|
||||
* should fill the matches action collection with one action per match
|
||||
* to a maximium of max matches starting at offset in the data set
|
||||
* If the action is informational only and should not be executed,
|
||||
* disable the action with setEnabled( false ).
|
||||
*
|
||||
* @param matches the action collection to add matches to
|
||||
* @param term the current search term
|
||||
* @param max the maximum number of results to return
|
||||
* @param offset the number of initial results to skip,
|
||||
* used in conjunction with max
|
||||
* Sets whether or not the the runner has options for matches
|
||||
*/
|
||||
virtual void fillMatches( KActionCollection* matches,
|
||||
const QString& term,
|
||||
int max, int offset );
|
||||
void setHasMatchOptions(bool hasMatchOptions);
|
||||
|
||||
/**
|
||||
* If the runner can run precisely this term, return a QAction, else
|
||||
* return 0. The first runner that returns a QAction will be the
|
||||
* default runner. Other runner's actions will be suggested in the
|
||||
* interface. Non-exact matches should be offered via findMatches.
|
||||
* The action will be activated if the user selects it.
|
||||
*
|
||||
* @param term the current search term
|
||||
* Sets whether or not the runner has configuration options itself
|
||||
*/
|
||||
virtual QAction* accepts(const QString& term) = 0;
|
||||
|
||||
/**
|
||||
* Take action on the command. What this means is dependant on the
|
||||
* particular runner implementation, e.g. some runners may treat
|
||||
* command as a shell command, while others may treat it as an
|
||||
* equation or a user name or ...
|
||||
*
|
||||
* This will be called automatically when the exact match is
|
||||
* selected.
|
||||
*
|
||||
* @param action the QAction provided via exactMatch
|
||||
* @param command the full command string
|
||||
*/
|
||||
virtual bool exec(QAction* action, const QString& command) = 0;
|
||||
void setCanBeConfigured(bool canBeConfigured);
|
||||
|
||||
private:
|
||||
class Private;
|
||||
Private* const d;
|
||||
|
||||
private Q_SLOTS:
|
||||
void runExactMatch();
|
||||
};
|
||||
|
||||
} // Plasma namespace
|
||||
|
Loading…
Reference in New Issue
Block a user