File indexing completed on 2024-04-28 11:44:24

0001 /*
0002     This file is part of the KDE libraries
0003     SPDX-FileCopyrightText: 2000 Torben Weis <weis@kde.org>
0004     SPDX-FileCopyrightText: 2006 David Faure <faure@kde.org>
0005     SPDX-FileCopyrightText: 2013 Sebastian Kügler <sebas@kde.org>
0006 
0007     SPDX-License-Identifier: LGPL-2.0-only
0008 */
0009 
0010 #ifndef __kplugintrader_h__
0011 #define __kplugintrader_h__
0012 
0013 #include "kplugininfo.h"
0014 
0015 #if KSERVICE_ENABLE_DEPRECATED_SINCE(5, 82)
0016 
0017 class KPluginTraderPrivate;
0018 /**
0019  * \class KPluginTrader kplugintrader.h <KPluginTrader>
0020  *
0021  * A trader interface which provides a way to query specific subdirectories in the Qt
0022  * plugin paths for plugins. KPluginTrader provides an easy way to load a plugin
0023  * instance from a KPluginFactory, or just querying for existing plugins.
0024  *
0025  * KPluginTrader provides a way for an application to query directories in the
0026  * Qt plugin paths, accessed through QCoreApplication::libraryPaths().
0027  * Plugins may match a specific set of requirements. This allows to find
0028  * specific plugins at run-time without having to hard-code their names and/or
0029  * paths. KPluginTrader does not search recursively, you are rather encouraged
0030  * to install plugins into specific subdirectories to further speed searching.
0031  *
0032  * KPluginTrader exclusively searches within the plugin binaries' metadata
0033  * (via QPluginLoader::metaData()). It does not search these directories recursively.
0034  *
0035  * KPluginTrader does not use KServiceTypeTrader or KSyCoCa. As such, it will
0036  * only find binary plugins. If you are looking for a generic way to query for
0037  * services, use KServiceTypeTrader. For anything relating to MIME types (type
0038  * of files), use KMimeTypeTrader.
0039  *
0040  * \par Example
0041  *
0042  * If you want to find all plugins for your application,
0043  * you would define a KMyApp/Plugin servicetype, and then you can query
0044  * the trader for it:
0045  * \code
0046  * KPluginInfo::List offers =
0047  *     KPluginTrader::self()->query("KMyApp/Plugin", "kf5");
0048  * \endcode
0049  *
0050  * You can add a constraint in the "trader query language". For instance:
0051  * \code
0052  * KPluginTrader::self()->query("KMyApp/Plugin", "kf5",
0053  *                                   "[X-KMyApp-InterfaceVersion] > 15");
0054  * \endcode
0055  *
0056  * Please note that when including property names containing arithmetic operators like - or +, then you have
0057  * to put brackets around the property name, in order to correctly separate arithmetic operations from
0058  * the name. So for example a constraint expression like
0059  * \code
0060  * X-KMyApp-InterfaceVersion > 4 // wrong!
0061  * \endcode
0062  * needs to be written as
0063  * \code
0064  * [X-KMyApp-InterfaceVersion] > 4
0065  * \endcode
0066  * otherwise it could also be interpreted as
0067  * Subtract the numeric value of the property "KMyApp" and "InterfaceVersion" from the
0068  * property "X" and make sure it is greater than 4.\n
0069  * Instead of the other meaning, make sure that the numeric value of "X-KMyApp-InterfaceVersion" is
0070  * greater than 4.
0071  *
0072  * @see KMimeTypeTrader, KServiceTypeTrader, KPluginInfo
0073  * @see QCoreApplication::libraryPaths
0074  * @see QT_PLUGIN_PATH (env variable)
0075  * @see KPluginFactory
0076  * @see kservice_desktop_to_json (Cmake macro)
0077  * @see K_PLUGIN_FACTORY_WITH_JSON (macro defined in KPluginFactory)
0078  *
0079  * @since 5.0
0080  */
0081 class KSERVICE_EXPORT KPluginTrader
0082 {
0083 public:
0084     /**
0085      * Standard destructor
0086      */
0087     ~KPluginTrader();
0088 
0089     /**
0090      * The main function in the KPluginTrader class.
0091      *
0092      * It will return a list of plugins that match your specifications. Required parameter is the
0093      * service type and subdirectory. This method will append the subDirectory to every path found
0094      * in QCoreApplication::libraryPaths(), append the subDirectory parameter, and search through
0095      * the plugin's metadata
0096      *
0097      * KPluginTrader exclusively searches within the plugin binaries' metadata
0098      * (via QPluginLoader::metaData()). It does not search these directories recursively.
0099      *
0100      * The constraint parameter is used to limit the possible choices returned based on the
0101      * constraints you give it.
0102      *
0103      * The @p constraint language is rather full.  The most common
0104      * keywords are AND, OR, NOT, IN, and EXIST, all used in an
0105      * almost spoken-word form.  An example is:
0106      * \code
0107      * (Type == 'Service') and (('KParts/ReadOnlyPart' in ServiceTypes) or (exist Exec))
0108      * \endcode
0109      *
0110      * If you want to load a list of plugins from a specific subdirectory, you can do the following:
0111      *
0112      * \code
0113      *
0114      * const KPluginInfo::List plugins = KPluginTrader::self()->query("plasma/engines");
0115      *
0116      * for (const KPluginInfo &info : plugins) {
0117      *      KPluginLoader loader(info.libraryPath());
0118      *      const QVariantList argsWithMetaData = QVariantList() << loader.metaData().toVariantMap();
0119      *      // In many cases, plugins are actually based on KPluginFactory, this is how that works:
0120      *      KPluginFactory* factory = loader.factory();
0121      *      if (factory) {
0122      *          Engine* component = factory->create<Engine>(parent, argsWithMetaData);
0123      *          if (component) {
0124      *              // Do whatever you want to do with the resulting object
0125      *          }
0126      *      }
0127      *      // Otherwise, just use the normal QPluginLoader methods
0128      *      Engine *myengine = qobject_cast<Engine*>(loader.instance());
0129      *      if (myengine) {
0130      *          // etc. ...
0131      *      }
0132      * }
0133      * \endcode
0134      *
0135      * If you have a specific query for just one plugin, use the createInstanceFromQuery method.
0136      *
0137      * The keys used in the query (Type, ServiceType, Exec) are all fields found in the .json files
0138      * which are compiled into the plugin binaries.
0139      *
0140      * @param subDirectory The subdirectory under the Qt plugin path
0141      * @param servicetype A service type like 'KMyApp/Plugin' or 'KFilePlugin'
0142      * @param constraint  A constraint to limit the choices returned, QString() to
0143      *                    get all services of the given @p servicetype
0144      *
0145      * @return A list of services that satisfy the query
0146      * @see http://techbase.kde.org/Development/Tutorials/Services/Traders#The_KTrader_Query_Language
0147      * @deprecated since 5.82, use KPluginMetaData::findPlugins.
0148      */
0149     KSERVICE_DEPRECATED_VERSION(5, 82, "Use KPluginMetaData::findPlugins")
0150     KPluginInfo::List query(const QString &subDirectory, const QString &serviceType = QString(), const QString &constraint = QString());
0151 
0152     /**
0153      * This is a static pointer to the KPluginTrader singleton.
0154      *
0155      * You will need to use this to access the KPluginTrader functionality since the
0156      * constructors are protected.
0157      *
0158      * @deprecated since 5.82, use KPluginMetaData and KPluginFactory.
0159      *
0160      * @return Static KPluginTrader instance
0161      */
0162     KSERVICE_DEPRECATED_VERSION(5, 82, "Use KPluginMetaData and KPluginFactory")
0163     static KPluginTrader *self();
0164 
0165     /**
0166      * Get a plugin from a trader query
0167      *
0168      * Example:
0169      * \code
0170      * KMyAppPlugin* plugin = KPluginTrader::createInstanceFromQuery<KMyAppPlugin>(subDirectory, serviceType, QString(), parentObject );
0171      * if ( plugin ) {
0172      *     ....
0173      * }
0174      * \endcode
0175      *
0176      * @param subDirectory The subdirectory under the Qt plugin paths to search in
0177      * @param serviceType The type of service for which to find a plugin
0178      * @param constraint An optional constraint to pass to the trader (see KTrader)
0179      * @param parent The parent object for the part itself
0180      * @param args A list of arguments passed to the service component
0181      * @param error The string passed here will contain an error description.
0182      * @return A pointer to the newly created object or a null pointer if the
0183      *         factory was unable to create an object of the given type.
0184      * @deprecated since 5.82, use KPluginLoader API.
0185      */
0186     template<class T>
0187     KSERVICE_DEPRECATED_VERSION(5, 82, "Use KPluginLoader API")
0188     static T *createInstanceFromQuery(const QString &subDirectory,
0189                                       const QString &serviceType = QString(),
0190                                       const QString &constraint = QString(),
0191                                       QObject *parent = nullptr,
0192                                       const QVariantList &args = QVariantList(),
0193                                       QString *error = nullptr)
0194     {
0195         return createInstanceFromQuery<T>(subDirectory, serviceType, constraint, parent, nullptr, args, error);
0196     }
0197 
0198     /**
0199      * Get a plugin from a trader query
0200      *
0201      * This method works like
0202      * createInstanceFromQuery(const QString&, const QString& ,const QString&, QObject*,
0203      * const QVariantList&, QString*),
0204      * but you can specify an additional parent widget.  This is important for a KPart, for example.
0205      *
0206      * @param subDirectory The subdirectory under the Qt plugin paths to search in
0207      * @param serviceType the type of service for which to find a plugin
0208      * @param constraint an optional constraint to pass to the trader (see KTrader)
0209      * @param parent the parent object for the part itself
0210      * @param parentWidget the parent widget for the plugin
0211      * @param args A list of arguments passed to the service component
0212      * @param error The string passed here will contain an error description.
0213      * @return A pointer to the newly created object or a null pointer if the
0214      *         factory was unable to create an object of the given type.
0215      * @deprecated since 5.82, use KPluginLoader API.
0216      */
0217     template<class T>
0218     KSERVICE_DEPRECATED_VERSION(5, 82, "Use KPluginLoader API")
0219     static T *createInstanceFromQuery(const QString &subDirectory,
0220                                       const QString &serviceType,
0221                                       const QString &constraint,
0222                                       QObject *parent,
0223                                       QWidget *parentWidget,
0224                                       const QVariantList &args = QVariantList(),
0225                                       QString *error = nullptr)
0226     {
0227         Q_UNUSED(parentWidget)
0228         Q_UNUSED(args)
0229         if (error) {
0230             error->clear();
0231         }
0232         const KPluginInfo::List offers = self()->query(subDirectory, serviceType, constraint);
0233 
0234         for (const KPluginInfo &info : offers) {
0235             KPluginLoader loader(info.libraryPath());
0236             const QVariantList argsWithMetaData = QVariantList() << loader.metaData().toVariantMap();
0237             KPluginFactory *factory = loader.factory();
0238             if (factory) {
0239                 T *component = factory->create<T>(parent, argsWithMetaData);
0240                 if (component) {
0241                     return component;
0242                 }
0243             }
0244         }
0245         if (error && error->isEmpty()) {
0246             *error = QCoreApplication::translate("", "No service matching the requirements was found");
0247         }
0248         return nullptr;
0249     }
0250 
0251     KSERVICE_DEPRECATED_VERSION(5, 82, "No users.")
0252     static void applyConstraints(KPluginInfo::List &lst, const QString &constraint);
0253 
0254 private:
0255     /**
0256      * @internal
0257      */
0258     KPluginTrader();
0259 
0260     // disallow copy ctor and assignment operator
0261     KPluginTrader(const KPluginTrader &other);
0262     KPluginTrader &operator=(const KPluginTrader &rhs);
0263 
0264     KPluginTraderPrivate *const d;
0265 };
0266 #endif
0267 
0268 #endif