KCoreAddons

kpluginloader.h
1 /*
2  This file is part of the KDE project
3 
4  SPDX-FileCopyrightText: 2007 Bernhard Loos <[email protected]>
5 
6  SPDX-License-Identifier: LGPL-2.0-only
7 */
8 #ifndef KPLUGINLOADER_H
9 #define KPLUGINLOADER_H
10 
11 #include <kcoreaddons_export.h>
12 
13 #if KCOREADDONS_ENABLE_DEPRECATED_SINCE(5, 86)
14 
15 #include <kexportplugin.h>
16 
17 #include <QPluginLoader>
18 
19 #include <functional>
20 #include <memory>
21 
22 class KPluginFactory;
23 class KPluginMetaData;
24 
25 class KPluginLoaderPrivate;
26 class KPluginName;
27 
28 /**
29  * \class KPluginLoader kpluginloader.h <KPluginLoader>
30  *
31  * This class behaves largely like QPluginLoader (and, indeed, uses it
32  * internally), but additionally reads the plugin version, as provided by the
33  * K_EXPORT_PLUGIN_VERSION macro (see pluginVersion()) and provides access to a
34  * KPluginFactory instance if the plugin provides one (see factory())
35  *
36  * Note that the factory() is a typesafe convenience method that just wraps a
37  * qobject_cast on the result of QPluginLoader::instance(). Therefore, if you do
38  * not need the plugin version feature, you can (and should) just use
39  * QPluginLoader instead.
40  *
41  * Unlike QPluginLoader, it is not possible to re-use KPluginLoader for more
42  * than one plugin (it provides no setFileName method).
43  *
44  * The same notes and caveats that apply to QPluginLoader also apply to
45  * KPluginLoader.
46  *
47  * Sample code:
48  * \code
49  * KPluginLoader loader( ...library or kservice... );
50  * KPluginFactory* factory = loader.factory();
51  * if (!factory) {
52  * qWarning() << "Error loading plugin:" << loader.errorString();
53  * } else {
54  * MyInterface* obj = factory->create<MyInterface>();
55  * if (!obj) {
56  * qWarning() << "Error creating object";
57  * }
58  * }
59  * \endcode
60  *
61  * \see KPluginFactory
62  *
63  * \author Bernhard Loos <[email protected]>
64  * @deprecated Since 5.86, the @p findPluginsById, @p findPlugins and @p factory methods have been imported to @ref KPluginMetaData.
65  * Check the deprecating messages of the other search related methods for porting instructions.
66  * The methods which are exclusively used to work around QTBUG-39642 are
67  * deprecated in favour of using QPluginLoader directly. With Qt 5.15 this bug has been fixed.
68  */
69 class KCOREADDONS_EXPORT KPluginLoader : public QObject
70 {
71  Q_OBJECT
72  Q_PROPERTY(QString fileName READ fileName)
73  Q_PROPERTY(QLibrary::LoadHints loadHints READ loadHints WRITE setLoadHints)
74  Q_PROPERTY(QString pluginName READ pluginName)
75 #if KCOREADDONS_ENABLE_DEPRECATED_SINCE(5, 84)
76  Q_PROPERTY(quint32 pluginVersion READ pluginVersion)
77 #endif
78 public:
79  /**
80  * Load a plugin by name.
81  *
82  * This should be the name of the plugin object file, without any suffix
83  * (like .so or .dll). Plugin object files should not have a 'lib' prefix.
84  *
85  * fileName() will be empty if the plugin could not be found.
86  *
87  * \param plugin The name of the plugin.
88  * \param parent A parent object.
89  */
90  explicit KPluginLoader(const QString &plugin, QObject *parent = nullptr);
91 
92  /**
93  * Load a plugin by name.
94  *
95  * This constructor behaves exactly the same as
96  * KPluginLoader(const QString&,QObject*). It allows any class that can be
97  * cast to KPluginName (such as KService) to be passed to KPluginLoader.
98  *
99  * \param name The name of the plugin.
100  * \param parent A parent object.
101  */
102  explicit KPluginLoader(const KPluginName &name, QObject *parent = nullptr);
103 
104  /**
105  * Destroys the plugin loader.
106  *
107  * Unless unload() was called explicitly, the plugin stays in memory until
108  * the application terminates.
109  */
110  ~KPluginLoader() override;
111 
112  /**
113  * Returns the factory object of the plugin.
114  *
115  * This is typically created by one of the KPluginFactory macros.
116  * Internally, this uses QPluginLoader::instance(), and the same
117  * behaviours apply.
118  *
119  * Since KF 5.77, the factory will have the metadata set fetched from
120  * any JSON metadata that is embedded into the plugin binary.
121  *
122  * \returns The factory of the plugin or @c nullptr on error.
123  * @deprecated Since 5.86, use @ref KPluginFactory::loadFactory or @ref KPluginFactory::instantiatePlugin instead
124  */
125  KCOREADDONS_DEPRECATED_VERSION(5, 86, "Use KPluginFactory::loadFactory or KPluginFactory::instantiatePlugin instead")
126  KPluginFactory *factory();
127 
128  /**
129  * Returns the name of this plugin as given to the constructor.
130  *
131  * If the KService constructor was used, this is the name of the library
132  * provided by the service.
133  *
134  * \returns The plugin name.
135  *
136  * \see fileName()
137  * @deprecated Since 5.86, use @ref KPluginMetaData::pluginId instead
138  */
139  KCOREADDONS_DEPRECATED_VERSION(5, 86, "Use KPluginMetaData::pluginId instead")
140  QString pluginName() const;
141 
142 #if KCOREADDONS_ENABLE_DEPRECATED_SINCE(5, 84)
143  /**
144  * Returns the plugin version.
145  *
146  * This will load the plugin if it is not already loaded.
147  *
148  * \returns The version given to K_EXPORT_PLUGIN_VERSION, or (quint32) -1 if
149  * the macro was not used or the plugin could not be loaded.
150  * @deprecated Since 5.84, use @ref KPluginMetaData::version() or a versioned namespace instead
151  */
152  KCOREADDONS_DEPRECATED_VERSION(5, 84, "Use KPluginMetaData::version or a versioned namespace instead")
153  quint32 pluginVersion();
154 #endif
155 
156  /**
157  * Locates a plugin.
158  *
159  * Searches for a dynamic object file in the locations KPluginLoader and
160  * QPluginLoader would search (ie: the current directory and
161  * QCoreApplication::libraryPaths()).
162  *
163  * This can be useful if you wish to use a plugin that does not conform to
164  * the Qt plugin scheme of providing a QObject that declares
165  * Q_PLUGIN_METADATA. In this case, you can find the plugin with this
166  * method, and load it with QLibrary.
167  *
168  * Note that the path is not necessarily absolute. In particular, if the
169  * plugin is found in the current directory, it will be a relative path.
170  *
171  * \param name The name of the plugin (can be a relative path; see above).
172  * This should not include a file extension (like .so or .dll).
173  * \returns The path to the plugin if it was found, or QString() if it
174  * could not be found.
175  *
176  * @since 5.0
177  * @deprecated Since 5.86, contruct a QPluginLoader and call fileName() or use KPluginMetaData::findPluginById instead
178  */
179  KCOREADDONS_DEPRECATED_VERSION(5, 86, "Contruct a QPluginLoader and call fileName() or use KPluginMetaData::findPluginById instead")
180  static QString findPlugin(const QString &name);
181 
182  /**
183  * Returns the last error.
184  *
185  * \returns The description of the last error.
186  *
187  * \see QPluginLoader::errorString()
188  * @deprecated Since 5.86, use QPluginLoader::errorString() instead
189  */
190  KCOREADDONS_DEPRECATED_VERSION(5, 86, "Use QPluginLoader::errorString() instead")
191  QString errorString() const;
192 
193  /**
194  * Returns the path of the plugin.
195  *
196  * This will be the full path of the plugin if it was found, and empty if
197  * it could not be found.
198  *
199  * \returns The full path of the plugin, or the null string if it could
200  * not be found.
201  *
202  * \see QPluginLoader::fileName(), pluginName()
203  * @deprecated Since 5.86, use QPluginLoader::fileName() instead, in case of complex query logic consider using @ref KPluginLoader::findPlugins
204  */
205  KCOREADDONS_DEPRECATED_VERSION(5, 86, "Use QPluginLoader::fileName() instead, in case of complex query logic consider using KPluginLoader::findPlugins")
206  QString fileName() const;
207 
208  /**
209  * Returns the root object of the plugin.
210  *
211  * The plugin will be loaded if necessary. If the plugin used one of the
212  * KPluginFactory macros, you should use factory() instead.
213  *
214  * \returns The plugin's root object.
215  *
216  * \see QPluginLoader::instance()
217  * @deprecated Since 5.86, use QPluginLoader::instance() instead
218  */
219  KCOREADDONS_DEPRECATED_VERSION(5, 86, "Use QPluginLoader::instance() instead")
220  QObject *instance();
221 
222  /**
223  * Determines whether the plugin is loaded.
224  *
225  * \returns @c True if the plugin is loaded, @c false otherwise.
226  *
227  * \see QPluginLoader::isLoaded()
228  * @deprecated Since 5.86, use QPluginLoader::isLoaded() instead
229  */
230  KCOREADDONS_DEPRECATED_VERSION(5, 86, "Use QPluginLoader::isLoaded() instead")
231  bool isLoaded() const;
232 
233  /**
234  * Loads the plugin.
235  *
236  * It is safe to call this multiple times; if the plugin was already loaded,
237  * it will just return @c true.
238  *
239  * Methods that require the plugin to be loaded will load it as necessary
240  * anyway, so you do not normally need to call this method.
241  *
242  * \returns @c True if the plugin was loaded successfully, @c false
243  * otherwise.
244  *
245  * \see QPluginLoader::load()
246  * @deprecated Since 5.86, use QPluginLoader::load() instead
247  */
248  KCOREADDONS_DEPRECATED_VERSION(5, 86, "Use QPluginLoader::load() instead")
249  bool load();
250 
251  /**
252  * Returns the load hints for the plugin.
253  *
254  * Determines how load() should work. See QLibrary::loadHints for more
255  * information.
256  *
257  * \returns The load hints for the plugin.
258  *
259  * \see QPluginLoader::loadHints(), setLoadHints()
260  * @deprecated Since 5.86, use QPluginLoader::loadHints() instead
261  */
262  KCOREADDONS_DEPRECATED_VERSION(5, 86, "Use QPluginLoader::loadHints() instead")
263  QLibrary::LoadHints loadHints() const;
264 
265  /**
266  * Returns the meta data for the plugin.
267  *
268  * \returns A JSON object containing the plugin's metadata, if found.
269  *
270  * \see QPluginLoader::metaData()
271  * @deprecated Since 5.86, use QPluginLoader::metaData() or @ref KPluginMetaData instead
272  */
273  KCOREADDONS_DEPRECATED_VERSION(5, 86, "Use QPluginLoader::metaData() or KPluginMetaData instead")
274  QJsonObject metaData() const;
275 
276  /**
277  * Set the load hints for the plugin.
278  *
279  * Determines how load() should work. See QLibrary::loadHints for more
280  * information.
281  *
282  * \param loadHints The load hints for the plugin.
283  *
284  * \see QPluginLoader::setLoadHints(), loadHints()
285  * @deprecated Since 5.86, use QPluginLoader::setLoadHints instead
286  */
287  KCOREADDONS_DEPRECATED_VERSION(5, 86, "Use QPluginLoader::setLoadHints instead")
288  void setLoadHints(QLibrary::LoadHints loadHints);
289 
290  /**
291  * Attempts to unload the plugin.
292  *
293  * If other instances of KPluginLoader or QPluginLoader are using the same
294  * plugin, this will fail; unloading will only happen when every instance
295  * has called unload().
296  *
297  * \returns @c True if the plugin was unloaded, @c false otherwise.
298  *
299  * \see QPluginLoader::unload(), load(), instance(), factory()
300  * @deprecated Since 5.86, use QPluginLoader::unload() instead
301  */
302  KCOREADDONS_DEPRECATED_VERSION(5, 86, "Use QPluginLoader::unload() instead")
303  bool unload();
304 
305  /**
306  * Finds and instantiates (by calling QPluginLoader::instance()) all plugins from a given
307  * directory. Only plugins which have JSON metadata will be considered. A filter can be passed
308  * which determines which of the found plugins should actually be loaded.
309  *
310  * If you use KConfig you could have a group "Plugins" in your configuration file with the
311  * plugin name as the key and true/false as the value to indicate whether the plugin should
312  * be loaded. In order to easily load all the enable plugins you could use the following code:
313  * @code
314  * KConfigGroup pluginGroup = KSharedConfig::openConfig()->group("Plugins");
315  * auto filter = [&](const KPluginMetaData &md) {
316  * if (!pluginGroup.hasKey(md.pluginName())) {
317  * return md.isEnabledByDefault();
318  * } else {
319  * return pluginGroup.readEntry(md.pluginName(), false);
320  * }
321  * };
322  * QList<QObject*> plugins = KPluginLoader::instantiatePlugins("myapp", filter);
323  * @endcode
324  *
325  * @param directory the directory to search for plugins. If a relative path is given for @p directory,
326  * all entries of QCoreApplication::libraryPaths() will be checked with @p directory appended as a
327  * subdirectory. If an absolute path is given only that directory will be searched.
328  *
329  * @param filter a callback function that returns @c true if the found plugin should be loaded
330  * and @c false if it should be skipped. If this argument is omitted all plugins will be loaded.
331  *
332  * @param parent the parent to set for the instantiated plugins, if the
333  * plugins were not already loaded.
334  *
335  * @note If the plugins have been previously loaded (via QPluginLoader,
336  * directly or due to this class) without being deleted in the meantime
337  * then they are not re-created or re-parented and will be returned using
338  * the parent they were originally created with. @sa
339  * QPluginLoader::instance().
340  *
341  * @return a list containing an instantiation of each plugin that met the filter criteria
342  *
343  * @see KPluginLoader::findPlugins()
344  *
345  * @since 5.1
346  * @deprecated Since 5.86 create instances from the KPluginMetaData::findPlugins result instead. In case
347  * you are using KPluginFactory use KPluginMetaData::factory on the returned metadata objects. Otherwise use
348  * @ref KPluginMetaData::instantiate or QPluginLoader on the returned metadata objects.
349  *
350  * @see KPluginFactory::loadFactory, KPluginFactory::instantiatePlugin
351  */
352  KCOREADDONS_DEPRECATED_VERSION(5, 86, "Create instances from the KPluginMetaData::findPlugins result instead")
353  static QList<QObject *> instantiatePlugins(const QString &directory,
354  std::function<bool(const KPluginMetaData &)> filter = std::function<bool(const KPluginMetaData &)>(),
355  QObject *parent = nullptr);
356 
357  /**
358  * Find all plugins inside @p directory. Only plugins which have JSON metadata will be considered.
359  *
360  * @param directory The directory to search for plugins. If a relative path is given for @p directory,
361  * all entries of QCoreApplication::libraryPaths() will be checked with @p directory appended as a
362  * subdirectory. If an absolute path is given only that directory will be searched.
363  *
364  * @param filter a callback function that returns @c true if the found plugin should be loaded
365  * and @c false if it should be skipped. If this argument is omitted all plugins will be loaded.
366  *
367  * @return all plugins found in @p directory that fulfil the constraints of @p filter
368  *
369  * @see KPluginLoader::instantiatePlugins()
370  *
371  * @since 5.1
372  * @deprecated Since 5.86 use @ref KPluginMetaData::findPlugins instead
373  */
374  KCOREADDONS_DEPRECATED_VERSION(5, 86, "Use KPluginMetaData::findPlugins instead")
375  static QVector<KPluginMetaData> findPlugins(const QString &directory,
376  std::function<bool(const KPluginMetaData &)> filter = std::function<bool(const KPluginMetaData &)>());
377 
378  /**
379  * Find all plugins inside @p directory with a given pluginId. Only plugins which have JSON metadata will be considered.
380  *
381  * @param directory The directory to search for plugins. If a relative path is given for @p directory,
382  * all entries of QCoreApplication::libraryPaths() will be checked with @p directory appended as a
383  * subdirectory. If an absolute path is given only that directory will be searched.
384  *
385  * @param pluginId The Id of the plugin, for example KPluginMetaData.pluginId().
386  *
387  * @return all plugins found in @p directory with the given pluginId.
388  *
389  * @see KPluginLoader::instantiatePlugins()
390  *
391  * @since 5.11
392  * @deprecated Since 5.86 use @ref KPluginMetaData::findPluginsById instead
393  */
394  KCOREADDONS_DEPRECATED_VERSION(5, 86, "Use KPluginMetaData::findPluginsById instead")
395  static QVector<KPluginMetaData> findPluginsById(const QString &directory, const QString &pluginId);
396 
397  /**
398  * Invokes @p callback for each valid plugin found inside @p directory. This is useful if
399  * your application needs to customize the behaviour of KPluginLoader::findPlugins() or
400  * KPluginLoader::instantiatePlugins().
401  *
402  * @note The files found do not necessarily contain JSON metadata and may not be loadable using K/QPluginLoader.
403  * The only guarantee made is that they are valid library file names as determined by QLibrary::isLibrary().
404  *
405  * @param directory The directory to search for plugins. If a relative path is given for @p directory,
406  * all entries of QCoreApplication::libraryPaths() will be checked with @p directory appended as a
407  * subdirectory. If an absolute path is given only that directory will be searched.
408  *
409  * @param callback This function will be invoked for each valid plugin that is found. It will receive
410  * the absolute path to the plugin as an argument
411  *
412  * @see KPluginLoader::findPlugins(), KPluginLoader::instantiatePlugins()
413  *
414  * @since 5.1
415  * @deprecated Since 5.86 use @ref KPluginMetaData::findPlugins instead. This will warn about invalid plugin
416  * metadata and only return valid results.
417  */
418  KCOREADDONS_DEPRECATED_VERSION(5, 86, "Use KPluginMetaData::findPlugins instead")
419  static void forEachPlugin(const QString &directory, std::function<void(const QString &)> callback = std::function<void(const QString &)>());
420 
421 private:
422  Q_DECLARE_PRIVATE(KPluginLoader)
424 
425  std::unique_ptr<KPluginLoaderPrivate> const d_ptr;
426 };
427 
428 /**
429  * Represents the name of a plugin intended for KPluginLoader.
430  *
431  * This exists only so that classes such as KService can provide a cast
432  * operator to allow them to be used as arguments to KPluginLoader.
433  * Unless you are implementing such a cast operator, you should never
434  * need to use this class directly.
435  */
436 // NOTE: this class is all inline, as it mainly exists for typing reasons
437 // (ie: to prevent the issues that would be caused by adding an
438 // operator QString() method to KService)
439 class KCOREADDONS_EXPORT KPluginName
440 {
441 public:
442  /**
443  * Construct a (valid) plugin name from a string.
444  *
445  * If there was an error and the name could not be determined,
446  * fromErrorString() should be used instead to construct an
447  * appropriate error message.
448  *
449  * @param name The name of the plugin; this should not be empty.
450  */
451  inline explicit KPluginName(const QString &name);
452 
453  /**
454  * The name of the plugin.
455  *
456  * @returns The string passed to the constructor if isValid() is
457  * @c true, QString() otherwise.
458  */
459  inline QString name() const;
460 
461  /**
462  * Whether the name is valid.
463  *
464  * Note that this only determines how the KPluginName was
465  * constructed, not anything about the value of the string.
466  *
467  * @returns @c true if the KPluginName(const QString&) constructor
468  * was used, @c false if fromErrorString() was used.
469  */
470  inline bool isValid() const;
471 
472  /**
473  * The error string if no name could be determined.
474  *
475  * @returns The string passed to fromErrorString() if isValid() is
476  * @c false, QString() otherwise.
477  */
478  inline QString errorString() const;
479 
480  /**
481  * Construct an invalid plugin name with an error message.
482  *
483  * When this object is passed to KPluginLoader, @p errorString
484  * will be used for KPluginLoader::errorString().
485  *
486  * @param errorString The (translated) error string.
487  */
488  static inline KPluginName fromErrorString(const QString &errorString);
489 
490 private:
491  inline KPluginName(const QString &name, bool isError);
492 
493  QString m_name;
494  bool m_isError;
495 };
496 
498  : m_name(name)
499  , m_isError(false)
500 {
501 }
502 inline KPluginName::KPluginName(const QString &name, bool isError)
503  : m_name(name)
504  , m_isError(isError)
505 {
506 }
508 {
509  return m_isError ? QString() : m_name;
510 }
511 inline bool KPluginName::isValid() const
512 {
513  return !m_isError;
514 }
516 {
517  return m_isError ? m_name : QString();
518 }
520 {
521  return KPluginName(errorString, true);
522 }
523 
524 #endif
525 #endif
Q_PROPERTY(...)
bool isValid() const
Whether the name is valid.
QString name() const
The name of the plugin.
typedef LoadHints
static KPluginName fromErrorString(const QString &errorString)
Construct an invalid plugin name with an error message.
QString errorString() const
The error string if no name could be determined.
Represents the name of a plugin intended for KPluginLoader.
Q_DISABLE_COPY(Class)
KPluginName(const QString &name)
Construct a (valid) plugin name from a string.
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Tue Nov 28 2023 04:05:52 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.