File indexing completed on 2024-03-24 03:59:36
0001 /* 0002 SPDX-FileCopyrightText: 2006-2007 Aaron Seigo <aseigo@kde.org> 0003 SPDX-FileCopyrightText: 2020-2023 Alexander Lohnau<alexander.lohnau@gmx.de> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #ifndef KRUNNER_ABSTRACTRUNNER_H 0009 #define KRUNNER_ABSTRACTRUNNER_H 0010 0011 #include "krunner_export.h" 0012 0013 #include <QObject> 0014 #include <QStringList> 0015 0016 #include <KPluginFactory> 0017 #include <KPluginMetaData> 0018 0019 #include <memory> 0020 0021 #include "querymatch.h" 0022 #include "runnercontext.h" 0023 #include "runnersyntax.h" 0024 0025 class KConfigGroup; 0026 class QMimeData; 0027 class QRegularExpression; 0028 class QIcon; 0029 0030 namespace KRunner 0031 { 0032 class AbstractRunnerPrivate; 0033 0034 /** 0035 * @class AbstractRunner abstractrunner.h <KRunner/AbstractRunner> 0036 * 0037 * @short An abstract base class for Plasma Runner plugins. 0038 * 0039 * Be aware that runners will be moved to their own thread after being instantiated. 0040 * This means that except for AbstractRunner::run and the constructor, all methods will be non-blocking 0041 * for the UI. 0042 * Consider doing heavy resource initialization in the init method instead of the constructor. 0043 */ 0044 class KRUNNER_EXPORT AbstractRunner : public QObject 0045 { 0046 Q_OBJECT 0047 0048 public: 0049 ~AbstractRunner() override; 0050 0051 /** 0052 * This is the main query method. It should trigger creation of 0053 * QueryMatch instances through RunnerContext::addMatch and 0054 * RunnerContext::addMatches. 0055 * 0056 * If the runner can run precisely the requested term (RunnerContext::query()), 0057 * it should create an exact match by setting the type to RunnerContext::ExactMatch. 0058 * The first runner that creates a QueryMatch will be the 0059 * default runner. Other runner's matches will be suggested in the 0060 * interface. Non-exact matches should be offered via RunnerContext::PossibleMatch. 0061 * 0062 * The match will be activated via run() if the user selects it. 0063 * 0064 * All matches need to be reported once this method returns. Asynchronous runners therefore need 0065 * to make use of a local event loop to wait for all matches. 0066 * 0067 * It is recommended to use local status data in async runners. The simplest way is 0068 * to have a separate class doing all the work like so: 0069 * 0070 * \code 0071 * void MyFancyAsyncRunner::match(RunnerContext &context) 0072 * { 0073 * QEventLoop loop; 0074 * MyAsyncWorker worker(context); 0075 * connect(&worker, &MyAsyncWorker::finished, &loop, &MyAsyncWorker::quit); 0076 * worker.work(); 0077 * loop.exec(); 0078 * } 0079 * \endcode 0080 * 0081 * Here MyAsyncWorker creates all the matches and calls RunnerContext::addMatch 0082 * in some internal slot. It emits the finished() signal once done which will 0083 * quit the loop and make the match() method return. 0084 * 0085 * Execution of the correct action should be handled in the run method. 0086 * 0087 * @warning Returning from this method means to end execution of the runner. 0088 * 0089 * @sa run(), RunnerContext::addMatch, RunnerContext::addMatches, QueryMatch 0090 */ 0091 virtual void match(KRunner::RunnerContext &context) = 0; 0092 0093 /** 0094 * Called whenever an exact or possible match associated with this 0095 * runner is triggered. 0096 * 0097 * @param context The context in which the match is triggered, i.e. for which 0098 * the match was created. 0099 * @param match The actual match to run/execute. 0100 */ 0101 virtual void run(const KRunner::RunnerContext &context, const KRunner::QueryMatch &match); 0102 0103 /** 0104 * @return the plugin metadata for this runner that was passed in the constructor 0105 */ 0106 KPluginMetaData metadata() const; 0107 0108 /** 0109 * Returns the translated name from the runner's metadata 0110 */ 0111 QString name() const; 0112 0113 /** 0114 * @return an id from the runner's metadata' 0115 */ 0116 QString id() const; 0117 0118 /** 0119 * Reloads the runner's configuration. This is called when it's KCM in the PluginSelector is applied. 0120 * This function may be used to set for example using setMatchRegex, setMinLetterCount or setTriggerWords. 0121 * Also, syntaxes should be updated when this method is called. 0122 * While reloading the config, matching is suspended. 0123 */ 0124 virtual void reloadConfiguration(); 0125 0126 /** 0127 * @return the syntaxes the runner has registered that it accepts and understands 0128 */ 0129 QList<RunnerSyntax> syntaxes() const; 0130 0131 /** 0132 * @return true if the runner is currently busy with non-interuptable work, signaling that 0133 * the RunnerManager may not query it or read it's config properties 0134 */ 0135 bool isMatchingSuspended() const; 0136 0137 /** 0138 * This is the minimum letter count for the query. If the query is shorter than this value 0139 * and KRunner is not in the singleRunnerMode, match method is not called. 0140 * This can be set using the X-Plasma-Runner-Min-Letter-Count property or the setMinLetterCount method. 0141 * The default value is 0. 0142 * 0143 * @see setMinLetterCount 0144 * @see match 0145 * @since 5.75 0146 */ 0147 int minLetterCount() const; 0148 0149 /** 0150 * Set the minLetterCount property 0151 * @param count 0152 * @since 5.75 0153 */ 0154 void setMinLetterCount(int count); 0155 0156 /** 0157 * If this regex is set with a non empty pattern it must match the query in order for match being called. 0158 * Just like the minLetterCount property this check is ignored when the runner is in the singleRunnerMode. 0159 * In case both the regex and the letter count is set the letter count is checked first. 0160 * @return matchRegex property 0161 * @see hasMatchRegex 0162 * @since 5.75 0163 */ 0164 QRegularExpression matchRegex() const; 0165 0166 /** 0167 * Set the matchRegex property 0168 * @param regex 0169 * @since 5.75 0170 */ 0171 void setMatchRegex(const QRegularExpression ®ex); 0172 0173 /** 0174 * Constructs internally a regex which requires the query to start with the trigger words. 0175 * Multiple words are concatenated with or, for instance: "^word1|word2|word3". 0176 * The trigger words are internally escaped. 0177 * Also the minLetterCount is set to the shortest word in the list. 0178 * @since 5.75 0179 * @see matchRegex 0180 */ 0181 void setTriggerWords(const QStringList &triggerWords); 0182 0183 /** 0184 * If the runner has a valid regex and non empty regex 0185 * @internal 0186 * @since 5.75 0187 */ 0188 bool hasMatchRegex() const; 0189 0190 Q_SIGNALS: 0191 /** 0192 * This signal is emitted when matching is about to commence, giving runners 0193 * an opportunity to prepare themselves, e.g. loading data sets or preparing 0194 * IPC or network connections. Things that should be loaded once and remain 0195 * extant for the lifespan of the AbstractRunner should be done in init(). 0196 * @see init() 0197 */ 0198 void prepare(); 0199 0200 /** 0201 * This signal is emitted when a session of matches is complete, giving runners 0202 * the opportunity to tear down anything set up as a result of the prepare() 0203 * method. 0204 */ 0205 void teardown(); 0206 0207 protected: 0208 friend class RunnerManager; 0209 friend class RunnerManagerPrivate; 0210 0211 /** 0212 * Constructor for a KRunner plugin 0213 * 0214 * @note You should connect here to the prepare/teardown signals. However, avoid doing heavy initialization here 0215 * in favor of doing it in AbstractRunner::init 0216 * 0217 * @param parent parent object for this runner 0218 * @param pluginMetaData metadata that was embedded in the runner 0219 * @param args for compatibility with KPluginFactory, since 6.0 this can be omitted 0220 * @since 5.72 0221 */ 0222 explicit AbstractRunner(QObject *parent, const KPluginMetaData &pluginMetaData); 0223 0224 /** 0225 * Sets whether or not the runner is available for match requests. Useful to 0226 * prevent queries when the runner is in a busy state. 0227 * @note Do not permanently suspend the runner. This is only intended as a temporary measure to 0228 * avoid useless queries being launched or async fetching of config/data being interfered with. 0229 */ 0230 void suspendMatching(bool suspend); 0231 0232 /** 0233 * Provides access to the runner's configuration object. 0234 */ 0235 KConfigGroup config() const; 0236 0237 /** 0238 * Adds a registered syntax that this runner understands. This is used to 0239 * display to the user what this runner can understand and how it can be 0240 * used. 0241 * 0242 * @param syntax the syntax to register 0243 */ 0244 void addSyntax(const RunnerSyntax &syntax); 0245 0246 /** 0247 * Utility overload for creating a syntax based on the given parameters 0248 * @see RunnerSyntax 0249 * @since 5.106 0250 */ 0251 inline void addSyntax(const QString &exampleQuery, const QString &description) 0252 { 0253 addSyntax(QStringList(exampleQuery), description); 0254 } 0255 0256 /// @copydoc addSyntax(const QString &exampleQuery, const QString &description) 0257 inline void addSyntax(const QStringList &exampleQueries, const QString &description) 0258 { 0259 addSyntax(KRunner::RunnerSyntax(exampleQueries, description)); 0260 } 0261 0262 /** 0263 * Sets the list of syntaxes; passing in an empty list effectively clears 0264 * the syntaxes. 0265 * 0266 * @param the syntaxes to register for this runner 0267 */ 0268 void setSyntaxes(const QList<RunnerSyntax> &syns); 0269 0270 /** 0271 * Reimplement this to run any initialization routines on first load. 0272 * Because it is executed in the runner's thread, it will not block the UI and is thus preferred. 0273 * By default, it calls reloadConfiguration(); 0274 * 0275 * Until the runner is initialized, it will not be queried by the RunnerManager. 0276 */ 0277 virtual void init(); 0278 0279 /** 0280 * Reimplement this if you want your runner to support serialization and drag and drop. 0281 * By default, this sets the QMimeData urls to the ones specified in @ref QueryMatch::urls 0282 */ 0283 virtual QMimeData *mimeDataForMatch(const KRunner::QueryMatch &match); 0284 0285 private: 0286 std::unique_ptr<AbstractRunnerPrivate> const d; 0287 KRUNNER_NO_EXPORT Q_INVOKABLE void matchInternal(KRunner::RunnerContext context); 0288 KRUNNER_NO_EXPORT Q_INVOKABLE void reloadConfigurationInternal(); 0289 KRUNNER_NO_EXPORT Q_SIGNAL void matchInternalFinished(const QString &jobId); 0290 KRUNNER_NO_EXPORT Q_SIGNAL void matchingResumed(); 0291 friend class RunnerManager; 0292 friend class RunnerContext; 0293 friend class RunnerContextPrivate; 0294 friend class QueryMatchPrivate; 0295 friend class DBusRunner; // Because it "overrides" matchInternal 0296 }; 0297 0298 } // KRunner namespace 0299 #endif