File indexing completed on 2024-05-12 03:54:57

0001 /*
0002     This file is part of the KDE project
0003 
0004     SPDX-FileCopyrightText: 2014 Alex Richardson <arichardson.kde@gmail.com>
0005     SPDX-FileCopyrightText: 2021 Alexander Lohnau <alexander.lohnau@gmx.de>
0006 
0007     SPDX-License-Identifier: LGPL-2.0-or-later
0008 */
0009 
0010 #ifndef KPLUGINMETADATA_H
0011 #define KPLUGINMETADATA_H
0012 
0013 #include "kcoreaddons_export.h"
0014 
0015 #include <QExplicitlySharedDataPointer>
0016 #include <QJsonObject>
0017 #include <QMetaType>
0018 #include <QString>
0019 #include <QStringList>
0020 
0021 #include <functional>
0022 
0023 class QPluginLoader;
0024 class QStaticPlugin;
0025 class KPluginMetaDataPrivate;
0026 class KAboutPerson;
0027 /**
0028  * @class KPluginMetaData kpluginmetadata.h KPluginMetaData
0029  *
0030  * This class allows easily accessing some standardized values from the JSON metadata that
0031  * can be embedded into Qt plugins. Additional plugin-specific metadata can be retrieved by
0032  * directly reading from the QJsonObject returned by KPluginMetaData::rawData().
0033  *
0034  * For embedded metadata, you should not specify an id manually. Instead the id will
0035  * be derived from the file basename.
0036  *
0037  * The following keys will be read from an object "KPlugin" inside the metadata JSON:
0038  *
0039  * Key                | Accessor function    | JSON Type
0040  * -------------------| -------------------- | ---------------------
0041  * Name               | name()               | string
0042  * Description        | description()        | string
0043  * Icon               | iconName()           | string
0044  * Authors            | authors()            | object array (KAboutPerson)
0045  * Category           | category()           | string
0046  * License            | license()            | string
0047  * Copyright          | copyrightText()      | string
0048  * Id                 | pluginId()           | string
0049  * Version            | version()            | string
0050  * Website            | website()            | string
0051  * BugReportUrl       | bugReportUrl()       | string
0052  * EnabledByDefault   | isEnabledByDefault() | bool
0053  * MimeTypes          | mimeTypes()          | string array
0054  * FormFactors        | formFactors()        | string array
0055  * Translators        | translators()        | object array (KAboutPerson)
0056  * OtherContributors  | otherContributors()  | object array (KAboutPerson)
0057  *
0058  * The Authors, Translators and OtherContributors keys are expected to be
0059  * list of objects that match the structure expected by KAboutPerson::fromJSON().
0060  *
0061  * An example metadata json file could look like this:
0062  * @verbatim
0063    {
0064      "KPlugin": {
0065         "Name": "Date and Time",
0066         "Description": "Date and time by timezone",
0067         "Icon": "preferences-system-time",
0068         "Authors": [ { "Name": "Aaron Seigo", "Email": "aseigo@kde.org" } ],
0069         "Category": "Date and Time",
0070         "EnabledByDefault": "true",
0071         "License": "LGPL",
0072         "Version": "1.0",
0073         "Website": "https://plasma.kde.org/"
0074      }
0075    }
0076    @endverbatim
0077  *
0078  * @sa KAboutPerson::fromJSON()
0079  * @since 5.1
0080  */
0081 class KCOREADDONS_EXPORT KPluginMetaData
0082 {
0083     Q_GADGET
0084     Q_PROPERTY(bool isValid READ isValid CONSTANT)
0085     Q_PROPERTY(bool isHidden READ isHidden CONSTANT)
0086     Q_PROPERTY(QString fileName READ fileName CONSTANT)
0087     Q_PROPERTY(QJsonObject rawData READ rawData CONSTANT)
0088     Q_PROPERTY(QString name READ name CONSTANT)
0089     Q_PROPERTY(QString description READ description CONSTANT)
0090     Q_PROPERTY(QList<KAboutPerson> authors READ authors CONSTANT)
0091     Q_PROPERTY(QList<KAboutPerson> translators READ translators CONSTANT)
0092     Q_PROPERTY(QList<KAboutPerson> otherContributors READ otherContributors CONSTANT)
0093     Q_PROPERTY(QString category READ category CONSTANT)
0094     Q_PROPERTY(QString iconName READ iconName CONSTANT)
0095     Q_PROPERTY(QString license READ license CONSTANT)
0096     Q_PROPERTY(QString licenseText READ licenseText CONSTANT)
0097     Q_PROPERTY(QString copyrightText READ copyrightText CONSTANT)
0098     Q_PROPERTY(QString pluginId READ pluginId CONSTANT)
0099     Q_PROPERTY(QString version READ version CONSTANT)
0100     Q_PROPERTY(QString website READ website CONSTANT)
0101     Q_PROPERTY(QString bugReportUrl READ bugReportUrl CONSTANT)
0102     Q_PROPERTY(QStringList mimeTypes READ mimeTypes CONSTANT)
0103     Q_PROPERTY(QStringList formFactors READ formFactors CONSTANT)
0104     Q_PROPERTY(bool isEnabledByDefault READ isEnabledByDefault CONSTANT)
0105 
0106 public:
0107     /**
0108      * Options for creating a KPluginMetaData object.
0109      * @since 5.91
0110      */
0111     enum KPluginMetaDataOption {
0112         AllowEmptyMetaData = 1, ///< Plugins with empty metaData are considered valid
0113         /**
0114          * If KCoreAddons should keep metadata in cache. This makes querying the namespace again faster. Consider using this if you need revalidation of plugins
0115          * @since 6.0
0116          */
0117         CacheMetaData = 2,
0118     };
0119     Q_DECLARE_FLAGS(KPluginMetaDataOptions, KPluginMetaDataOption)
0120     Q_FLAG(KPluginMetaDataOption)
0121 
0122     /** Creates an invalid KPluginMetaData instance */
0123     KPluginMetaData();
0124 
0125     /**
0126      * Reads the plugin metadata from a QPluginLoader instance. You must call QPluginLoader::setFileName()
0127      * or use the appropriate constructor on @p loader before calling this.
0128      * @param option Added in 6.0, see enum docs
0129      */
0130     KPluginMetaData(const QPluginLoader &loader, KPluginMetaDataOptions options = {});
0131 
0132     /**
0133      * Reads the plugin metadata from a plugin which can be loaded from @p file.
0134      *
0135      * Platform-specific library suffixes may be omitted since @p file will be resolved
0136      * using the same logic as QPluginLoader.
0137      *
0138      * @see QPluginLoader::setFileName()
0139      */
0140     KPluginMetaData(const QString &pluginFile, KPluginMetaDataOptions options = {});
0141 
0142     /**
0143      * Creates a KPluginMetaData from a QJsonObject holding the metadata and a file name
0144      * This can be used if the data is not retrieved from a Qt C++ plugin library but from some
0145      * other source.
0146      *
0147      * @param metaData the JSON metadata to use for this object
0148      * @param pluginFile the file that the plugin can be loaded from
0149      *
0150      * @since 6.0
0151      */
0152     KPluginMetaData(const QJsonObject &metaData, const QString &fileName);
0153 
0154     /**
0155      * Copy contructor
0156      */
0157     KPluginMetaData(const KPluginMetaData &);
0158     /**
0159      * Copy assignment
0160      */
0161     KPluginMetaData &operator=(const KPluginMetaData &);
0162     /**
0163      * Destructor
0164      */
0165     ~KPluginMetaData();
0166 
0167     /**
0168      * Load a KPluginMetaData instance from a .json file. Unlike the constructor with a single file argument,
0169      * this ensure that only JSON format plugins are loaded and any other type is rejected.
0170      *
0171      * @param jsonFile the .json file to load
0172      * @since 5.91
0173      */
0174     static KPluginMetaData fromJsonFile(const QString &jsonFile);
0175 
0176     /**
0177      * @param directory The directory to search for plugins. If a relative path is given for @p directory,
0178      * all entries of QCoreApplication::libraryPaths() will be checked with @p directory appended as a
0179      * subdirectory. If an absolute path is given only that directory will be searched.
0180      * @note Check if the returned KPluginMetaData is valid before continuing to use it.
0181      *
0182      * @param pluginId The Id of the plugin. The id should be the same as the filename, see KPluginMetaData::pluginId()
0183      * @param option Added in 6.0, see enum docs
0184      * @since 5.84
0185      */
0186     static KPluginMetaData findPluginById(const QString &directory, const QString &pluginId, KPluginMetaDataOptions options = {});
0187 
0188     /**
0189      * Find all plugins inside @p directory. Only plugins which have JSON metadata will be considered.
0190      *
0191      * @param directory The directory to search for plugins. If a relative path is given for @p directory,
0192      * all entries of QCoreApplication::libraryPaths() will be checked with @p directory appended as a
0193      * subdirectory. If an absolute path is given only that directory will be searched.
0194      *
0195      * @param filter a callback function that returns @c true if the found plugin should be loaded
0196      * and @c false if it should be skipped. If this argument is omitted all plugins will be loaded
0197      * @param option Weather or not allow plugins with empty metadata to be considered valid
0198      *
0199      * @return all plugins found in @p directory that fulfil the constraints of @p filter
0200      * @since 5.86
0201      */
0202     static QList<KPluginMetaData>
0203     findPlugins(const QString &directory, std::function<bool(const KPluginMetaData &)> filter = {}, KPluginMetaDataOptions options = {});
0204 
0205     /**
0206      * @return whether this object holds valid information about a plugin.
0207      * If this is @c true pluginId() will return a non-empty string.
0208      */
0209     bool isValid() const;
0210 
0211     /**
0212      * @return whether this object should be hidden
0213      *
0214      * @since 5.8
0215      */
0216     bool isHidden() const;
0217 
0218     /**
0219      * @return the path to the plugin.
0220      * When the KPluginMetaData(QJsonObject, QString) constructor is used, the string is not modified.
0221      * Otherwise, the path is resolved using QPluginLoader.
0222      * For static plugins the fileName is the namespace and pluginId concatenated
0223      *
0224      * @note It is not guaranteed that this is a valid path to a shared library (i.e. loadable
0225      * by QPluginLoader) since the metadata could also refer to a non-C++ plugin.
0226      */
0227     QString fileName() const;
0228 
0229     /**
0230      * @return the full metadata stored inside the plugin file.
0231      */
0232     QJsonObject rawData() const;
0233 
0234     /**
0235      * @return the user visible name of the plugin.
0236      */
0237     QString name() const;
0238 
0239     /**
0240      * @return a short description of the plugin.
0241      */
0242     QString description() const;
0243 
0244     /**
0245      * @return the author(s) of this plugin.
0246      */
0247     QList<KAboutPerson> authors() const;
0248 
0249     /**
0250      * @return the translator(s) of this plugin.
0251      *
0252      * @since 5.18
0253      */
0254     QList<KAboutPerson> translators() const;
0255 
0256     /**
0257      * @return a list of people that contributed to this plugin (other than the authors and translators).
0258      *
0259      * @since 5.18
0260      */
0261     QList<KAboutPerson> otherContributors() const;
0262 
0263     /**
0264      * @return the categories of this plugin (e.g. "playlist/skin").
0265      */
0266     QString category() const;
0267 
0268     /**
0269      * @return the icon name for this plugin
0270      * @see QIcon::fromTheme()
0271      */
0272     QString iconName() const;
0273 
0274     /**
0275      * @return the short license identifier (e.g. LGPL).
0276      * @see KAboutLicense::byKeyword() for retrieving the full license information
0277      */
0278     QString license() const;
0279 
0280     /**
0281      * @return the text of the license, equivalent to KAboutLicense::byKeyword(license()).text()
0282      * @since 5.73
0283      */
0284     QString licenseText() const;
0285 
0286     /**
0287      * @return a short copyright statement
0288      *
0289      * @since 5.18
0290      */
0291     QString copyrightText() const;
0292 
0293     /**
0294      * @return the unique identifier within the namespace of the plugin
0295      *
0296      * For C++ plugins, this ID is derived from the filename.
0297      * It should not be set in the metadata explicitly.
0298      *
0299      * When using @ref KPluginMetaData::fromJsonFile or @ref KPluginMetaData(QJsonObject, QString),
0300      * the "Id" of the "KPlugin" object will be used. If unset, it will be derived
0301      * from the filename.
0302      */
0303     QString pluginId() const;
0304 
0305     /**
0306      * @return the version of the plugin.
0307      */
0308     QString version() const;
0309 
0310     /**
0311      * @return the website of the plugin.
0312      */
0313     QString website() const;
0314 
0315     /**
0316      * @return the website where people can report a bug found in this plugin
0317      * @since 5.99
0318      */
0319     QString bugReportUrl() const;
0320 
0321     /**
0322      * @return a list of MIME types this plugin can handle (e.g. "application/pdf", "image/png", etc.)
0323      * @since 5.16
0324      */
0325     QStringList mimeTypes() const;
0326 
0327     /**
0328      * @return true if this plugin can handle the given mimetype
0329      * This is more accurate than mimeTypes().contains(mimeType) because it also
0330      * takes MIME type inheritance into account.
0331      * @since 5.66
0332      */
0333     bool supportsMimeType(const QString &mimeType) const;
0334 
0335     /**
0336      * @return A string list of formfactors this plugin is useful for, e.g. desktop, handset or mediacenter.
0337      * The keys for this are not formally defined, though the above-mentioned values should be used when applicable.
0338      *
0339      * @since 5.12
0340      */
0341     QStringList formFactors() const;
0342 
0343     /**
0344      * @return whether the plugin should be enabled by default.
0345      * This is only a recommendation, applications can ignore this value if they want to.
0346      */
0347     bool isEnabledByDefault() const;
0348 
0349     /**
0350      * Returns @c true if the plugin is enabled in @p config, otherwise returns isEnabledByDefault().
0351      * This can be used in conjunction with KPluginWidget.
0352      *
0353      * The @p config param should be a KConfigGroup object, because KCoreAddons can not depend
0354      * on KConfig directly, this parameter is a template.
0355      * @param config KConfigGroup where the enabled state is stored
0356      * @since 5.89
0357      */
0358     template<typename T>
0359     bool isEnabled(const T &config) const
0360     {
0361         Q_ASSERT(config.isValid());
0362         return config.readEntry(pluginId() + QLatin1String("Enabled"), isEnabledByDefault());
0363     }
0364 
0365     /**
0366      * @return the string value for @p key from the metadata or @p defaultValue if the key does not exist
0367      *
0368      * if QString is not the correct type for @p key you should use the other overloads or @ref KPluginMetaData::rawData
0369      */
0370     QString value(const QString &key, const QString &defaultValue = QString()) const;
0371     QString value(const QString &key, const char *ch) const = delete;
0372 
0373     /**
0374      * @overload
0375      * @since 5.88
0376      */
0377     bool value(const QString &key, bool defaultValue) const;
0378 
0379     /**
0380      * @overload
0381      * @since 5.88
0382      */
0383     int value(const QString &key, int defaultValue) const;
0384 
0385     /** @return the value for @p key from the metadata or @p defaultValue if the key does not exist.
0386      * If the type of @p key is string, a list containing just that string will be returned.
0387      * If the type is array, the list will contain one entry for each array member.
0388      * @overload
0389      * @since 5.88
0390      */
0391     QStringList value(const QString &key, const QStringList &defaultValue) const;
0392 
0393     /**
0394      * @return @c true if this object is equal to @p other, otherwise @c false
0395      */
0396     bool operator==(const KPluginMetaData &other) const;
0397 
0398     /**
0399      * @return @c true if this object is not equal to @p other, otherwise @c false.
0400      */
0401     inline bool operator!=(const KPluginMetaData &other) const
0402     {
0403         return !(*this == other);
0404     }
0405 
0406     /**
0407      * @note for loading plugin the plugin independently of it being static/dynamic
0408      * use @ref KPluginFactory::loadFactory or @ref KPluginFactory::instantiatePlugin.
0409      * @return true if the instance represents a static plugin
0410      * @since 5.89
0411      */
0412     bool isStaticPlugin() const;
0413 
0414 private:
0415     KCOREADDONS_NO_EXPORT QStaticPlugin staticPlugin() const;
0416     KCOREADDONS_NO_EXPORT QString requestedFileName() const;
0417 
0418     QExplicitlySharedDataPointer<KPluginMetaDataPrivate> d;
0419     friend class KPluginFactory;
0420     friend class KPluginMetaDataPrivate;
0421 };
0422 
0423 inline size_t qHash(const KPluginMetaData &md, size_t seed)
0424 {
0425     return qHash(md.pluginId(), seed);
0426 }
0427 
0428 /// @since 6.0
0429 KCOREADDONS_EXPORT QDebug operator<<(QDebug debug, const KPluginMetaData &metaData);
0430 
0431 Q_DECLARE_TYPEINFO(KPluginMetaData, Q_RELOCATABLE_TYPE);
0432 Q_DECLARE_OPERATORS_FOR_FLAGS(KPluginMetaData::KPluginMetaDataOptions)
0433 
0434 #endif // KPLUGINMETADATA_H