1 /* 2 This file is part of the KDE libraries 3 SPDX-FileCopyrightText: 2000 Torben Weis <weis@kde.org> 4 SPDX-FileCopyrightText: 2006 David Faure <faure@kde.org> 5 SPDX-FileCopyrightText: 2013 Sebastian Kügler <sebas@kde.org> 6 7 SPDX-License-Identifier: LGPL-2.0-only 8 */ 9 10 #ifndef __kplugintrader_h__ 11 #define __kplugintrader_h__ 12 13 #include "kplugininfo.h" 14 15 #if KSERVICE_ENABLE_DEPRECATED_SINCE(5, 82) 16 17 class KPluginTraderPrivate; 18 /** 19 * \class KPluginTrader kplugintrader.h <KPluginTrader> 20 * 21 * A trader interface which provides a way to query specific subdirectories in the Qt 22 * plugin paths for plugins. KPluginTrader provides an easy way to load a plugin 23 * instance from a KPluginFactory, or just querying for existing plugins. 24 * 25 * KPluginTrader provides a way for an application to query directories in the 26 * Qt plugin paths, accessed through QCoreApplication::libraryPaths(). 27 * Plugins may match a specific set of requirements. This allows to find 28 * specific plugins at run-time without having to hard-code their names and/or 29 * paths. KPluginTrader does not search recursively, you are rather encouraged 30 * to install plugins into specific subdirectories to further speed searching. 31 * 32 * KPluginTrader exclusively searches within the plugin binaries' metadata 33 * (via QPluginLoader::metaData()). It does not search these directories recursively. 34 * 35 * KPluginTrader does not use KServiceTypeTrader or KSyCoCa. As such, it will 36 * only find binary plugins. If you are looking for a generic way to query for 37 * services, use KServiceTypeTrader. For anything relating to MIME types (type 38 * of files), use KMimeTypeTrader. 39 * 40 * \par Example 41 * 42 * If you want to find all plugins for your application, 43 * you would define a KMyApp/Plugin servicetype, and then you can query 44 * the trader for it: 45 * \code 46 * KPluginInfo::List offers = 47 * KPluginTrader::self()->query("KMyApp/Plugin", "kf5"); 48 * \endcode 49 * 50 * You can add a constraint in the "trader query language". For instance: 51 * \code 52 * KPluginTrader::self()->query("KMyApp/Plugin", "kf5", 53 * "[X-KMyApp-InterfaceVersion] > 15"); 54 * \endcode 55 * 56 * Please note that when including property names containing arithmetic operators like - or +, then you have 57 * to put brackets around the property name, in order to correctly separate arithmetic operations from 58 * the name. So for example a constraint expression like 59 * \code 60 * X-KMyApp-InterfaceVersion > 4 // wrong! 61 * \endcode 62 * needs to be written as 63 * \code 64 * [X-KMyApp-InterfaceVersion] > 4 65 * \endcode 66 * otherwise it could also be interpreted as 67 * Subtract the numeric value of the property "KMyApp" and "InterfaceVersion" from the 68 * property "X" and make sure it is greater than 4.\n 69 * Instead of the other meaning, make sure that the numeric value of "X-KMyApp-InterfaceVersion" is 70 * greater than 4. 71 * 72 * @see KMimeTypeTrader, KServiceTypeTrader, KPluginInfo 73 * @see QCoreApplication::libraryPaths 74 * @see QT_PLUGIN_PATH (env variable) 75 * @see KPluginFactory 76 * @see kservice_desktop_to_json (Cmake macro) 77 * @see K_PLUGIN_FACTORY_WITH_JSON (macro defined in KPluginFactory) 78 * 79 * @since 5.0 80 */ 81 class KSERVICE_EXPORT KPluginTrader 82 { 83 public: 84 /** 85 * Standard destructor 86 */ 87 ~KPluginTrader(); 88 89 /** 90 * The main function in the KPluginTrader class. 91 * 92 * It will return a list of plugins that match your specifications. Required parameter is the 93 * service type and subdirectory. This method will append the subDirectory to every path found 94 * in QCoreApplication::libraryPaths(), append the subDirectory parameter, and search through 95 * the plugin's metadata 96 * 97 * KPluginTrader exclusively searches within the plugin binaries' metadata 98 * (via QPluginLoader::metaData()). It does not search these directories recursively. 99 * 100 * The constraint parameter is used to limit the possible choices returned based on the 101 * constraints you give it. 102 * 103 * The @p constraint language is rather full. The most common 104 * keywords are AND, OR, NOT, IN, and EXIST, all used in an 105 * almost spoken-word form. An example is: 106 * \code 107 * (Type == 'Service') and (('KParts/ReadOnlyPart' in ServiceTypes) or (exist Exec)) 108 * \endcode 109 * 110 * If you want to load a list of plugins from a specific subdirectory, you can do the following: 111 * 112 * \code 113 * 114 * const KPluginInfo::List plugins = KPluginTrader::self()->query("plasma/engines"); 115 * 116 * for (const KPluginInfo &info : plugins) { 117 * KPluginLoader loader(info.libraryPath()); 118 * const QVariantList argsWithMetaData = QVariantList() << loader.metaData().toVariantMap(); 119 * // In many cases, plugins are actually based on KPluginFactory, this is how that works: 120 * KPluginFactory* factory = loader.factory(); 121 * if (factory) { 122 * Engine* component = factory->create<Engine>(parent, argsWithMetaData); 123 * if (component) { 124 * // Do whatever you want to do with the resulting object 125 * } 126 * } 127 * // Otherwise, just use the normal QPluginLoader methods 128 * Engine *myengine = qobject_cast<Engine*>(loader.instance()); 129 * if (myengine) { 130 * // etc. ... 131 * } 132 * } 133 * \endcode 134 * 135 * If you have a specific query for just one plugin, use the createInstanceFromQuery method. 136 * 137 * The keys used in the query (Type, ServiceType, Exec) are all fields found in the .json files 138 * which are compiled into the plugin binaries. 139 * 140 * @param subDirectory The subdirectory under the Qt plugin path 141 * @param servicetype A service type like 'KMyApp/Plugin' or 'KFilePlugin' 142 * @param constraint A constraint to limit the choices returned, QString() to 143 * get all services of the given @p servicetype 144 * 145 * @return A list of services that satisfy the query 146 * @see http://techbase.kde.org/Development/Tutorials/Services/Traders#The_KTrader_Query_Language 147 * @deprecated since 5.82, use KPluginMetaData::findPlugins. 148 */ 149 KSERVICE_DEPRECATED_VERSION(5, 82, "Use KPluginMetaData::findPlugins") 150 KPluginInfo::List query(const QString &subDirectory, const QString &serviceType = QString(), const QString &constraint = QString()); 151 152 /** 153 * This is a static pointer to the KPluginTrader singleton. 154 * 155 * You will need to use this to access the KPluginTrader functionality since the 156 * constructors are protected. 157 * 158 * @deprecated since 5.82, use KPluginMetaData and KPluginFactory. 159 * 160 * @return Static KPluginTrader instance 161 */ 162 KSERVICE_DEPRECATED_VERSION(5, 82, "Use KPluginMetaData and KPluginFactory") 163 static KPluginTrader *self(); 164 165 /** 166 * Get a plugin from a trader query 167 * 168 * Example: 169 * \code 170 * KMyAppPlugin* plugin = KPluginTrader::createInstanceFromQuery<KMyAppPlugin>(subDirectory, serviceType, QString(), parentObject ); 171 * if ( plugin ) { 172 * .... 173 * } 174 * \endcode 175 * 176 * @param subDirectory The subdirectory under the Qt plugin paths to search in 177 * @param serviceType The type of service for which to find a plugin 178 * @param constraint An optional constraint to pass to the trader (see KTrader) 179 * @param parent The parent object for the part itself 180 * @param args A list of arguments passed to the service component 181 * @param error The string passed here will contain an error description. 182 * @return A pointer to the newly created object or a null pointer if the 183 * factory was unable to create an object of the given type. 184 * @deprecated since 5.82, use KPluginLoader API. 185 */ 186 template<class T> 187 KSERVICE_DEPRECATED_VERSION(5, 82, "Use KPluginLoader API") 188 static T *createInstanceFromQuery(const QString &subDirectory, 189 const QString &serviceType = QString(), 190 const QString &constraint = QString(), 191 QObject *parent = nullptr, 192 const QVariantList &args = QVariantList(), 193 QString *error = nullptr) 194 { 195 return createInstanceFromQuery<T>(subDirectory, serviceType, constraint, parent, nullptr, args, error); 196 } 197 198 /** 199 * Get a plugin from a trader query 200 * 201 * This method works like 202 * createInstanceFromQuery(const QString&, const QString& ,const QString&, QObject*, 203 * const QVariantList&, QString*), 204 * but you can specify an additional parent widget. This is important for a KPart, for example. 205 * 206 * @param subDirectory The subdirectory under the Qt plugin paths to search in 207 * @param serviceType the type of service for which to find a plugin 208 * @param constraint an optional constraint to pass to the trader (see KTrader) 209 * @param parent the parent object for the part itself 210 * @param parentWidget the parent widget for the plugin 211 * @param args A list of arguments passed to the service component 212 * @param error The string passed here will contain an error description. 213 * @return A pointer to the newly created object or a null pointer if the 214 * factory was unable to create an object of the given type. 215 * @deprecated since 5.82, use KPluginLoader API. 216 */ 217 template<class T> 218 KSERVICE_DEPRECATED_VERSION(5, 82, "Use KPluginLoader API") 219 static T *createInstanceFromQuery(const QString &subDirectory, 220 const QString &serviceType, 221 const QString &constraint, 222 QObject *parent, 223 QWidget *parentWidget, 224 const QVariantList &args = QVariantList(), 225 QString *error = nullptr) 226 { 227 Q_UNUSED(parentWidget) 228 Q_UNUSED(args) 229 if (error) { 230 error->clear(); 231 } 232 const KPluginInfo::List offers = self()->query(subDirectory, serviceType, constraint); 233 234 for (const KPluginInfo &info : offers) { 235 KPluginLoader loader(info.libraryPath()); 236 const QVariantList argsWithMetaData = QVariantList() << loader.metaData().toVariantMap(); 237 KPluginFactory *factory = loader.factory(); 238 if (factory) { 239 T *component = factory->create<T>(parent, argsWithMetaData); 240 if (component) { 241 return component; 242 } 243 } 244 } 245 if (error && error->isEmpty()) { 246 *error = QCoreApplication::translate("", "No service matching the requirements was found"); 247 } 248 return nullptr; 249 } 250 251 KSERVICE_DEPRECATED_VERSION(5, 82, "No users.") 252 static void applyConstraints(KPluginInfo::List &lst, const QString &constraint); 253 254 private: 255 /** 256 * @internal 257 */ 258 KPluginTrader(); 259 260 // disallow copy ctor and assignment operator 261 KPluginTrader(const KPluginTrader &other); 262 KPluginTrader &operator=(const KPluginTrader &rhs); 263 264 KPluginTraderPrivate *const d; 265 }; 266 #endif 267 268 #endif 269