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

KDE's Doxygen guidelines are available online.