1 /*
2     kopetepluginmanager.h - Kopete Plugin Loader
3 
4     Copyright (c) 2002-2003 by Duncan Mac-Vicar Prett <duncan@kde.org>
5     Copyright (c) 2002-2003 by Martijn Klingens       <klingens@kde.org>
6 
7     Kopete    (c) 2002-2003 by the Kopete developers  <kopete-devel@kde.org>
8 
9     *************************************************************************
10     *                                                                       *
11     * This library is free software; you can redistribute it and/or         *
12     * modify it under the terms of the GNU Lesser General Public            *
13     * License as published by the Free Software Foundation; either          *
14     * version 2 of the License, or (at your option) any later version.      *
15     *                                                                       *
16     *************************************************************************
17 */
18 
19 #ifndef KOPETEPLUGINMANAGER_H
20 #define KOPETEPLUGINMANAGER_H
21 
22 #include <QObject>
23 #include <QList>
24 #include "libkopete_export.h"
25 
26 class KPluginInfo;
27 
28 namespace Kopete {
29 class Plugin;
30 class Protocol;
31 typedef QList<Plugin *> PluginList;
32 class PluginManagerPrivate;
33 
34 /**
35  * @author Duncan Mac-Vicar Prett <duncan@kde.org>
36  * @author Martijn Klingens <klingens@kde.org>
37  */
38 class LIBKOPETE_EXPORT PluginManager : public QObject
39 {
40     friend class PluginManagerPrivate;
41     Q_OBJECT
42     Q_ENUMS(PluginLoadMode)
43 
44 public:
45     /**
46      * Retrieve the plugin loader instance.
47      */
48     static PluginManager *self();
49 
50     /**
51      * Returns a list of all available plugins for the given category.
52      * Currently there are two categories, "Plugins" and "Protocols", but
53      * you can add your own categories if you want.
54      *
55      * If you pass an empty string you get the complete list of ALL plugins.
56      *
57      * You can query all information on the plugins through the KPluginInfo
58      * interface.
59      */
60     QList<KPluginInfo> availablePlugins(const QString &category = QString()) const;
61 
62     /**
63      * Returns a list of all plugins that are actually loaded.
64      * If you omit the category you get all, otherwise it's a filtered list.
65      * See also @ref availablePlugins().
66      */
67     PluginList loadedPlugins(const QString &category = QString()) const;
68 
69     /**
70      * @brief Search by plugin name. This is the key used as X-KDE-PluginInfo-Name in
71      * the .desktop file, e.g. "kopete_jabber"
72      *
73      * @return The @ref Kopete::Plugin object found by the search, or a null
74      * pointer if the plugin is not loaded.
75      *
76      * If you want to also load the plugin you can better use @ref loadPlugin, which returns
77      * the pointer to the plugin if it's already loaded.
78      */
79     Plugin *plugin(const QString &pluginName) const;
80 
81     /**
82      * @return the KPluginInfo for the specified plugin
83      */
84     KPluginInfo pluginInfo(const Kopete::Plugin *plugin) const;
85 
86     /**
87      * Shuts down the plugin manager on Kopete shutdown, but first
88      * unloads all plugins asynchronously.
89      *
90      * After 3 seconds all plugins should be removed; what's still left
91      * by then is unloaded through a hard delete instead.
92      *
93      * Note that this call also derefs the plugin manager from the event
94      * loop, so do NOT call this method when not terminating Kopete!
95      */
96     void shutdown();
97 
98     /**
99      * Enable a plugin.
100      *
101      * This marks a plugin as enabled in the config file, so loadAll()
102      * can pick it up later.
103      *
104      * This method does not actually load a plugin, it only edits the
105      * config file.
106      *
107      * @param name is the name of the plugin as it is listed in the .desktop
108      * file in the X-KDE-Library field.
109      * @param enabled sets whether or not the plugin is enabled
110      *
111      * Returns false when no appropriate plugin can be found.
112      */
113     bool setPluginEnabled(const QString &name, bool enabled = true);
114 
115     /**
116      * This method check if all the plugins are loaded.
117      * @return true if all the plugins are loaded.
118      */
119     bool isAllPluginsLoaded() const;
120 
121     /**
122      * Plugin loading mode. Used by @ref loadPlugin(). Code that doesn't want to block
123      * the GUI and/or lot a lot of plugins at once should use asynchronous loading (@c LoadAsync).
124      * The default is synchronous loading (@c LoadSync).
125      */
126     enum PluginLoadMode {
127         LoadSync, LoadAsync
128     };
129 
130 public Q_SLOTS:
131     /**
132      * @brief Load a single plugin by plugin name. Returns an existing plugin
133      * if one is already loaded in memory.
134      *
135      * If mode is set to Async, the plugin will be queued and loaded in
136      * the background. This method will return a null pointer. To get
137      * the loaded plugin you can track the @ref pluginLoaded() signal.
138      *
139      * See also @ref plugin().
140      */
141     Plugin *loadPlugin(const QString &pluginId, PluginLoadMode mode = LoadSync);
142 
143     /**
144      * @brief Unload the plugin specified by @p pluginName
145      */
146     bool unloadPlugin(const QString &pluginName);
147 
148     /**
149      * @brief Loads all the enabled plugins. Also used to reread the
150      * config file when the configuration has changed.
151      */
152     void loadAllPlugins();
153 
154 Q_SIGNALS:
155     /**
156      * @brief Signals a new plugin has just been loaded.
157      */
158     void pluginLoaded(Kopete::Plugin *plugin);
159 
160     /**
161      * @brief Signals a plugin has just been unloaded.
162      */
163     void pluginUnloaded(const QString &pluginName);
164 
165     /**
166      * @brief Signals a new protocol has just been loaded.
167      * @note pluginLoaded is also emitted before this signal
168      */
169     void protocolLoaded(Kopete::Protocol *protocol);
170 
171     /**
172      * @brief All plugins have been loaded by the plugin manager.
173      *
174      * This signal is emitted exactly ONCE, when the plugin manager has emptied
175      * its plugin queue for the first time. This means that if you call an async
176      * loadPlugin() before loadAllPlugins() this signal is probably emitted after
177      * the initial call completes, unless you are quick enough to fill the queue
178      * before it completes, which is a dangerous race you shouldn't count upon :)
179      *
180      * The signal is delayed one event loop iteration through a singleShot timer,
181      * but that is not guaranteed to be enough for account instantiation. You may
182      * need an additional timer for it in the code if you want to programmatically
183      * act on it.
184      *
185      * If you use the signal for enabling/disabling GUI objects there is little
186      * chance a user is able to activate them in the short while that's remaining,
187      * the slow part of the code is over now and the remaining processing time
188      * is neglectable for the user.
189      */
190     void allPluginsLoaded();
191 
192 private Q_SLOTS:
193     /**
194      * @brief Cleans up some references if the plugin is destroyed
195      */
196     void slotPluginDestroyed(QObject *plugin);
197 
198     /**
199      * shutdown() starts a timer, when it fires we force all plugins
200      * to be unloaded here by deref()-ing the event loop to trigger the plugin
201      * manager's destruction
202      */
203     void slotShutdownTimeout();
204 
205     /**
206      * Common entry point to deref() the KApplication. Used both by the clean
207      * shutdown and the timeout condition of slotShutdownTimeout()
208      */
209     void slotShutdownDone();
210 
211     /**
212      * Emitted by a Kopete::Plugin when it's ready for unload
213      */
214     void slotPluginReadyForUnload();
215 
216     /**
217      * Load a plugin from our queue. Does nothing if the queue is empty.
218      * Schedules itself again if more plugins are pending.
219      */
220     void slotLoadNextPlugin();
221 
222 private:
223     /**
224      * @internal
225      *
226      * The internal method for loading plugins.
227      * Called by @ref loadPlugin directly or through the queue for async plugin
228      * loading.
229      */
230     Plugin *loadPluginInternal(const QString &pluginId);
231 
232     /**
233      * @internal
234      *
235      * Find the KPluginInfo structure by key. Reduces some code duplication.
236      *
237      * Returns a null pointer when no plugin info is found.
238      */
239     KPluginInfo infoForPluginId(const QString &pluginId) const;
240 
241     PluginManager();
242     ~PluginManager();
243 };
244 }
245 
246 #endif // KOPETEPLUGINMANAGER_H
247 
248 // vim: set noet ts=4 sts=4 sw=4:
249