1 #ifndef PLUGINMANAGERIMPL_H 2 #define PLUGINMANAGERIMPL_H 3 4 #include "services/pluginmanager.h" 5 #include <QPluginLoader> 6 #include <QHash> 7 8 class API_EXPORT PluginManagerImpl : public PluginManager 9 { 10 Q_OBJECT 11 12 public: 13 /** 14 * @brief Creates plugin manager. 15 */ 16 PluginManagerImpl(); 17 18 /** 19 * @brief Deletes plugin manager. 20 */ 21 ~PluginManagerImpl(); 22 23 void init(); 24 void deinit(); 25 QList<PluginType*> getPluginTypes() const; 26 QStringList getPluginDirs() const; 27 QString getFilePath(Plugin* plugin) const; 28 bool loadBuiltInPlugin(Plugin* plugin); 29 bool load(const QString& pluginName); 30 void unload(const QString& pluginName); 31 void unload(Plugin* plugin); 32 bool isLoaded(const QString& pluginName) const; 33 bool isBuiltIn(const QString& pluginName) const; 34 Plugin* getLoadedPlugin(const QString& pluginName) const; 35 QStringList getAllPluginNames(PluginType* type) const; 36 QStringList getAllPluginNames() const; 37 PluginType* getPluginType(const QString& pluginName) const; 38 QString getAuthor(const QString& pluginName) const; 39 QString getTitle(const QString& pluginName) const; 40 QString getPrintableVersion(const QString& pluginName) const; 41 int getVersion(const QString& pluginName) const; 42 QString getDescription(const QString& pluginName) const; 43 PluginType* getPluginType(Plugin* plugin) const; 44 QList<Plugin*> getLoadedPlugins(PluginType* type) const; 45 ScriptingPlugin* getScriptingPlugin(const QString& languageName) const; 46 QHash<QString,QVariant> readMetaData(const QJsonObject& metaData); 47 QString toPrintableVersion(int version) const; 48 QStringList getDependencies(const QString& pluginName) const; 49 QStringList getConflicts(const QString& pluginName) const; 50 bool arePluginsInitiallyLoaded() const; 51 QList<Plugin*> getLoadedPlugins() const; 52 QStringList getLoadedPluginNames() const; 53 QList<PluginDetails> getAllPluginDetails() const; 54 QList<PluginDetails> getLoadedPluginDetails() const; 55 56 protected: 57 void registerPluginType(PluginType* type); 58 59 private: 60 struct PluginDependency 61 { 62 QString name; 63 int minVersion = 0; 64 int maxVersion = 0; 65 }; 66 67 /** 68 * @brief Container for plugin related data. 69 * 70 * The container is used to represent plugin available to the application, 71 * no matter if it's loaded or not. It keeps all plugin related data, 72 * so it's available even the plugin is not loaded. 73 */ 74 struct PluginContainer 75 { 76 /** 77 * @brief Name of the plugin. 78 */ 79 QString name; 80 81 /** 82 * @brief Title of the plugin, used on UI. 83 */ 84 QString title; 85 86 /** 87 * @brief Plugin's detailed description. 88 */ 89 QString description; 90 91 /** 92 * @brief Plugin's author. 93 */ 94 QString author; 95 96 /** 97 * @brief Numeric verion of the plugin. 98 */ 99 int version; 100 101 /** 102 * @brief Human-readable version. 103 */ 104 QString printableVersion; 105 106 /** 107 * @brief Type of the plugin. 108 */ 109 PluginType* type = nullptr; 110 111 /** 112 * @brief Full path to the plugin's file. 113 */ 114 QString filePath; 115 116 /** 117 * @brief Plugin's loaded state flag. 118 */ 119 bool loaded; 120 121 /** 122 * @brief Qt's plugin framework loaded for this plugin. 123 */ 124 QPluginLoader* loader = nullptr; 125 126 /** 127 * @brief Plugin object. 128 * 129 * It's null when plugin is not loaded. 130 */ 131 Plugin* plugin = nullptr; 132 133 /** 134 * @brief Flag indicating that the plugin is built in. 135 * 136 * Plugins built-in are classes implementing plugin's interface, 137 * but they are compiled and statically linked to the main application binary. 138 * They cannot be loaded or unloaded - they are loaded by default. 139 */ 140 bool builtIn = false; 141 142 /** 143 * @brief Flag indicating that plugin should be loaded, unless user unloaded it manually. 144 * 145 * If this flag is set to false, then the plugin will not be loaded, even it was not manually unloaded. 146 * This flag can be defined in plugin's json file using property named 'loadByDefault'. 147 */ 148 bool loadByDefault = true; 149 150 /** 151 * @brief Names of plugnis that this plugin depends on. 152 */ 153 QList<PluginDependency> dependencies; 154 155 /** 156 * @brief Names of plugins that this plugin conflicts with. 157 */ 158 QStringList conflicts; 159 }; 160 161 /** 162 * @brief List of plugins, both loaded and unloaded. 163 */ 164 typedef QList<PluginContainer*> PluginContainerList; 165 166 /** 167 * @brief Scans plugin directories to find out available plugins. 168 * 169 * It looks in the following locations: 170 * <ul> 171 * <li> application_directory/plugins/ 172 * <li> application_config_directory/plugins/ 173 * <li> directory pointed by the SQLITESTUDIO_PLUGINS environment variable 174 * <li> directory compiled in as PLUGINS_DIR parameter of the compilation 175 * </ul> 176 * 177 * The application_directory is a directory where the application executable is. 178 * The application_config_directory can be different, see ConfigImpl::initDbFile() for details. 179 * The SQLITESTUDIO_PLUGINS variable can contain several paths, separated by : (for Unix/Mac) or ; (for Windows). 180 */ 181 void scanPlugins(); 182 183 /** 184 * @brief Loads plugins defined in configuration. 185 * 186 * It loads all plugins that are available to the application 187 * and are not marked to not load in the configuration. 188 * 189 * In other words, every plugin will load by default, unless it was 190 * explicitly unloaded previously and that was saved in the configuration 191 * (when application was closing). 192 */ 193 void loadPlugins(); 194 195 /** 196 * @brief Loads given plugin. 197 * @param pluginName Name of the plugin to load. 198 * @param alreadyAttempted List of plugin names that were already attempted to be loaded. 199 * @param minVersion Minimum required version of the plugin to load. 200 * @param maxVersion Maximum required version of the plugin to load. 201 * @return true on success, false on failure. 202 * 203 * This is pretty much what the public load() method does, except this one tracks what plugins were already 204 * attempted to be loaded (and failed), so it doesn't warn twice about the same plugin if it failed 205 * to load while it was a dependency for some other plugins. 206 * 207 * It also allows to define minimum and maximum plugin version, so if SQLiteStudio has the plugin available, 208 * but the version is out of required range, it will also fail to load. 209 */ 210 bool load(const QString& pluginName, QStringList& alreadyAttempted, int minVersion = 0, int maxVersion = 0); 211 212 /** 213 * @brief Executes standard routines after plugin was loaded. 214 * @param container Container for the loaded plugin. 215 * 216 * It fills all members of the plugin container and emits loaded() signal. 217 */ 218 void pluginLoaded(PluginContainer* container); 219 220 /** 221 * @brief Stores some specific plugin types in internal collections for faster access. 222 * @param plugin Plugin that was just loaded. 223 * 224 * This is called after we are sure we have a Plugin instance. 225 * 226 * The method stores certain plugin types in internal collections, so they can be accessed 227 * faster, instead of calling getLoadedPlugin<T>(), which is not as fast. 228 * 229 * The internal collections are used for plugins that are likely to be accessed frequently, 230 * like ScriptingPlugin. 231 */ 232 void addPluginToCollections(Plugin* plugin); 233 234 /** 235 * @brief Removes plugin from internal collections. 236 * @param plugin Plugin that is about to be unloaded. 237 * 238 * This is the reverse operation to what addPluginToCollections(Plugin*) does. 239 */ 240 void removePluginFromCollections(Plugin* plugin); 241 242 /** 243 * @brief Reads title, description, author, etc. from the plugin. 244 * @param plugin Plugin to read data from. 245 * @param container Container to put the data to. 246 * @return true on success, false on problems (with details in logs) 247 * 248 * It does the reading by calling all related methods from Plugin interface, 249 * then stores those information in given \p container. 250 * 251 * The built-in plugins define those methods using their class metadata. 252 * 253 * External plugins provide this information in their file metadata 254 * and this method uses QPluginLoader to read this metadata. 255 */ 256 bool readMetaData(PluginContainer* container); 257 258 /** 259 * @brief Creates plugin container and initializes it. 260 * @param loader Qt's plugin framework loader used to load this plugin. 261 * For built-in plugins (statically linked) this must be null. 262 * @param fileName Plugin's file path. For built-in plugins it's ignored. 263 * @param plugin Plugin object from loaded plugin. 264 * @return true if the initialization succeeded, or false otherwise. 265 * 266 * It assigns plugin type to the plugin, creates plugin container and fills 267 * all necessary data for the plugin. If the plugin was configured to not load, 268 * then this method unloads the file, before plugin was initialized (with Plugin::init()). 269 * 270 * All plugins are loaded at the start, but before they are fully initialized 271 * and enabled, they are simply queried for metadata, then either unloaded 272 * (when configured to not load at startup), or the initialization proceeds. 273 */ 274 bool initPlugin(QPluginLoader* loader, const QString& fileName); 275 276 bool checkPluginRequirements(const QString& pluginName, const QJsonObject& metaObject); 277 bool readDependencies(const QString& pluginName, PluginContainer* container, const QJsonValue& depsValue); 278 bool readConflicts(const QString& pluginName, PluginContainer* container, const QJsonValue& confValue); 279 280 /** 281 * @brief Creates plugin container and initializes it. 282 * @param plugin Built-in plugin object. 283 * @return true if the initialization succeeded, or false otherwise. 284 * 285 * This is pretty much the same as the other initPlugin() method, but this one is for built-in plugins. 286 */ 287 bool initPlugin(Plugin* plugin); 288 289 /** 290 * @brief Tests if given plugin is configured to be loaded at startup. 291 * @param plugin Tested plugin object. 292 * @return true if plugin should be loaded at startup, or false otherwise. 293 * 294 * This method checks General.LoadedPlugins configuration entry to see if plugin 295 * was explicitly disabled for loading at startup. 296 */ 297 bool shouldAutoLoad(const QString& pluginName); 298 299 /** 300 * @brief List of plugin directories (not necessarily absolute paths). 301 */ 302 QStringList pluginDirs; 303 304 /** 305 * @brief List of registered plugin types. 306 */ 307 QList<PluginType*> registeredPluginTypes; 308 309 /** 310 * @brief Table with plugin types as keys and list of plugins assigned for each type. 311 */ 312 QHash<PluginType*,PluginContainerList> pluginCategories; 313 314 /** 315 * @brief Table with plugin names and containers assigned for each plugin. 316 */ 317 QHash<QString,PluginContainer*> pluginContainer; 318 319 /** 320 * @brief Internal list of scripting plugins, updated on load/unload of plugins. 321 * 322 * Keys are scripting language name. It's a separate table to optimize querying scripting plugins. 323 */ 324 QHash<QString,ScriptingPlugin*> scriptingPlugins; 325 326 bool pluginsAreInitiallyLoaded = false; 327 }; 328 329 #endif // PLUGINMANAGERIMPL_H 330