1/*
2 This file is part of the KDE project
3
4 SPDX-FileCopyrightText: 2014 Alex Richardson <arichardson.kde@gmail.com>
5 SPDX-FileCopyrightText: 2021 Alexander Lohnau <alexander.lohnau@gmx.de>
6
7 SPDX-License-Identifier: LGPL-2.0-or-later
8*/
9
10#ifndef KPLUGINMETADATA_H
11#define KPLUGINMETADATA_H
12
13#include "kcoreaddons_export.h"
14
15#include <QExplicitlySharedDataPointer>
16#include <QJsonObject>
17#include <QMetaType>
18#include <QString>
19#include <QStringList>
20
21#include <functional>
22
23class QPluginLoader;
24struct QStaticPlugin;
25class KPluginMetaDataPrivate;
26class KAboutPerson;
27/*!
28 \class KPluginMetaData
29 \inmodule KCoreAddons
30
31 \brief This class allows easily accessing some standardized values from the JSON metadata that
32 can be embedded into Qt plugins.
33
34 Additional plugin-specific metadata can be retrieved by
35 directly reading from the QJsonObject returned by KPluginMetaData::rawData.
36
37 For embedded metadata, you should not specify an id manually. Instead the id will
38 be derived from the file basename.
39
40 The following keys will be read from an object "KPlugin" inside the metadata JSON:
41
42 \table
43 \header
44 \li Key
45 \li Accessor function
46 \li JSON Type
47 \row
48 \li Name
49 \li name()
50 \li string
51 \row
52 \li Description
53 \li description()
54 \li string
55 \row
56 \li Icon
57 \li iconName()
58 \li string
59 \row
60 \li Authors
61 \li authors()
62 \li object array (KAboutPerson)
63 \row
64 \li Category
65 \li category()
66 \li string
67 \row
68 \li License
69 \li license()
70 \li string
71 \row
72 \li Copyright
73 \li copyrightText()
74 \li string
75 \row
76 \li Id
77 \li pluginId()
78 \li string
79 \row
80 \li Version
81 \li version()
82 \li string
83 \row
84 \li Website
85 \li website()
86 \li string
87 \row
88 \li BugReportUrl
89 \li bugReportUrl()
90 \li string
91 \row
92 \li EnabledByDefault
93 \li isEnabledByDefault()
94 \li bool
95 \row
96 \li MimeTypes
97 \li mimeTypes()
98 \li string array
99 \row
100 \li FormFactors
101 \li formFactors()
102 \li string array
103 \row
104 \li Translators
105 \li translators()
106 \li object array (KAboutPerson)
107 \row
108 \li OtherContributors
109 \li otherContributors()
110 \li object array (KAboutPerson)
111 \endtable
112
113 The Authors, Translators and OtherContributors keys are expected to be
114 list of objects that match the structure expected by KAboutPerson::fromJSON.
115
116 An example metadata json file could look like this:
117 \badcode
118 {
119 "KPlugin": {
120 "Name": "Date and Time",
121 "Description": "Date and time by timezone",
122 "Icon": "preferences-system-time",
123 "Authors": [ { "Name": "Aaron Seigo", "Email": "aseigo@kde.org" } ],
124 "Category": "Date and Time",
125 "EnabledByDefault": "true",
126 "License": "LGPL",
127 "Version": "1.0",
128 "Website": "https://plasma.kde.org/"
129 }
130 }
131 \endcode
132
133 \sa KAboutPerson::fromJSON()
134 \since 5.1
135 */
136class KCOREADDONS_EXPORT KPluginMetaData
137{
138 Q_GADGET
139
140 /*!
141 * \property KPluginMetaData::isValid
142 */
143 Q_PROPERTY(bool isValid READ isValid CONSTANT)
144
145 /*!
146 * \property KPluginMetaData::isHidden
147 */
148 Q_PROPERTY(bool isHidden READ isHidden CONSTANT)
149
150 /*!
151 * \property KPluginMetaData::fileName
152 */
153 Q_PROPERTY(QString fileName READ fileName CONSTANT)
154
155 /*!
156 * \property KPluginMetaData::rawData
157 */
158 Q_PROPERTY(QJsonObject rawData READ rawData CONSTANT)
159
160 /*!
161 * \property KPluginMetaData::name
162 */
163 Q_PROPERTY(QString name READ name CONSTANT)
164
165 /*!
166 * \property KPluginMetaData::description
167 */
168 Q_PROPERTY(QString description READ description CONSTANT)
169
170 /*!
171 * \property KPluginMetaData::authors
172 */
173 Q_PROPERTY(QList<KAboutPerson> authors READ authors CONSTANT)
174
175 /*!
176 * \property KPluginMetaData::translators
177 */
178 Q_PROPERTY(QList<KAboutPerson> translators READ translators CONSTANT)
179
180 /*!
181 * \property KPluginMetaData::otherContributors
182 */
183 Q_PROPERTY(QList<KAboutPerson> otherContributors READ otherContributors CONSTANT)
184
185 /*!
186 * \property KPluginMetaData::category
187 */
188 Q_PROPERTY(QString category READ category CONSTANT)
189
190 /*!
191 * \property KPluginMetaData::iconName
192 */
193 Q_PROPERTY(QString iconName READ iconName CONSTANT)
194
195 /*!
196 * \property KPluginMetaData::license
197 */
198 Q_PROPERTY(QString license READ license CONSTANT)
199
200 /*!
201 * \property KPluginMetaData::licenseText
202 */
203 Q_PROPERTY(QString licenseText READ licenseText CONSTANT)
204
205 /*!
206 * \property KPluginMetaData::copyrightText
207 */
208 Q_PROPERTY(QString copyrightText READ copyrightText CONSTANT)
209
210 /*!
211 * \property KPluginMetaData::pluginId
212 */
213 Q_PROPERTY(QString pluginId READ pluginId CONSTANT)
214
215 /*!
216 * \property KPluginMetaData::version
217 */
218 Q_PROPERTY(QString version READ version CONSTANT)
219
220 /*!
221 * \property KPluginMetaData::website
222 */
223 Q_PROPERTY(QString website READ website CONSTANT)
224
225 /*!
226 * \property KPluginMetaData::bugReportUrl
227 */
228 Q_PROPERTY(QString bugReportUrl READ bugReportUrl CONSTANT)
229
230 /*!
231 * \property KPluginMetaData::mimeTypes
232 */
233 Q_PROPERTY(QStringList mimeTypes READ mimeTypes CONSTANT)
234
235 /*!
236 * \property KPluginMetaData::formFactors
237 */
238 Q_PROPERTY(QStringList formFactors READ formFactors CONSTANT)
239
240 /*!
241 * \property KPluginMetaData::isEnabledByDefault
242 */
243 Q_PROPERTY(bool isEnabledByDefault READ isEnabledByDefault CONSTANT)
244
245public:
246 /*!
247 * Options for creating a KPluginMetaData object.
248 * \since 5.91
249 *
250 * \value AllowEmptyMetaData Plugins with empty metaData are considered valid
251 * \value [since 6.0] CacheMetaData If KCoreAddons should keep metadata in cache. This makes querying the namespace again faster. Consider using
252 * this if you need revalidation of plugins
253 *
254 */
255 enum KPluginMetaDataOption {
256 AllowEmptyMetaData = 1,
257 CacheMetaData = 2,
258 };
259 Q_DECLARE_FLAGS(KPluginMetaDataOptions, KPluginMetaDataOption)
260 Q_FLAG(KPluginMetaDataOption)
261
262 /*! Creates an invalid KPluginMetaData instance */
263 KPluginMetaData();
264
265 /*!
266 * Reads the plugin metadata from a QPluginLoader instance. You must call QPluginLoader::setFileName()
267 * or use the appropriate constructor on \a loader before calling this.
268 *
269 * \a options Whether or not plugins without JSON metadata are considered valid.
270 */
271 KPluginMetaData(const QPluginLoader &loader, KPluginMetaDataOptions options = {});
272
273 /*!
274 * Reads the plugin metadata from a plugin which can be loaded from \a file.
275 *
276 * Platform-specific library suffixes may be omitted since \a file will be resolved
277 * using the same logic as QPluginLoader.
278 *
279 * \a options Whether or not plugins without JSON metadata are considered valid.
280 *
281 * \sa QPluginLoader::setFileName()
282 */
283 KPluginMetaData(const QString &pluginFile, KPluginMetaDataOptions options = {});
284
285 /*!
286 * Creates a KPluginMetaData from a QJsonObject holding the metadata and a file name
287 * This can be used if the data is not retrieved from a Qt C++ plugin library but from some
288 * other source.
289 *
290 * \a metaData the JSON metadata to use for this object
291 *
292 * \a pluginFile the file that the plugin can be loaded from
293 *
294 * \since 6.0
295 */
296 KPluginMetaData(const QJsonObject &metaData, const QString &fileName);
297
298 KPluginMetaData(const KPluginMetaData &);
299
300 KPluginMetaData &operator=(const KPluginMetaData &);
301
302 ~KPluginMetaData();
303
304 /*!
305 * Load a KPluginMetaData instance from a .json file. Unlike the constructor with a single file argument,
306 * this ensure that only JSON format plugins are loaded and any other type is rejected.
307 *
308 * \a jsonFile the .json file to load
309 *
310 * \since 5.91
311 */
312 static KPluginMetaData fromJsonFile(const QString &jsonFile);
313
314 /*!
315 * \a directory The directory to search for plugins. If a relative path is given for \a directory,
316 * all entries of QCoreApplication::libraryPaths() will be checked with \a directory appended as a
317 * subdirectory. If an absolute path is given only that directory will be searched.
318 *
319 * \note Check if the returned KPluginMetaData is valid before continuing to use it.
320 *
321 * \a pluginId The Id of the plugin. The id should be the same as the filename, see KPluginMetaData::pluginId()
322 *
323 * \a options Whether or not plugins without JSON metadata are considered valid.
324 *
325 * \since 5.84
326 */
327 static KPluginMetaData findPluginById(const QString &directory, const QString &pluginId, KPluginMetaDataOptions options = {});
328
329 /*!
330 * Find all plugins inside \a directory that satisfy a filter.
331 *
332 * \a directory The directory to search for plugins. If a relative path is given for \a directory,
333 * all entries of QCoreApplication::libraryPaths() will be checked with \a directory appended as a
334 * subdirectory. If an absolute path is given only that directory will be searched.
335 *
336 * \a filter a callback function that returns \c true if the found plugin should be loaded
337 * and \c false if it should be skipped. If this argument is omitted all plugins will be loaded.
338 *
339 * \a options Whether or not plugins without JSON metadata are considered valid.
340 *
341 * Returns all plugins found in \a directory that fulfill the constraints of \a filter
342 * \since 5.86
343 */
344 static QList<KPluginMetaData>
345 findPlugins(const QString &directory, std::function<bool(const KPluginMetaData &)> filter = {}, KPluginMetaDataOptions options = {});
346
347 /*!
348 * Returns whether this object holds valid information about a plugin.
349 *
350 * If this is \c true pluginId() will return a non-empty string.
351 */
352 bool isValid() const;
353
354 /*!
355 * Returns whether this object should be hidden
356 *
357 * \since 5.8
358 */
359 bool isHidden() const;
360
361 /*!
362 * Returns the path to the plugin.
363 *
364 * When the KPluginMetaData(QJsonObject, QString) constructor is used, the string is not modified.
365 * Otherwise, the path is resolved using QPluginLoader.
366 * For static plugins the fileName is the namespace and pluginId concatenated.
367 *
368 * \note It is not guaranteed that this is a valid path to a shared library (i.e. loadable
369 * by QPluginLoader) since the metadata could also refer to a non-C++ plugin.
370 */
371 QString fileName() const;
372
373 /*!
374 * Returns the full metadata stored inside the plugin file.
375 */
376 QJsonObject rawData() const;
377
378 /*!
379 * Returns the user visible name of the plugin.
380 */
381 QString name() const;
382
383 /*!
384 * Returns a short description of the plugin.
385 */
386 QString description() const;
387
388 /*!
389 * Returns the author(s) of this plugin.
390 */
391 QList<KAboutPerson> authors() const;
392
393 /*!
394 * Returns the translator(s) of this plugin.
395 *
396 * \since 5.18
397 */
398 QList<KAboutPerson> translators() const;
399
400 /*!
401 * Returns a list of people that contributed to this plugin (other than the authors and translators).
402 *
403 * \since 5.18
404 */
405 QList<KAboutPerson> otherContributors() const;
406
407 /*!
408 * Returns the categories of this plugin (e.g. "playlist/skin").
409 */
410 QString category() const;
411
412 /*!
413 * Returns the icon name for this plugin
414 * \sa QIcon::fromTheme()
415 */
416 QString iconName() const;
417
418 /*!
419 * Returns the short license identifier (e.g. LGPL).
420 *
421 * See KAboutLicense::byKeyword() for retrieving the full license information
422 */
423 QString license() const;
424
425 /*!
426 * Returns the text of the license, equivalent to KAboutLicense::byKeyword(license()).text()
427 *
428 * \since 5.73
429 */
430 QString licenseText() const;
431
432 /*!
433 * Returns a short copyright statement
434 *
435 * \since 5.18
436 */
437 QString copyrightText() const;
438
439 /*!
440 * Returns the unique identifier within the namespace of the plugin
441 *
442 * For C++ plugins, this ID is derived from the filename.
443 * It should not be set in the metadata explicitly.
444 *
445 * When using KPluginMetaData::fromJsonFile or KPluginMetaData(QJsonObject, QString),
446 * the "Id" of the "KPlugin" object will be used. If unset, it will be derived
447 * from the filename.
448 */
449 QString pluginId() const;
450
451 /*!
452 * Returns the version of the plugin.
453 */
454 QString version() const;
455
456 /*!
457 * Returns the website of the plugin.
458 */
459 QString website() const;
460
461 /*!
462 * Returns the website where people can report a bug found in this plugin
463 * \since 5.99
464 */
465 QString bugReportUrl() const;
466
467 /*!
468 * Returns a list of MIME types this plugin can handle (e.g. "application/pdf", "image/png", etc.)
469 * \since 5.16
470 */
471 QStringList mimeTypes() const;
472
473 /*!
474 * Returns true if this plugin can handle the given mimetype
475 * This is more accurate than mimeTypes().contains(mimeType) because it also
476 * takes MIME type inheritance into account.
477 * \since 5.66
478 */
479 bool supportsMimeType(const QString &mimeType) const;
480
481 /*!
482 * Returns A string list of formfactors this plugin is useful for, e.g. desktop, handset or mediacenter.
483 * The keys for this are not formally defined, though the above-mentioned values should be used when applicable.
484 *
485 * \since 5.12
486 */
487 QStringList formFactors() const;
488
489 /*!
490 * Returns whether the plugin should be enabled by default.
491 * This is only a recommendation, applications can ignore this value if they want to.
492 */
493 bool isEnabledByDefault() const;
494
495 /*!
496 * Returns \c true if the plugin is enabled in \a config, otherwise returns isEnabledByDefault().
497 * This can be used in conjunction with KPluginWidget.
498 *
499 * The \a config param should be a KConfigGroup object, because KCoreAddons can not depend
500 * on KConfig directly, this parameter is a template.
501 *
502 * \a config KConfigGroup where the enabled state is stored
503 *
504 * \since 5.89
505 */
506 template<typename T>
507 bool isEnabled(const T &config) const
508 {
509 Q_ASSERT(config.isValid());
510 return config.readEntry(pluginId() + QLatin1String("Enabled"), isEnabledByDefault());
511 }
512
513 /*!
514 * Returns the string value for \a key from the metadata or \a defaultValue if the key does not exist
515 *
516 * if QString is not the correct type for \a key you should use the other overloads or KPluginMetaData::rawData
517 */
518 QString value(QStringView key, const QString &defaultValue = QString()) const;
519 QString value(const QString &key, const QString &defaultValue = QString()) const; // TODO KF7: remove
520 QString value(const QString &key, const char *ch) const = delete;
521
522 /*!
523 * \overload
524 * \since 5.88
525 */
526 bool value(QStringView key, bool defaultValue) const;
527 bool value(const QString &key, bool defaultValue) const; // TODO KF7: remove
528
529 /*!
530 * \overload
531 * \since 5.88
532 */
533 int value(QStringView key, int defaultValue) const;
534 int value(const QString &key, int defaultValue) const; // TODO KF7: remove
535
536 /*! Returns the value for \a key from the metadata or \a defaultValue if the key does not exist.
537 * If the type of \a key is string, a list containing just that string will be returned.
538 * If the type is array, the list will contain one entry for each array member.
539 * \overload
540 * \since 5.88
541 */
542 QStringList value(QStringView key, const QStringList &defaultValue) const;
543 QStringList value(const QString &key, const QStringList &defaultValue) const; // TODO KF7: remove
544
545 /*!
546 *
547 */
548 bool operator==(const KPluginMetaData &other) const;
549
550 inline bool operator!=(const KPluginMetaData &other) const
551 {
552 return !(*this == other);
553 }
554
555 /*!
556 * Returns true if the instance represents a static plugin
557 *
558 * \note for loading plugin the plugin independently of it being static/dynamic
559 * use KPluginFactory::loadFactory or KPluginFactory::instantiatePlugin.
560 * \since 5.89
561 */
562 bool isStaticPlugin() const;
563
564private:
565 KCOREADDONS_NO_EXPORT QStaticPlugin staticPlugin() const;
566 KCOREADDONS_NO_EXPORT QString requestedFileName() const;
567
568 QExplicitlySharedDataPointer<KPluginMetaDataPrivate> d;
569 friend class KPluginFactory;
570 friend class KPluginMetaDataPrivate;
571};
572
573inline size_t qHash(const KPluginMetaData &md, size_t seed)
574{
575 return qHash(key: md.pluginId(), seed);
576}
577
578/*!
579 * \since 6.0
580 * \relates KPluginMetaData
581 */
582KCOREADDONS_EXPORT QDebug operator<<(QDebug debug, const KPluginMetaData &metaData);
583
584Q_DECLARE_TYPEINFO(KPluginMetaData, Q_RELOCATABLE_TYPE);
585Q_DECLARE_OPERATORS_FOR_FLAGS(KPluginMetaData::KPluginMetaDataOptions)
586
587#endif // KPLUGINMETADATA_H
588

source code of kcoreaddons/src/lib/plugin/kpluginmetadata.h