1 | /* |
2 | * Copyright 2006-2007 Aaron Seigo <aseigo@kde.org> |
3 | * |
4 | * This program is free software; you can redistribute it and/or modify |
5 | * it under the terms of the GNU Library General Public License as |
6 | * published by the Free Software Foundation; either version 2, or |
7 | * (at your option) any later version. |
8 | * |
9 | * This program is distributed in the hope that it will be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | * GNU Library General Public License for more details |
13 | * |
14 | * You should have received a copy of the GNU Library General Public |
15 | * License along with this program; if not, write to the |
16 | * Free Software Foundation, Inc., |
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
18 | */ |
19 | |
20 | #ifndef PLASMA_ABSTRACTRUNNER_H |
21 | #define PLASMA_ABSTRACTRUNNER_H |
22 | |
23 | #include <QtCore/QObject> |
24 | #include <QtCore/QMutex> |
25 | #include <QtCore/QStringList> |
26 | |
27 | #include <kconfiggroup.h> |
28 | #include <kservice.h> |
29 | |
30 | #include <plasma/plasma_export.h> |
31 | #include <plasma/querymatch.h> |
32 | #include <plasma/runnercontext.h> |
33 | #include <plasma/runnersyntax.h> |
34 | #include <plasma/version.h> |
35 | |
36 | class QAction; |
37 | class QMimeData; |
38 | |
39 | class KCompletion; |
40 | |
41 | namespace Plasma |
42 | { |
43 | |
44 | class DataEngine; |
45 | class Package; |
46 | class RunnerScript; |
47 | class QueryMatch; |
48 | class AbstractRunnerPrivate; |
49 | |
50 | /** |
51 | * @class AbstractRunner plasma/abstractrunner.h <Plasma/AbstractRunner> |
52 | * |
53 | * @short An abstract base class for Plasma Runner plugins. |
54 | * |
55 | * Be aware that runners have to be thread-safe. This is due to the fact that |
56 | * each runner is executed in its own thread for each new term. Thus, a runner |
57 | * may be executed more than once at the same time. See match() for details. |
58 | * To let krunner expose a global shortcut for the single runner query mode, the runner |
59 | * must set the "X-Plasma-AdvertiseSingleRunnerMode" key to true in the .desktop file |
60 | * and set a default syntax. See setDefaultSyntax() for details. |
61 | * |
62 | */ |
63 | class PLASMA_EXPORT AbstractRunner : public QObject |
64 | { |
65 | Q_OBJECT |
66 | Q_PROPERTY(bool matchingSuspended READ isMatchingSuspended WRITE suspendMatching NOTIFY matchingSuspended) |
67 | Q_PROPERTY(QString id READ id) |
68 | Q_PROPERTY(QString description READ description) |
69 | Q_PROPERTY(QString name READ name) |
70 | Q_PROPERTY(QIcon icon READ icon) |
71 | public: |
72 | /** Specifies a nominal speed for the runner */ |
73 | enum Speed { |
74 | SlowSpeed, |
75 | NormalSpeed |
76 | }; |
77 | |
78 | /** Specifies a priority for the runner */ |
79 | enum Priority { |
80 | LowestPriority = 0, |
81 | LowPriority, |
82 | NormalPriority, |
83 | HighPriority, |
84 | HighestPriority |
85 | }; |
86 | |
87 | /** An ordered list of runners */ |
88 | typedef QList<AbstractRunner*> List; |
89 | |
90 | virtual ~AbstractRunner(); |
91 | |
92 | /** |
93 | * This is the main query method. It should trigger creation of |
94 | * QueryMatch instances through RunnerContext::addMatch and |
95 | * RunnerContext::addMatches. It is called internally by performMatch(). |
96 | * |
97 | * If the runner can run precisely the requested term (RunnerContext::query()), |
98 | * it should create an exact match by setting the type to RunnerContext::ExactMatch. |
99 | * The first runner that creates a QueryMatch will be the |
100 | * default runner. Other runner's matches will be suggested in the |
101 | * interface. Non-exact matches should be offered via RunnerContext::PossibleMatch. |
102 | * |
103 | * The match will be activated via run() if the user selects it. |
104 | * |
105 | * Each runner is executed in its own thread. Whenever the user input changes this |
106 | * method is called again. Thus, it needs to be thread-safe. Also, all matches need |
107 | * to be reported once this method returns. Asynchronous runners therefore need |
108 | * to make use of a local event loop to wait for all matches. |
109 | * |
110 | * It is recommended to use local status data in async runners. The simplest way is |
111 | * to have a separate class doing all the work like so: |
112 | * |
113 | * \code |
114 | * void MyFancyAsyncRunner::match( RunnerContext& context ) |
115 | * { |
116 | * QEventLoop loop; |
117 | * MyAsyncWorker worker( context ); |
118 | * connect( &worker, SIGNAL(finished()), |
119 | * &loop, SLOT(quit()) ); |
120 | * worker.work(); |
121 | * loop.exec(); |
122 | * } |
123 | * \endcode |
124 | * |
125 | * Here MyAsyncWorker creates all the matches and calls RunnerContext::addMatch |
126 | * in some internal slot. It emits the finished() signal once done which will |
127 | * quit the loop and make the match() method return. The local status is kept |
128 | * entirely in MyAsyncWorker which makes match() trivially thread-safe. |
129 | * |
130 | * If a particular match supports multiple actions, set up the corresponding |
131 | * actions in the actionsForMatch method. Do not call any of the action methods |
132 | * within this method! |
133 | * |
134 | * Execution of the correct action should be handled in the run method. |
135 | * @caution This method needs to be thread-safe since KRunner will simply |
136 | * start a new thread for each new term. |
137 | * |
138 | * @warning Returning from this method means to end execution of the runner. |
139 | * |
140 | * @sa run(), RunnerContext::addMatch, RunnerContext::addMatches, QueryMatch |
141 | */ |
142 | virtual void match(Plasma::RunnerContext &context); |
143 | |
144 | /** |
145 | * Triggers a call to match. This will call match() internally. |
146 | * |
147 | * @param context the search context used in executing this match. |
148 | */ |
149 | void performMatch(Plasma::RunnerContext &context); |
150 | |
151 | /** |
152 | * If the runner has options that the user can interact with to modify |
153 | * what happens when run or one of the actions created in match |
154 | * is called, the runner should return true |
155 | */ |
156 | bool hasRunOptions(); |
157 | |
158 | /** |
159 | * If hasRunOptions() returns true, this method may be called to get |
160 | * a widget displaying the options the user can interact with to modify |
161 | * the behaviour of what happens when a given match is selected. |
162 | * |
163 | * @param widget the parent of the options widgets. |
164 | */ |
165 | virtual void createRunOptions(QWidget *widget); |
166 | |
167 | /** |
168 | * Called whenever an exact or possible match associated with this |
169 | * runner is triggered. |
170 | * |
171 | * @param context The context in which the match is triggered, i.e. for which |
172 | * the match was created. |
173 | * @param match The actual match to run/execute. |
174 | */ |
175 | virtual void run(const Plasma::RunnerContext &context, const Plasma::QueryMatch &match); |
176 | |
177 | /** |
178 | * The nominal speed of the runner. |
179 | * @see setSpeed |
180 | */ |
181 | Speed speed() const; |
182 | |
183 | /** |
184 | * The priority of the runner. |
185 | * @see setPriority |
186 | */ |
187 | Priority priority() const; |
188 | |
189 | /** |
190 | * Returns the OR'ed value of all the Information types (as defined in RunnerContext::Type) |
191 | * this runner is not interested in. |
192 | * @return OR'ed value of black listed types |
193 | */ |
194 | RunnerContext::Types ignoredTypes() const; |
195 | |
196 | /** |
197 | * Sets the types this runner will ignore |
198 | * @param types OR'ed listed of ignored types |
199 | */ |
200 | void setIgnoredTypes(RunnerContext::Types types); |
201 | |
202 | /** |
203 | * @return the user visible engine name for the Runner |
204 | */ |
205 | QString name() const; |
206 | |
207 | /** |
208 | * @return an id string for the Runner |
209 | */ |
210 | QString id() const; |
211 | |
212 | /** |
213 | * @return the description of this Runner |
214 | */ |
215 | QString description() const; |
216 | |
217 | /** |
218 | * @return the icon for this Runner |
219 | */ |
220 | QIcon icon() const; |
221 | |
222 | /** |
223 | * Accessor for the associated Package object if any. |
224 | * |
225 | * Note that the returned pointer is only valid for the lifetime of |
226 | * the runner. |
227 | * |
228 | * @return the Package object, or 0 if none |
229 | **/ |
230 | const Package *package() const; |
231 | |
232 | /** |
233 | * Signal runner to reload its configuration. |
234 | */ |
235 | virtual void reloadConfiguration(); |
236 | |
237 | /** |
238 | * @return the syntaxes the runner has registered that it accepts and understands |
239 | * @since 4.3 |
240 | */ |
241 | QList<RunnerSyntax> syntaxes() const; |
242 | |
243 | /** |
244 | * Access to a shared lock that all runners (and code that manages/interacts with them) |
245 | * can share to protect access to non-thread-safe shared code or data. |
246 | * Access of KSycoca records, for instance, is one place this lock should be used. |
247 | * |
248 | * Common usage: |
249 | * |
250 | * { |
251 | * QMutexLocker lock(bigLock()); |
252 | * .. do something that isn't thread safe .. |
253 | * } |
254 | */ |
255 | static QMutex *bigLock(); |
256 | |
257 | /** |
258 | * @return the default syntax for the runner or 0 if no default syntax has been defined |
259 | * |
260 | * @since 4.4 |
261 | */ |
262 | RunnerSyntax *defaultSyntax() const; |
263 | |
264 | /** |
265 | * @return true if the runner is currently busy with non-interuptable work, signaling that |
266 | * new threads should not be created for it at this time |
267 | * @since 4.6 |
268 | */ |
269 | bool isMatchingSuspended() const; |
270 | |
271 | Q_SIGNALS: |
272 | /** |
273 | * This signal is emitted when matching is about to commence, giving runners |
274 | * an opportunity to prepare themselves, e.g. loading data sets or preparing |
275 | * IPC or network connections. This method should be fast so as not to cause |
276 | * slow downs. Things that take longer or which should be loaded once and |
277 | * remain extant for the lifespan of the AbstractRunner should be done in init(). |
278 | * @see init() |
279 | * @since 4.4 |
280 | */ |
281 | void prepare(); |
282 | |
283 | /** |
284 | * This signal is emitted when a session of matches is complete, giving runners |
285 | * the opportunity to tear down anything set up as a result of the prepare() |
286 | * method. |
287 | * @since 4.4 |
288 | */ |
289 | void teardown(); |
290 | |
291 | /** |
292 | * Emitted when the runner enters or exits match suspension |
293 | * @see matchingSuspended |
294 | * @since 4.6 |
295 | */ |
296 | void matchingSuspended(bool suspended); |
297 | |
298 | protected: |
299 | friend class RunnerManager; |
300 | friend class RunnerManagerPrivate; |
301 | |
302 | explicit AbstractRunner(QObject *parent = 0, const QString &path = QString()); |
303 | explicit AbstractRunner(const KService::Ptr service, QObject *parent = 0); |
304 | |
305 | AbstractRunner(QObject *parent, const QVariantList &args); |
306 | |
307 | /** |
308 | * Sets whether or not the runner is available for match requests. Useful to |
309 | * prevent more thread spawning when the thread is in a busy state. |
310 | */ |
311 | void suspendMatching(bool suspend); |
312 | |
313 | /** |
314 | * Provides access to the runner's configuration object. |
315 | */ |
316 | KConfigGroup config() const; |
317 | |
318 | /** |
319 | * Sets whether or not the runner has options for matches |
320 | */ |
321 | void setHasRunOptions(bool hasRunOptions); |
322 | |
323 | /** |
324 | * Sets the nominal speed of the runner. Only slow runners need |
325 | * to call this within their constructor because the default |
326 | * speed is NormalSpeed. Runners that use DBUS should call |
327 | * this within their constructors. |
328 | */ |
329 | void setSpeed(Speed newSpeed); |
330 | |
331 | /** |
332 | * Sets the priority of the runner. Lower priority runners are executed |
333 | * only after higher priority runners. |
334 | */ |
335 | void setPriority(Priority newPriority); |
336 | |
337 | /** |
338 | * @deprecated |
339 | * A blocking method to do queries of installed Services which can provide |
340 | * a measure of safety for runners running their own threads. This should |
341 | * be used instead of calling KServiceTypeTrader::query(..) directly. |
342 | * |
343 | * @param serviceType a service type like "Plasma/Applet" or "KFilePlugin" |
344 | * @param constraint a constraint to limit the choices returned. |
345 | * @see KServiceTypeTrader::query(const QString&, const QString&) |
346 | * |
347 | * @return a list of services that satisfy the query. |
348 | */ |
349 | KService::List serviceQuery(const QString &serviceType, |
350 | const QString &constraint = QString()) const; |
351 | |
352 | /** |
353 | * A given match can have more than action that can be performed on it. |
354 | * For example, a song match returned by a music player runner can be queued, |
355 | * added to the playlist, or played. |
356 | * |
357 | * Call this method to add actions that can be performed by the runner. |
358 | * Actions must first be added to the runner's action registry. |
359 | * Note: execution of correct action is left up to the runner. |
360 | */ |
361 | virtual QList<QAction*> actionsForMatch(const Plasma::QueryMatch &match); |
362 | |
363 | /** |
364 | * Creates and then adds an action to the action registry. |
365 | * AbstractRunner assumes ownership of the created action. |
366 | * |
367 | * @param id A unique identifier string |
368 | * @param icon The icon to display |
369 | * @param text The text to display |
370 | * @return the created QAction |
371 | */ |
372 | QAction* addAction(const QString &id, const QIcon &icon, const QString &text); |
373 | |
374 | /** |
375 | * Adds an action to the runner's action registry. |
376 | * |
377 | * The QAction must be created within the GUI thread; |
378 | * do not create it within the match method of AbstractRunner. |
379 | * |
380 | * @param id A unique identifier string |
381 | * @param action The QAction to be stored |
382 | */ |
383 | void addAction(const QString &id, QAction *action); |
384 | |
385 | /** |
386 | * Removes the action from the action registry. |
387 | * AbstractRunner deletes the action once removed. |
388 | * |
389 | * @param id The id of the action to be removed |
390 | */ |
391 | void removeAction(const QString &id); |
392 | |
393 | /** |
394 | * Returns the action associated with the id |
395 | */ |
396 | QAction* action(const QString &id) const; |
397 | |
398 | /** |
399 | * Returns all registered actions |
400 | */ |
401 | QHash<QString, QAction*> actions() const; |
402 | |
403 | /** |
404 | * Clears the action registry. |
405 | * The action pool deletes the actions. |
406 | */ |
407 | void clearActions(); |
408 | |
409 | /** |
410 | * Adds a registered syntax that this runner understands. This is used to |
411 | * display to the user what this runner can understand and how it can be |
412 | * used. |
413 | * |
414 | * @param syntax the syntax to register |
415 | * @since 4.3 |
416 | */ |
417 | void addSyntax(const RunnerSyntax &syntax); |
418 | |
419 | /** |
420 | * Set @p syntax as the default syntax for the runner; the default syntax will be |
421 | * substituted to the empty query in single runner mode. This is also used to |
422 | * display to the user what this runner can understand and how it can be |
423 | * used. |
424 | * The default syntax is automatically added to the list of registered syntaxes, there |
425 | * is no need to add it using addSyntax. |
426 | * Note that there can be only one default syntax; if called more than once, the last |
427 | * call will determine the default syntax. |
428 | * A default syntax (even trivial) is required to advertise single runner mode |
429 | * |
430 | * @param syntax the syntax to register and to set as default |
431 | * @since 4.4 |
432 | **/ |
433 | void setDefaultSyntax(const RunnerSyntax &syntax); |
434 | |
435 | /** |
436 | * Sets the list of syntaxes; passing in an empty list effectively clears |
437 | * the syntaxes. |
438 | * |
439 | * @param the syntaxes to register for this runner |
440 | * @since 4.3 |
441 | */ |
442 | void setSyntaxes(const QList<RunnerSyntax> &syns); |
443 | |
444 | /** |
445 | * Loads the given DataEngine |
446 | * |
447 | * Tries to load the data engine given by @p name. Each engine is |
448 | * only loaded once, and that instance is re-used on all subsequent |
449 | * requests. |
450 | * |
451 | * If the data engine was not found, an invalid data engine is returned |
452 | * (see DataEngine::isValid()). |
453 | * |
454 | * Note that you should <em>not</em> delete the returned engine. |
455 | * |
456 | * @param name Name of the data engine to load |
457 | * @return pointer to the data engine if it was loaded, |
458 | * or an invalid data engine if the requested engine |
459 | * could not be loaded |
460 | * |
461 | * @since 4.4 |
462 | */ |
463 | Q_INVOKABLE DataEngine *dataEngine(const QString &name) const; |
464 | |
465 | protected Q_SLOTS: |
466 | /** |
467 | * Reimplement this slot to run any initialization routines on first load. |
468 | * By default, it calls reloadConfiguration(); for scripted Runners this |
469 | * method also sets up the ScriptEngine. |
470 | */ |
471 | void init(); |
472 | |
473 | /** |
474 | * Reimplement this slot if you want your runner |
475 | * to support serialization and drag and drop |
476 | * @since 4.5 |
477 | */ |
478 | QMimeData * mimeDataForMatch(const Plasma::QueryMatch *match); |
479 | |
480 | private: |
481 | friend class RunnerScript; |
482 | |
483 | AbstractRunnerPrivate *const d; |
484 | }; |
485 | |
486 | } // Plasma namespace |
487 | |
488 | #define K_EXPORT_PLASMA_RUNNER( libname, classname ) \ |
489 | K_PLUGIN_FACTORY(factory, registerPlugin<classname>();) \ |
490 | K_EXPORT_PLUGIN(factory("plasma_runner_" #libname)) \ |
491 | K_EXPORT_PLUGIN_VERSION(PLASMA_VERSION) |
492 | |
493 | /** |
494 | * These plugins are Used by the plugin selector dialog to show |
495 | * configuration options specific to this runner. These options |
496 | * must be runner global and not pertain to a specific match. |
497 | */ |
498 | #define K_EXPORT_RUNNER_CONFIG( name, classname ) \ |
499 | K_PLUGIN_FACTORY(ConfigFactory, registerPlugin<classname>();) \ |
500 | K_EXPORT_PLUGIN(ConfigFactory("kcm_krunner_" #name)) \ |
501 | K_EXPORT_PLUGIN_VERSION(PLASMA_VERSION) |
502 | |
503 | #endif |
504 | |