File indexing completed on 2024-03-24 04:58:21
0001 /* 0002 This file is part of Choqok, the KDE micro-blogging client 0003 Some of below codes are got from Kopete source code. 0004 0005 SPDX-FileCopyrightText: 2008-2012 Mehrdad Momeny <mehrdad.momeny@gmail.com> 0006 0007 SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0008 */ 0009 0010 #ifndef CHOQOKPLUGINMANAGER_H 0011 #define CHOQOKPLUGINMANAGER_H 0012 0013 #include <QList> 0014 #include <QEventLoopLocker> 0015 0016 #include <KPluginMetaData> 0017 0018 #include "plugin.h" 0019 #include "choqok_export.h" 0020 0021 namespace Choqok 0022 { 0023 0024 class Protocol; 0025 typedef QList<Plugin *> PluginList; 0026 class PluginManagerPrivate; 0027 0028 /** 0029 * @author Mehrdad Momeny \<mehrdad.momeny@gmail.com\> 0030 */ 0031 class CHOQOK_EXPORT PluginManager : public QObject 0032 { 0033 friend class PluginManagerPrivate; 0034 Q_OBJECT 0035 Q_ENUMS(PluginLoadMode) 0036 0037 public: 0038 /** 0039 * Retrieve the plugin loader instance. 0040 */ 0041 static PluginManager *self(); 0042 0043 /** 0044 * Returns a list of all available plugins for the given category. 0045 * Currently there are two categories, "Plugins" and "Protocols", but 0046 * you can add your own categories if you want. 0047 * 0048 * If you pass an empty string you get the complete list of ALL plugins. 0049 * 0050 * You can query all information on the plugins through the KPluginMetaData 0051 * interface. 0052 */ 0053 QVector<KPluginMetaData> availablePlugins(const QString &category = QString()) const; 0054 0055 /** 0056 * Returns a list of all plugins that are actually loaded. 0057 * If you omit the category you get all, otherwise it's a filtered list. 0058 * See also @ref availablePlugins(). 0059 */ 0060 PluginList loadedPlugins(const QString &category = QString()) const; 0061 0062 /** 0063 * @brief Search by plugin name. This is the key used as X-KDE-PluginInfo-Name in 0064 * the .desktop file. 0065 * 0066 * @return The @ref Choqok::Plugin object found by the search, or a null 0067 * pointer if the plugin is not loaded. 0068 * 0069 * If you want to also load the plugin you can better use @ref loadPlugin, which returns 0070 * the pointer to the plugin if it's already loaded. 0071 */ 0072 Plugin *plugin(const QString &pluginName) const; 0073 0074 /** 0075 * @return the KPluginMetaData for the specified plugin 0076 */ 0077 KPluginMetaData pluginMetaData(const Choqok::Plugin *plugin) const; 0078 0079 /** 0080 * Shuts down the plugin manager on Choqok shutdown, but first 0081 * unloads all plugins asynchronously. 0082 * 0083 * After 3 seconds all plugins should be removed; what's still left 0084 * by then is unloaded through a hard delete instead. 0085 * 0086 * Note that this call also derefs the plugin manager from the event 0087 * loop, so do NOT call this method when not terminating Choqok! 0088 */ 0089 void shutdown(); 0090 0091 /** 0092 * Enable a plugin. 0093 * 0094 * This marks a plugin as enabled in the config file, so loadAll() 0095 * can pick it up later. 0096 * 0097 * This method does not actually load a plugin, it only edits the 0098 * config file. 0099 * 0100 * @param name is the name of the plugin as it is listed in the .desktop 0101 * file in the X-KDE-Library field. 0102 * @param enabled sets whether or not the plugin is enabled 0103 * 0104 * Returns false when no appropriate plugin can be found. 0105 */ 0106 bool setPluginEnabled(const QString &name, bool enabled = true); 0107 0108 /** 0109 * This method check if all the plugins are loaded. 0110 * @return true if all the plugins are loaded. 0111 */ 0112 bool isAllPluginsLoaded() const; 0113 0114 /** 0115 * Plugin loading mode. Used by @ref loadPlugin(). Code that doesn't want to block 0116 * the GUI and/or lot a lot of plugins at once should use asynchronous loading (@c LoadAsync). 0117 * The default is synchronous loading (@c LoadSync). 0118 */ 0119 enum PluginLoadMode { LoadSync, LoadAsync }; 0120 0121 public Q_SLOTS: 0122 /** 0123 * @brief Load a single plugin by plugin name. Returns an existing plugin 0124 * if one is already loaded in memory. 0125 * 0126 * If mode is set to Async, the plugin will be queued and loaded in 0127 * the background. This method will return a null pointer. To get 0128 * the loaded plugin you can track the @ref pluginLoaded() signal. 0129 * 0130 * See also @ref plugin(). 0131 */ 0132 Plugin *loadPlugin(const QString &pluginId, PluginLoadMode mode = LoadSync); 0133 0134 /** 0135 * @brief Unload the plugin specified by @p pluginName 0136 */ 0137 bool unloadPlugin(const QString &pluginName); 0138 0139 /** 0140 * @brief Loads all the enabled plugins. Also used to reread the 0141 * config file when the configuration has changed. 0142 */ 0143 void loadAllPlugins(); 0144 0145 Q_SIGNALS: 0146 /** 0147 * @brief Signals a new plugin has just been loaded. 0148 */ 0149 void pluginLoaded(Choqok::Plugin *plugin); 0150 0151 /** 0152 * @brief Signals a plugin has just been unloaded. 0153 */ 0154 void pluginUnloaded(const QString &pluginName); 0155 0156 /** 0157 * @brief All plugins have been loaded by the plugin manager. 0158 * 0159 * This signal is emitted exactly ONCE, when the plugin manager has emptied 0160 * its plugin queue for the first time. This means that if you call an async 0161 * loadPlugin() before loadAllPlugins() this signal is probably emitted after 0162 * the initial call completes, unless you are quick enough to fill the queue 0163 * before it completes, which is a dangerous race you shouldn't count upon :) 0164 * 0165 * The signal is delayed one event loop iteration through a singleShot timer, 0166 * but that is not guaranteed to be enough for account instantiation. You may 0167 * need an additional timer for it in the code if you want to programmatically 0168 * act on it. 0169 * 0170 * If you use the signal for enabling/disabling GUI objects there is little 0171 * chance a user is able to activate them in the short while that's remaining, 0172 * the slow part of the code is over now and the remaining processing time 0173 * is neglectable for the user. 0174 */ 0175 void allPluginsLoaded(); 0176 0177 private Q_SLOTS: 0178 /** 0179 * @brief Cleans up some references if the plugin is destroyed 0180 */ 0181 void slotPluginDestroyed(QObject *plugin); 0182 0183 /** 0184 * shutdown() starts a timer, when it fires we force all plugins 0185 * to be unloaded here by deref()-ing the event loop to trigger the plugin 0186 * manager's destruction 0187 */ 0188 void slotShutdownTimeout(); 0189 0190 /** 0191 * Common entry point to deref() the KApplication. Used both by the clean 0192 * shutdown and the timeout condition of slotShutdownTimeout() 0193 */ 0194 void slotShutdownDone(); 0195 0196 /** 0197 * Emitted by a Choqok::Plugin when it's ready for unload 0198 */ 0199 void slotPluginReadyForUnload(); 0200 0201 /** 0202 * Load a plugin from our queue. Does nothing if the queue is empty. 0203 * Schedules itself again if more plugins are pending. 0204 */ 0205 void slotLoadNextPlugin(); 0206 0207 /** 0208 * Called when the application is quitting 0209 */ 0210 void slotAboutToQuit(); 0211 0212 private: 0213 /** 0214 * @internal 0215 * 0216 * The internal method for loading plugins. 0217 * Called by @ref loadPlugin directly or through the queue for async plugin 0218 * loading. 0219 */ 0220 Plugin *loadPluginInternal(const QString &pluginId); 0221 0222 /** 0223 * @internal 0224 * 0225 * Find the KPluginMetaData structure by key. Reduces some code duplication. 0226 * 0227 * Returns a null pointer when no plugin info is found. 0228 */ 0229 KPluginMetaData metaDataForPluginId(const QString &pluginId) const; 0230 0231 PluginManager(); 0232 ~PluginManager(); 0233 0234 // We want to add a reference to the application's event loop so we 0235 // can remain in control when all windows are removed. 0236 // This way we can unload plugins asynchronously, which is more 0237 // robust if they are still doing processing. 0238 QEventLoopLocker lock; 0239 0240 }; 0241 0242 } 0243 0244 #endif // KOPETEPLUGINMANAGER_H 0245