diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 818042a..4f5e92b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,141 +1,141 @@ add_subdirectory(declarative) set (KF5Runner_SRCS abstractrunner.cpp dbusrunner.cpp runnerjobs.cpp querymatch.cpp runnercontext.cpp runnermanager.cpp runnersyntax.cpp) ecm_qt_declare_logging_category(KF5Runner_SRCS HEADER krunner_debug.h IDENTIFIER KRUNNER CATEGORY_NAME org.kde.krunner DESCRIPTION "KRunner" EXPORT KRUNNER ) set_property(SOURCE "data/org.kde.krunner1.xml" PROPERTY INCLUDE dbusutils_p.h) add_library(KF5Runner ${KF5Runner_SRCS}) add_library(KF5::Runner ALIAS KF5Runner) ecm_generate_export_header(KF5Runner BASE_NAME KRunner GROUP_BASE_NAME KF VERSION ${KF5_VERSION} DEPRECATED_BASE_VERSION 0 - DEPRECATION_VERSIONS 5.28 + DEPRECATION_VERSIONS 5.28 5.71 EXCLUDE_DEPRECATED_BEFORE_AND_AT ${EXCLUDE_DEPRECATED_BEFORE_AND_AT} ) set(KRunner_BUILD_INCLUDE_DIRS ${KRunner_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}) target_include_directories(KF5Runner INTERFACE "$") target_include_directories(KF5Runner PUBLIC "$") target_link_libraries(KF5Runner PUBLIC Qt5::Core KF5::Plasma # Must be public because abstractrunner.h needs plasma/version.h PRIVATE Qt5::DBus Qt5::Gui Qt5::Widgets KF5::ConfigCore KF5::Service KF5::I18n KF5::ThreadWeaver KF5::CoreAddons #KShell KF5::KIOCore #KProtocolInfo ) set_target_properties(KF5Runner PROPERTIES VERSION ${KRUNNER_VERSION_STRING} SOVERSION 5 EXPORT_NAME "Runner" ) ecm_generate_headers(KRunner_CamelCase_HEADERS HEADER_NAMES AbstractRunner RunnerContext RunnerManager RunnerSyntax QueryMatch PREFIX KRunner REQUIRED_HEADERS KRunner_HEADERS ) # Install files install(TARGETS KF5Runner EXPORT KF5RunnerTargets ${KF5_INSTALL_TARGETS_DEFAULT_ARGS}) install(FILES ${KRunner_CamelCase_HEADERS} DESTINATION ${KF5_INCLUDE_INSTALL_DIR}/KRunner/KRunner COMPONENT Devel) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/krunner_export.h ${KRunner_HEADERS} DESTINATION ${KF5_INCLUDE_INSTALL_DIR}/KRunner/krunner COMPONENT Devel) install(FILES data/servicetypes/plasma-runner.desktop DESTINATION ${SERVICETYPES_INSTALL_DIR}) add_custom_target(copy_servicetypes) file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/bin/data/kservicetypes5) add_custom_command(TARGET copy_servicetypes PRE_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/data/servicetypes/plasma-runner.desktop ${CMAKE_BINARY_DIR}/bin/data/kservicetypes5) add_dependencies(KF5Runner copy_servicetypes) ecm_qt_install_logging_categories( EXPORT KRUNNER FILE krunner.categories DESTINATION ${KDE_INSTALL_LOGGINGCATEGORIESDIR} ) if(BUILD_QCH) ecm_add_qch( KF5Runner_QCH NAME KRunner BASE_NAME KF5Runner VERSION ${KF5_VERSION} ORG_DOMAIN org.kde SOURCES # using only public headers, to cover only public API ${KRunner_HEADERS} MD_MAINPAGE "${CMAKE_SOURCE_DIR}/README.md" LINK_QCHS Qt5Core_QCH INCLUDE_DIRS ${KRunner_BUILD_INCLUDE_DIRS} BLANK_MACROS KRUNNER_EXPORT KRUNNER_DEPRECATED KRUNNER_DEPRECATED_EXPORT "KRUNNER_DEPRECATED_VERSION(x, y, t)" PREDEFINED_MACROS "PLASMA_ENABLE_DEPRECATED_SINCE(x, y)=1" TAGFILE_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR} QCH_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR} COMPONENT Devel ) endif() include(ECMGeneratePriFile) ecm_generate_pri_file(BASE_NAME KRunner LIB_NAME KF5Runner DEPS "core" FILENAME_VAR PRI_FILENAME INCLUDE_INSTALL_DIR ${KF5_INCLUDE_INSTALL_DIR}/KRunner) install(FILES ${PRI_FILENAME} DESTINATION ${ECM_MKSPECS_INSTALL_DIR}) install(FILES "data/org.kde.krunner1.xml" DESTINATION ${KDE_INSTALL_DBUSINTERFACEDIR} RENAME kf5_org.kde.krunner1.xml) diff --git a/src/abstractrunner.cpp b/src/abstractrunner.cpp index 6ef8b9d..62674ce 100644 --- a/src/abstractrunner.cpp +++ b/src/abstractrunner.cpp @@ -1,398 +1,404 @@ /* * Copyright 2006-2007 Aaron Seigo * * 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 "abstractrunner.h" #include "abstractrunner_p.h" #include #include #include #include #include #include "krunner_debug.h" #include #include #include #include #if KRUNNER_BUILD_DEPRECATED_SINCE(5, 65) #include #endif #include #include "querymatch.h" #include "runnercontext.h" namespace Plasma { AbstractRunner::AbstractRunner(QObject *parent, const QString &path) : QObject(parent), d(new AbstractRunnerPrivate(this)) { d->init(path); } AbstractRunner::AbstractRunner(const KService::Ptr service, QObject *parent) : QObject(parent), d(new AbstractRunnerPrivate(this)) { d->init(service); } AbstractRunner::AbstractRunner(QObject *parent, const QVariantList &args) : QObject(parent), d(new AbstractRunnerPrivate(this)) { if (!args.isEmpty()) { KService::Ptr service = KService::serviceByStorageId(args[0].toString()); if (service) { d->init(service); } } } AbstractRunner::~AbstractRunner() { delete d; } KConfigGroup AbstractRunner::config() const { QString group = id(); if (group.isEmpty()) { group = QStringLiteral("UnnamedRunner"); } KConfigGroup runners(KSharedConfig::openConfig(), "Runners"); return KConfigGroup(&runners, group); } void AbstractRunner::reloadConfiguration() { } void AbstractRunner::addSyntax(const RunnerSyntax &syntax) { d->syntaxes.append(syntax); } void AbstractRunner::setDefaultSyntax(const RunnerSyntax &syntax) { d->syntaxes.append(syntax); d->defaultSyntax = &(d->syntaxes.last()); } void AbstractRunner::setSyntaxes(const QList &syntaxes) { d->syntaxes = syntaxes; } QList AbstractRunner::syntaxes() const { return d->syntaxes; } RunnerSyntax *AbstractRunner::defaultSyntax() const { return d->defaultSyntax; } void AbstractRunner::performMatch(Plasma::RunnerContext &localContext) { static const int reasonableRunTime = 1500; static const int fastEnoughTime = 250; if (d->suspendMatching) { return; } QElapsedTimer time; time.start(); //The local copy is already obtained in the job match(localContext); // automatically rate limit runners that become slooow const int runtime = time.elapsed(); bool slowed = speed() == SlowSpeed; if (!slowed && runtime > reasonableRunTime) { // we punish runners that return too slowly, even if they don't bring // back matches #ifndef NDEBUG // qCDebug(KRUNNER) << id() << "runner is too slow, putting it on the back burner."; #endif d->fastRuns = 0; setSpeed(SlowSpeed); } if (slowed && runtime < fastEnoughTime && localContext.query().size() > 2) { ++d->fastRuns; if (d->fastRuns > 2) { // we reward slowed runners who bring back matches fast enough // 3 times in a row #ifndef NDEBUG // qCDebug(KRUNNER) << id() << "runner is faster than we thought, kicking it up a notch"; #endif setSpeed(NormalSpeed); } } } QList AbstractRunner::actionsForMatch(const Plasma::QueryMatch &match) { Q_UNUSED(match) QList ret; return ret; } QAction* AbstractRunner::addAction(const QString &id, const QIcon &icon, const QString &text) { QAction *a = new QAction(icon, text, this); d->actions.insert(id, a); return a; } void AbstractRunner::addAction(const QString &id, QAction *action) { d->actions.insert(id, action); } void AbstractRunner::removeAction(const QString &id) { QAction *a = d->actions.take(id); delete a; } QAction* AbstractRunner::action(const QString &id) const { return d->actions.value(id); } QHash AbstractRunner::actions() const { return d->actions; } void AbstractRunner::clearActions() { qDeleteAll(d->actions); d->actions.clear(); } QMimeData *AbstractRunner::mimeDataForMatch(const QueryMatch &match) { if (match.urls().isEmpty()) { return nullptr; } QMimeData *result = new QMimeData(); result->setUrls(match.urls()); return result; } +#if KRUNNER_BUILD_DEPRECATED_SINCE(5, 71) bool AbstractRunner::hasRunOptions() { return d->hasRunOptions; } +#endif +#if KRUNNER_BUILD_DEPRECATED_SINCE(5, 71) void AbstractRunner::setHasRunOptions(bool hasRunOptions) { d->hasRunOptions = hasRunOptions; } +#endif +#if KRUNNER_BUILD_DEPRECATED_SINCE(5, 71) void AbstractRunner::createRunOptions(QWidget *parent) { - Q_UNUSED(parent); + Q_UNUSED(parent) } +#endif AbstractRunner::Speed AbstractRunner::speed() const { // the only time the read lock will fail is if we were slow are going to speed up // or if we were fast and are going to slow down; so don't wait in this case, just // say we're slow. we either will be soon or were just a moment ago and it doesn't // hurt to do one more run the slow way if (!d->speedLock.tryLockForRead()) { return SlowSpeed; } Speed s = d->speed; d->speedLock.unlock(); return s; } void AbstractRunner::setSpeed(Speed speed) { d->speedLock.lockForWrite(); d->speed = speed; d->speedLock.unlock(); } AbstractRunner::Priority AbstractRunner::priority() const { return d->priority; } void AbstractRunner::setPriority(Priority priority) { d->priority = priority; } RunnerContext::Types AbstractRunner::ignoredTypes() const { return d->blackListed; } void AbstractRunner::setIgnoredTypes(RunnerContext::Types types) { d->blackListed = types; } void AbstractRunner::run(const Plasma::RunnerContext &search, const Plasma::QueryMatch &action) { Q_UNUSED(search); Q_UNUSED(action); } QStringList AbstractRunner::categories() const { return QStringList() << name(); } QIcon AbstractRunner::categoryIcon(const QString&) const { return icon(); } void AbstractRunner::match(Plasma::RunnerContext &) { } QString AbstractRunner::name() const { if (d->runnerDescription.isValid()) { return d->runnerDescription.name(); } return objectName(); } QIcon AbstractRunner::icon() const { if (d->runnerDescription.isValid()) { return QIcon::fromTheme(d->runnerDescription.icon()); } return QIcon(); } QString AbstractRunner::id() const { if (d->runnerDescription.isValid()) { return d->runnerDescription.pluginName(); } return objectName(); } QString AbstractRunner::description() const { if (d->runnerDescription.isValid()) { return d->runnerDescription.property(QStringLiteral("Comment")).toString(); } return objectName(); } KPluginInfo AbstractRunner::metadata() const { return d->runnerDescription; } #if KRUNNER_BUILD_DEPRECATED_SINCE(5, 65) Package AbstractRunner::package() const { QT_WARNING_PUSH QT_WARNING_DISABLE_CLANG("-Wdeprecated-declarations") QT_WARNING_DISABLE_GCC("-Wdeprecated-declarations") return Package(); QT_WARNING_POP } #endif void AbstractRunner::init() { reloadConfiguration(); } DataEngine *AbstractRunner::dataEngine(const QString &name) const { return d->dataEngine(name); } bool AbstractRunner::isMatchingSuspended() const { return d->suspendMatching; } void AbstractRunner::suspendMatching(bool suspend) { if (d->suspendMatching == suspend) { return; } d->suspendMatching = suspend; emit matchingSuspended(suspend); } AbstractRunnerPrivate::AbstractRunnerPrivate(AbstractRunner *r) : priority(AbstractRunner::NormalPriority), speed(AbstractRunner::NormalSpeed), blackListed(RunnerContext::None), runner(r), fastRuns(0), defaultSyntax(nullptr), hasRunOptions(false), suspendMatching(false) { } AbstractRunnerPrivate::~AbstractRunnerPrivate() { } void AbstractRunnerPrivate::init(const KService::Ptr service) { QT_WARNING_PUSH QT_WARNING_DISABLE_CLANG("-Wdeprecated-declarations") QT_WARNING_DISABLE_GCC("-Wdeprecated-declarations") runnerDescription = KPluginInfo(service); QT_WARNING_POP } void AbstractRunnerPrivate::init(const QString &path) { runnerDescription = KPluginInfo(path + QStringLiteral("/metadata.desktop")); const QString api = runnerDescription.property(QStringLiteral("X-Plasma-API")).toString(); } } // Plasma namespace #include "moc_abstractrunner.cpp" diff --git a/src/abstractrunner.h b/src/abstractrunner.h index e3e3bc9..68f9e45 100644 --- a/src/abstractrunner.h +++ b/src/abstractrunner.h @@ -1,498 +1,510 @@ /* * Copyright 2006-2007 Aaron Seigo * * 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 Library 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 PLASMA_ABSTRACTRUNNER_H #define PLASMA_ABSTRACTRUNNER_H #include #include #include #include #include #include #include "krunner_export.h" #include "querymatch.h" #include "runnercontext.h" #include "runnersyntax.h" #include #include // for PLASMA_ENABLE_DEPRECATED_SINCE class QAction; class QMimeData; namespace Plasma { class DataEngine; class Package; class QueryMatch; class AbstractRunnerPrivate; /** * @class AbstractRunner abstractrunner.h * * @short An abstract base class for Plasma Runner plugins. * * Be aware that runners have to be thread-safe. This is due to the fact that * each runner is executed in its own thread for each new term. Thus, a runner * may be executed more than once at the same time. See match() for details. * To let krunner expose a global shortcut for the single runner query mode, the runner * must set the "X-Plasma-AdvertiseSingleRunnerMode" key to true in the .desktop file * and set a default syntax. See setDefaultSyntax() for details. * */ class KRUNNER_EXPORT AbstractRunner : public QObject { Q_OBJECT Q_PROPERTY(bool matchingSuspended READ isMatchingSuspended WRITE suspendMatching NOTIFY matchingSuspended) Q_PROPERTY(QString id READ id) Q_PROPERTY(QString description READ description) Q_PROPERTY(QString name READ name) Q_PROPERTY(QIcon icon READ icon) public: /** Specifies a nominal speed for the runner */ enum Speed { SlowSpeed, NormalSpeed }; /** Specifies a priority for the runner */ enum Priority { LowestPriority = 0, LowPriority, NormalPriority, HighPriority, HighestPriority }; /** An ordered list of runners */ typedef QList List; virtual ~AbstractRunner(); /** * This is the main query method. It should trigger creation of * QueryMatch instances through RunnerContext::addMatch and * RunnerContext::addMatches. It is called internally by performMatch(). * * If the runner can run precisely the requested term (RunnerContext::query()), * it should create an exact match by setting the type to RunnerContext::ExactMatch. * The first runner that creates a QueryMatch will be the * default runner. Other runner's matches will be suggested in the * interface. Non-exact matches should be offered via RunnerContext::PossibleMatch. * * The match will be activated via run() if the user selects it. * * Each runner is executed in its own thread. Whenever the user input changes this * method is called again. Thus, it needs to be thread-safe. Also, all matches need * to be reported once this method returns. Asynchronous runners therefore need * to make use of a local event loop to wait for all matches. * * It is recommended to use local status data in async runners. The simplest way is * to have a separate class doing all the work like so: * * \code * void MyFancyAsyncRunner::match(RunnerContext &context) * { * QEventLoop loop; * MyAsyncWorker worker(context); * connect(&worker, &MyAsyncWorker::finished, &loop, &MyAsyncWorker::quit); * worker.work(); * loop.exec(); * } * \endcode * * Here MyAsyncWorker creates all the matches and calls RunnerContext::addMatch * in some internal slot. It emits the finished() signal once done which will * quit the loop and make the match() method return. The local status is kept * entirely in MyAsyncWorker which makes match() trivially thread-safe. * * If a particular match supports multiple actions, set up the corresponding * actions in the actionsForMatch method. Do not call any of the action methods * within this method! * * Execution of the correct action should be handled in the run method. * @caution This method needs to be thread-safe since KRunner will simply * start a new thread for each new term. * * @warning Returning from this method means to end execution of the runner. * * @sa run(), RunnerContext::addMatch, RunnerContext::addMatches, QueryMatch */ virtual void match(Plasma::RunnerContext &context); /** * Triggers a call to match. This will call match() internally. * * @param context the search context used in executing this match. */ void performMatch(Plasma::RunnerContext &context); +#if KRUNNER_ENABLE_DEPRECATED_SINCE(5, 71) /** * If the runner has options that the user can interact with to modify * what happens when run or one of the actions created in match * is called, the runner should return true + * @deprecated Since 5.0, this feature has been defunct */ + KRUNNER_DEPRECATED_VERSION_BELATED(5, 71, 5, 0, "No longer use, feature removed") bool hasRunOptions(); +#endif +#if KRUNNER_ENABLE_DEPRECATED_SINCE(5, 71) /** * If hasRunOptions() returns true, this method may be called to get * a 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. + * @deprecated Since 5.0, this feature has been defunct */ + KRUNNER_DEPRECATED_VERSION_BELATED(5, 71, 5, 0, "No longer use, feature removed") virtual void createRunOptions(QWidget *widget); +#endif /** * Called whenever an exact or possible match associated with this * runner is triggered. * * @param context The context in which the match is triggered, i.e. for which * the match was created. * @param match The actual match to run/execute. */ virtual void run(const Plasma::RunnerContext &context, const Plasma::QueryMatch &match); /** * Return a list of categories that this runner provides. By default * this list just contains the runners name. It is used by the runner manager * to disable certain runners if all the categories they provide have * been disabled. * * This list of categories is also used to provide a better way to * configure the runner instead of the typical on / off switch. */ virtual QStringList categories() const; /** * Returns the icon which accurately describes the category \p category. * This is meant to be used in a configuration dialog when showing * all the categories. * * By default this returns the icon of the AbstractRunner */ virtual QIcon categoryIcon(const QString& category) const; /** * The nominal speed of the runner. * @see setSpeed */ Speed speed() const; /** * The priority of the runner. * @see setPriority */ Priority priority() const; /** * Returns the OR'ed value of all the Information types (as defined in RunnerContext::Type) * this runner is not interested in. * @return OR'ed value of black listed types */ RunnerContext::Types ignoredTypes() const; /** * Sets the types this runner will ignore * @param types OR'ed listed of ignored types */ void setIgnoredTypes(RunnerContext::Types types); /** * @return the user visible engine name for the Runner */ QString name() const; /** * @return an id string for the Runner */ QString id() const; /** * @return the description of this Runner */ QString description() const; /** * @return the plugin info for this runner */ KPluginInfo metadata() const; /** * @return the icon for this Runner */ QIcon icon() const; #if KRUNNER_ENABLE_DEPRECATED_SINCE(5, 65) // not 5.28 here, this KRUNNER visibility control only added at 5.65 #if PLASMA_ENABLE_DEPRECATED_SINCE(5, 28) // Plasma::Package is defined with this condition /** * Accessor for the associated Package object if any. * * Note that the returned pointer is only valid for the lifetime of * the runner. * * @return the Package object, which may be invalid * @deprecated since 5.28, use KPackage::Package instead, no accessor in this class **/ KRUNNER_DEPRECATED_VERSION(5, 28, "No longer use, feature removed") Package package() const; #endif #endif /** * Signal runner to reload its configuration. */ virtual void reloadConfiguration(); /** * @return the syntaxes the runner has registered that it accepts and understands * @since 4.3 */ QList syntaxes() const; /** * @return the default syntax for the runner or @c nullptr if no default syntax has been defined * * @since 4.4 */ RunnerSyntax *defaultSyntax() const; /** * @return true if the runner is currently busy with non-interuptable work, signaling that * new threads should not be created for it at this time * @since 4.6 */ bool isMatchingSuspended() const; Q_SIGNALS: /** * This signal is emitted when matching is about to commence, giving runners * an opportunity to prepare themselves, e.g. loading data sets or preparing * IPC or network connections. This method should be fast so as not to cause * slow downs. Things that take longer or which should be loaded once and * remain extant for the lifespan of the AbstractRunner should be done in init(). * @see init() * @since 4.4 */ void prepare(); /** * This signal is emitted when a session of matches is complete, giving runners * the opportunity to tear down anything set up as a result of the prepare() * method. * @since 4.4 */ void teardown(); /** * Emitted when the runner enters or exits match suspension * @see matchingSuspended * @since 4.6 */ void matchingSuspended(bool suspended); protected: friend class RunnerManager; friend class RunnerManagerPrivate; explicit AbstractRunner(QObject *parent = nullptr, const QString &path = QString()); explicit AbstractRunner(const KService::Ptr service, QObject *parent = nullptr); AbstractRunner(QObject *parent, const QVariantList &args); /** * Sets whether or not the runner is available for match requests. Useful to * prevent more thread spawning when the thread is in a busy state. */ void suspendMatching(bool suspend); /** * Provides access to the runner's configuration object. */ KConfigGroup config() const; +#if KRUNNER_ENABLE_DEPRECATED_SINCE(5, 71) /** * Sets whether or not the runner has options for matches + * @deprecated Since 5.0, this feature has been defunct */ + KRUNNER_DEPRECATED_VERSION_BELATED(5, 71, 5, 0, "No longer use, feature removed") void setHasRunOptions(bool hasRunOptions); +#endif /** * Sets the nominal speed of the runner. Only slow runners need * to call this within their constructor because the default * speed is NormalSpeed. Runners that use D-Bus should call * this within their constructors. */ void setSpeed(Speed newSpeed); /** * Sets the priority of the runner. Lower priority runners are executed * only after higher priority runners. */ void setPriority(Priority newPriority); /** * A given match can have more than action that can be performed on it. * For example, a song match returned by a music player runner can be queued, * added to the playlist, or played. * * Call this method to add actions that can be performed by the runner. * Actions must first be added to the runner's action registry. * Note: execution of correct action is left up to the runner. */ virtual QList actionsForMatch(const Plasma::QueryMatch &match); /** * Creates and then adds an action to the action registry. * AbstractRunner assumes ownership of the created action. * * @param id A unique identifier string * @param icon The icon to display * @param text The text to display * @return the created QAction */ QAction* addAction(const QString &id, const QIcon &icon, const QString &text); /** * Adds an action to the runner's action registry. * * The QAction must be created within the GUI thread; * do not create it within the match method of AbstractRunner. * * @param id A unique identifier string * @param action The QAction to be stored */ void addAction(const QString &id, QAction *action); /** * Removes the action from the action registry. * AbstractRunner deletes the action once removed. * * @param id The id of the action to be removed */ void removeAction(const QString &id); /** * Returns the action associated with the id */ QAction* action(const QString &id) const; /** * Returns all registered actions */ QHash actions() const; /** * Clears the action registry. * The action pool deletes the actions. */ void clearActions(); /** * Adds a registered syntax that this runner understands. This is used to * display to the user what this runner can understand and how it can be * used. * * @param syntax the syntax to register * @since 4.3 */ void addSyntax(const RunnerSyntax &syntax); /** * Set @p syntax as the default syntax for the runner; the default syntax will be * substituted to the empty query in single runner mode. This is also used to * display to the user what this runner can understand and how it can be * used. * The default syntax is automatically added to the list of registered syntaxes, there * is no need to add it using addSyntax. * Note that there can be only one default syntax; if called more than once, the last * call will determine the default syntax. * A default syntax (even trivial) is required to advertise single runner mode * * @param syntax the syntax to register and to set as default * @since 4.4 **/ void setDefaultSyntax(const RunnerSyntax &syntax); /** * Sets the list of syntaxes; passing in an empty list effectively clears * the syntaxes. * * @param the syntaxes to register for this runner * @since 4.3 */ void setSyntaxes(const QList &syns); /** * Loads the given DataEngine * * Tries to load the data engine given by @p name. Each engine is * only loaded once, and that instance is re-used on all subsequent * requests. * * If the data engine was not found, an invalid data engine is returned * (see DataEngine::isValid()). * * Note that you should not delete the returned engine. * * @param name Name of the data engine to load * @return pointer to the data engine if it was loaded, * or an invalid data engine if the requested engine * could not be loaded * * @since 4.4 */ Q_INVOKABLE DataEngine *dataEngine(const QString &name) const; /** * Reimplement this slot to run any initialization routines on first load. * By default, it calls reloadConfiguration(); for scripted Runners this * method also sets up the ScriptEngine. */ virtual void init(); /** * Reimplement this slot if you want your runner * to support serialization and drag and drop * @since 4.5 */ virtual QMimeData *mimeDataForMatch(const Plasma::QueryMatch &match); private: AbstractRunnerPrivate *const d; }; } // Plasma namespace #define K_EXPORT_PLASMA_RUNNER( libname, classname ) \ K_PLUGIN_FACTORY(factory, registerPlugin();) \ K_EXPORT_PLUGIN_VERSION(PLASMA_VERSION) /** * These plugins are Used by the plugin selector dialog to show * configuration options specific to this runner. These options * must be runner global and not pertain to a specific match. */ #define K_EXPORT_RUNNER_CONFIG( name, classname ) \ K_PLUGIN_FACTORY(ConfigFactory, registerPlugin();) \ K_EXPORT_PLUGIN_VERSION(PLASMA_VERSION) #endif diff --git a/src/querymatch.cpp b/src/querymatch.cpp index a62aedb..8b77f05 100644 --- a/src/querymatch.cpp +++ b/src/querymatch.cpp @@ -1,349 +1,351 @@ /* * Copyright 2006-2007 Aaron Seigo * * 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 "querymatch.h" #include #include #include #include #include #include "krunner_debug.h" #include "abstractrunner.h" namespace Plasma { class QueryMatchPrivate : public QSharedData { public: QueryMatchPrivate(AbstractRunner *r) : QSharedData(), lock(new QReadWriteLock(QReadWriteLock::Recursive)), runner(r), type(QueryMatch::ExactMatch), relevance(.7), selAction(nullptr), enabled(true), idSetByData(false) { } QueryMatchPrivate(const QueryMatchPrivate &other) : QSharedData(other), lock(new QReadWriteLock(QReadWriteLock::Recursive)) { QReadLocker l(other.lock); runner = other.runner; type = other.type; relevance = other.relevance; selAction = other.selAction; enabled = other.enabled; idSetByData = other.idSetByData; matchCategory = other.matchCategory; id = other.id; text = other.text; subtext = other.subtext; icon = other.icon; iconName = other.iconName; data = other.data; mimeType = other.mimeType; urls = other.urls; } ~QueryMatchPrivate() { delete lock; } QReadWriteLock *lock; QPointer runner; QueryMatch::Type type; QString matchCategory; QString id; QString text; QString subtext; QString mimeType; QList urls; QIcon icon; QString iconName; QVariant data; qreal relevance; QAction *selAction; bool enabled : 1; bool idSetByData : 1; }; QueryMatch::QueryMatch(AbstractRunner *runner) : d(new QueryMatchPrivate(runner)) { // qCDebug(KRUNNER) << "new match created"; } QueryMatch::QueryMatch(const QueryMatch &other) : d(other.d) { } QueryMatch::~QueryMatch() { } bool QueryMatch::isValid() const { return d->runner != nullptr; } QString QueryMatch::id() const { if (d->id.isEmpty() && d->runner) { return d->runner.data()->id(); } return d->id; } void QueryMatch::setType(Type type) { d->type = type; } QueryMatch::Type QueryMatch::type() const { return d->type; } void QueryMatch::setMatchCategory(const QString &category) { d->matchCategory = category; } QString QueryMatch::matchCategory() const { if (d->matchCategory.isEmpty() && d->runner) { return d->runner->name(); } return d->matchCategory; } void QueryMatch::setRelevance(qreal relevance) { d->relevance = qMax(qreal(0.0), relevance); } qreal QueryMatch::relevance() const { return d->relevance; } AbstractRunner* QueryMatch::runner() const { return d->runner.data(); } void QueryMatch::setText(const QString &text) { QWriteLocker locker(d->lock); d->text = text; } void QueryMatch::setSubtext(const QString &subtext) { QWriteLocker locker(d->lock); d->subtext = subtext; } void QueryMatch::setData(const QVariant & data) { QWriteLocker locker(d->lock); d->data = data; if (d->id.isEmpty() || d->idSetByData) { const QString id = data.toString(); if (!id.isEmpty()) { setId(data.toString()); d->idSetByData = true; } } } void QueryMatch::setId(const QString &id) { QWriteLocker locker(d->lock); if (d->runner) { d->id = d->runner.data()->id(); } if (!id.isEmpty()) { d->id.append(QLatin1Char('_')).append(id); } d->idSetByData = false; } void QueryMatch::setIcon(const QIcon &icon) { QWriteLocker locker(d->lock); d->icon = icon; } void QueryMatch::setIconName(const QString &iconName) { QWriteLocker locker(d->lock); d->iconName = iconName; } QVariant QueryMatch::data() const { QReadLocker locker(d->lock); return d->data; } QString QueryMatch::text() const { QReadLocker locker(d->lock); return d->text; } QString QueryMatch::subtext() const { QReadLocker locker(d->lock); return d->subtext; } QIcon QueryMatch::icon() const { QReadLocker locker(d->lock); return d->icon; } QString QueryMatch::iconName() const { QReadLocker locker(d->lock); return d->iconName; } void QueryMatch::setMimeType(const QString &mimeType) { QWriteLocker locker(d->lock); d->mimeType = mimeType; } QString QueryMatch::mimeType() const { QReadLocker locker(d->lock); return d->mimeType; } void QueryMatch::setUrls(const QList &urls) { QWriteLocker locker(d->lock); d->urls = urls; } QList QueryMatch::urls() const { QReadLocker locker(d->lock); return d->urls; } void QueryMatch::setEnabled(bool enabled) { d->enabled = enabled; } bool QueryMatch::isEnabled() const { return d->enabled && d->runner; } QAction* QueryMatch::selectedAction() const { return d->selAction; } void QueryMatch::setSelectedAction(QAction *action) { d->selAction = action; } bool QueryMatch::operator<(const QueryMatch &other) const { if (d->type == other.d->type) { if (isEnabled() != other.isEnabled()) { return other.isEnabled(); } if (!qFuzzyCompare(d->relevance, other.d->relevance)) { return d->relevance < other.d->relevance; } QReadLocker locker(d->lock); QReadLocker otherLocker(other.d->lock); // when resorting to sort by alpha, we want the // reverse sort order! return d->text > other.d->text; } return d->type < other.d->type; } QueryMatch &QueryMatch::operator=(const QueryMatch &other) { if (d != other.d) { d = other.d; } return *this; } bool QueryMatch::operator==(const QueryMatch &other) const { return (d == other.d); } bool QueryMatch::operator!=(const QueryMatch &other) const { return (d != other.d); } void QueryMatch::run(const RunnerContext &context) const { //qCDebug(KRUNNER) << "we run the term" << context.query() << "whose type is" << d->mimeType; if (d->runner) { d->runner.data()->run(context, *this); } } +#if KRUNNER_BUILD_DEPRECATED_SINCE(5, 71) bool QueryMatch::hasConfigurationInterface() const { - return d->runner && d->runner.data()->hasRunOptions(); + return false; } +#endif +#if KRUNNER_BUILD_DEPRECATED_SINCE(5, 71) void QueryMatch::createConfigurationInterface(QWidget *parent) { - if (hasConfigurationInterface()) { - d->runner.data()->createRunOptions(parent); - } + Q_UNUSED(parent) } +#endif } // Plasma namespace diff --git a/src/querymatch.h b/src/querymatch.h index d0687c2..3d8f276 100644 --- a/src/querymatch.h +++ b/src/querymatch.h @@ -1,312 +1,320 @@ /* * Copyright 2006-2007 Aaron Seigo * * 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 PLASMA_QUERYMATCH_H #define PLASMA_QUERYMATCH_H #include #include #include #include "krunner_export.h" class QAction; class QIcon; class QString; class QVariant; class QWidget; namespace Plasma { class RunnerContext; class AbstractRunner; class QueryMatchPrivate; /** * @class QueryMatch querymatch.h * * @short A match returned by an AbstractRunner in response to a given * RunnerContext. */ class KRUNNER_EXPORT QueryMatch { public: /** * The type of match. Value is important here as it is used for sorting */ enum Type { NoMatch = 0, /**< Null match */ 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 to activating the given search term, such as a search in an external tool or a command learning trigger. Helper matches tend to be generic to the query and should not be autoactivated just because the user hits "Enter" while typing. They must be explicitly selected to be activated, but unlike InformationalMatch cause an action to be triggered. */ ExactMatch = 100 /**< An exact match to the query */ }; /** * Constructs a PossibleMatch associated with a given RunnerContext * and runner. * * @param runner the runner this match belongs to */ explicit QueryMatch(AbstractRunner *runner = nullptr); /** * Copy constructor */ QueryMatch(const QueryMatch &other); ~QueryMatch(); QueryMatch &operator=(const QueryMatch &other); bool operator==(const QueryMatch &other) const; bool operator!=(const QueryMatch &other) const; bool operator<(const QueryMatch &other) const; /** * @return the runner associated with this action */ AbstractRunner *runner() const; /** * Requests this match to activae using the given context * * @param context the context to use in conjunction with this run * * @sa AbstractRunner::run */ void run(const RunnerContext &context) const; /** * @return true if the match is valid and can therefore be run, * an invalid match does not have an associated AbstractRunner */ bool isValid() const; /** * Sets the type of match this action represents. */ void setType(Type type); /** * The type of action this is. Defaults to PossibleMatch. */ Type type() const; /** * Sets information about the type of the match which can * be used to categorize the match. * * This string should be translated as it can be displayed * in an UI */ void setMatchCategory(const QString& category); /** * Extra information about the match which can be used * to categorize the type. * * By default this returns the internal name of the runner * which returned this result */ QString matchCategory() 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; /** * Sets data to be used internally by the associated * AbstractRunner. * * When set, it is also used to form * part of the id() for this match. If that is inappropriate * as an id, the runner may generate its own id and set that * with setId(const QString&) directly after calling setData */ void setData(const QVariant &data); /** * @return the data associated with this match; usually runner-specific */ QVariant data() const; /** * Sets the id for this match; useful if the id does not * match data().toString(). The id must be unique to all * matches from this runner, and should remain constant * for the same query for best results. * * @param id the new identifying string to use to refer * to this entry */ void setId(const QString &id); /** * @return a string that can be used as an ID for this match, * even between different queries. It is based in part * on the source of the match (the AbstractRunner) and * distinguishing information provided by the runner, * ensuring global uniqueness as well as consistency * between query matches. */ QString id() const; /** * Sets the main title text for this match; should be short * enough to fit nicely on one line in a user interface * * @param text the text to use as the title */ void setText(const QString &text); /** * @return the title text for this match */ QString text() const; /** * Sets the descriptive text for this match; can be longer * than the main title text * * @param text the text to use as the description */ void setSubtext(const QString &text); /** * @return the descriptive text for this match */ QString subtext() const; /** * Sets the icon associated with this match * * Prefer using setIconName. * * @param icon the icon to show along with the match */ void setIcon(const QIcon &icon); /** * @return the icon for this match */ QIcon icon() const; /** * Sets the icon name associated with this match * * @param icon the name of the icon to show along with the match * @since 5.24 */ void setIconName(const QString &iconName); /** * @return the name of the icon for this match * @since 5.24 */ QString iconName() const; /** * Sets the MimeType, if any, associated with this match. * This overrides the MimeType provided by QueryContext, and should only be * set when it is different from the QueryContext MimeType */ void setMimeType(const QString &mimeType); /** * @return the mimtype for this match, or QString() is none */ QString mimeType() const; /** * Sets the urls, if any, associated with this match */ void setUrls(const QList &urls); /** * @return the mimtype for this match, or QString() is none */ QList urls() const; /** * Sets whether or not this match can be activited * * @param enable true if the match is enabled and therefore runnable */ void setEnabled(bool enable); /** * @return true if the match is enabled and therefore runnable, otherwise false */ bool isEnabled() const; /** * The current action. */ QAction* selectedAction() const; /** * Sets the selected action */ void setSelectedAction(QAction *action); +#if KRUNNER_ENABLE_DEPRECATED_SINCE(5, 71) /** * @return true if this match can be configured before being run * @since 4.3 + * @deprecated Since 5.0, this feature has been defunct */ + KRUNNER_DEPRECATED_VERSION_BELATED(5, 71, 5, 0, "No longer use, feature removed") bool hasConfigurationInterface() const; +#endif +#if KRUNNER_ENABLE_DEPRECATED_SINCE(5, 71) /** * If hasConfigurationInterface() returns true, this method may be called to get * a widget displaying the options the user can interact with to modify * the behaviour of what happens when the match is run. * * @param widget the parent of the options widgets. * @since 4.3 + * @deprecated Since 5.0, this feature has been defunct */ + KRUNNER_DEPRECATED_VERSION_BELATED(5, 71, 5, 0, "No longer use, feature removed") void createConfigurationInterface(QWidget *parent); +#endif private: QSharedDataPointer d; }; } #endif