1 | /* |
2 | This file is part of the KDE project |
3 | |
4 | SPDX-FileCopyrightText: 2007 Matthias Kretz <kretz@kde.org> |
5 | SPDX-FileCopyrightText: 2007 Bernhard Loos <nhuh.put@web.de> |
6 | SPDX-FileCopyrightText: 2021-2023 Alexander Lohnau <alexander.lohnau@gmx.de> |
7 | |
8 | SPDX-License-Identifier: LGPL-2.0-or-later |
9 | */ |
10 | |
11 | #ifndef KPLUGINFACTORY_H |
12 | #define KPLUGINFACTORY_H |
13 | |
14 | #include "kcoreaddons_export.h" |
15 | #include "kpluginmetadata.h" |
16 | |
17 | #include <QObject> |
18 | #include <QVariant> |
19 | |
20 | #include <memory> |
21 | #include <type_traits> |
22 | |
23 | class QWidget; |
24 | class KPluginFactoryPrivate; |
25 | |
26 | namespace KParts |
27 | { |
28 | class Part; |
29 | } |
30 | |
31 | #define KPluginFactory_iid "org.kde.KPluginFactory" |
32 | |
33 | // Internal macro that generated the KPluginFactory subclass |
34 | #define __K_PLUGIN_FACTORY_DEFINITION(name, pluginRegistrations, ...) \ |
35 | class name : public KPluginFactory \ |
36 | { \ |
37 | Q_OBJECT \ |
38 | Q_INTERFACES(KPluginFactory) \ |
39 | Q_PLUGIN_METADATA(__VA_ARGS__) \ |
40 | public: \ |
41 | explicit name() \ |
42 | { \ |
43 | pluginRegistrations \ |
44 | } \ |
45 | ~name() { }; \ |
46 | }; |
47 | |
48 | /*! |
49 | * \macro K_PLUGIN_FACTORY |
50 | * \relates KPluginFactory |
51 | * |
52 | * Create a KPluginFactory subclass and export it as the root plugin object. |
53 | * |
54 | * \a name the name of the KPluginFactory derived class. |
55 | * |
56 | * \a pluginRegistrations code to be inserted into the constructor of the |
57 | * class. Usually a series of registerPlugin() calls. |
58 | * |
59 | * \note K_PLUGIN_FACTORY declares the subclass including a Q_OBJECT macro. |
60 | * So you need to make sure to have Qt's moc run also for the source file |
61 | * where you use the macro. E.g. in projects using CMake and it's automoc feature, |
62 | * as usual you need to have a line |
63 | * \code |
64 | * #include <myplugin.moc> |
65 | * \endcode |
66 | * in the same source file when that one has the name "myplugin.cpp". |
67 | * |
68 | * Example: |
69 | * \code |
70 | * #include <KPluginFactory> |
71 | * #include <plugininterface.h> |
72 | * |
73 | * class MyPlugin : public PluginInterface |
74 | * { |
75 | * public: |
76 | * MyPlugin(QObject *parent, const QVariantList &args) |
77 | * : PluginInterface(parent) |
78 | * {} |
79 | * }; |
80 | * |
81 | * K_PLUGIN_FACTORY(MyPluginFactory, registerPlugin<MyPlugin>();) |
82 | * |
83 | * #include <myplugin.moc> |
84 | * \endcode |
85 | * |
86 | * If you want to compile a .json file into the plugin, use K_PLUGIN_FACTORY_WITH_JSON. |
87 | * |
88 | * \sa K_PLUGIN_FACTORY_WITH_JSON |
89 | */ |
90 | #define K_PLUGIN_FACTORY(name, pluginRegistrations) __K_PLUGIN_FACTORY_DEFINITION(name, pluginRegistrations, IID KPluginFactory_iid) |
91 | |
92 | /*! |
93 | * \macro K_PLUGIN_FACTORY_WITH_JSON |
94 | * \relates KPluginFactory |
95 | * |
96 | * Create a KPluginFactory subclass and export it as the root plugin object with |
97 | * JSON metadata. |
98 | * |
99 | * This macro does the same as K_PLUGIN_FACTORY, but adds a JSON file as plugin |
100 | * metadata. See Q_PLUGIN_METADATA() for more information. |
101 | * |
102 | * \a name the name of the KPluginFactory derived class. |
103 | * |
104 | * \a pluginRegistrations code to be inserted into the constructor of the |
105 | * class. Usually a series of registerPlugin() calls. |
106 | * |
107 | * \a jsonFile name of the JSON file to be compiled into the plugin as metadata |
108 | * |
109 | * \note K_PLUGIN_FACTORY_WITH_JSON declares the subclass including a Q_OBJECT macro. |
110 | * So you need to make sure to have Qt's moc run also for the source file |
111 | * where you use the macro. E.g. in projects using CMake and its automoc feature, |
112 | * as usual you need to have a line |
113 | * \code |
114 | * #include <myplugin.moc> |
115 | * \endcode |
116 | * in the same source file when that one has the name "myplugin.cpp". |
117 | * |
118 | * Example: |
119 | * \code |
120 | * #include <KPluginFactory> |
121 | * #include <plugininterface.h> |
122 | * |
123 | * class MyPlugin : public PluginInterface |
124 | * { |
125 | * public: |
126 | * MyPlugin(QObject *parent, const KPluginMetaData &metaData, const QVariantList &args) |
127 | * : PluginInterface(parent) |
128 | * {} |
129 | * }; |
130 | * |
131 | * K_PLUGIN_FACTORY_WITH_JSON(MyPluginFactory, |
132 | * "metadata.json", |
133 | * registerPlugin<MyPlugin>(); |
134 | * ) |
135 | * |
136 | * #include <myplugin.moc> |
137 | * \endcode |
138 | * |
139 | * \sa K_PLUGIN_FACTORY |
140 | * |
141 | * \since 5.0 |
142 | */ |
143 | #define K_PLUGIN_FACTORY_WITH_JSON(name, jsonFile, pluginRegistrations) \ |
144 | __K_PLUGIN_FACTORY_DEFINITION(name, pluginRegistrations, IID KPluginFactory_iid FILE jsonFile) |
145 | |
146 | /*! |
147 | * \macro K_PLUGIN_CLASS_WITH_JSON |
148 | * \relates KPluginFactory |
149 | * |
150 | * Create a KPluginFactory subclass and export it as the root plugin object with |
151 | * JSON metadata. |
152 | * |
153 | * This macro does the same as K_PLUGIN_FACTORY_WITH_JSON, but you only have to pass the class name and the json file. |
154 | * The factory name and registerPlugin call are deduced from the class name. |
155 | * |
156 | * \code |
157 | * #include <myplugin.moc> |
158 | * \endcode |
159 | * in the same source file when that one has the name "myplugin.cpp". |
160 | * |
161 | * Example: |
162 | * \code |
163 | * #include <KPluginFactory> |
164 | * #include <plugininterface.h> |
165 | * |
166 | * class MyPlugin : public PluginInterface |
167 | * { |
168 | * public: |
169 | * MyPlugin(QObject *parent, const KPluginMetaData &metaData, const QVariantList &args) |
170 | * : PluginInterface(parent) |
171 | * {} |
172 | * }; |
173 | * |
174 | * K_PLUGIN_CLASS_WITH_JSON(MyPlugin, "metadata.json") |
175 | * |
176 | * #include <myplugin.moc> |
177 | * \endcode |
178 | * |
179 | * \sa K_PLUGIN_FACTORY_WITH_JSON |
180 | * |
181 | * \since 5.44 |
182 | */ |
183 | #ifdef KPLUGINFACTORY_PLUGIN_CLASS_INTERNAL_NAME |
184 | #define K_PLUGIN_CLASS_WITH_JSON(classname, jsonFile) \ |
185 | K_PLUGIN_FACTORY_WITH_JSON(KPLUGINFACTORY_PLUGIN_CLASS_INTERNAL_NAME, jsonFile, registerPlugin<classname>();) |
186 | #else |
187 | #define K_PLUGIN_CLASS_WITH_JSON(classname, jsonFile) K_PLUGIN_FACTORY_WITH_JSON(classname##Factory, jsonFile, registerPlugin<classname>();) |
188 | #endif |
189 | |
190 | /*! |
191 | * \macro K_PLUGIN_CLASS |
192 | * \relates KPluginFactory |
193 | * |
194 | * Creates a KPluginFactory subclass and exports it as the root plugin object. |
195 | * Unlike K_PLUGIN_CLASS_WITH_JSON, this macro does not require json meta data. |
196 | * |
197 | * This macro does the same as K_PLUGIN_FACTORY, but you only have to pass the class name. |
198 | * The factory name and registerPlugin call are deduced from the class name. |
199 | * This is also useful if you want to use static plugins, see the kcoreaddons_add_plugin CMake method. |
200 | * \since 5.90 |
201 | */ |
202 | #ifdef KPLUGINFACTORY_PLUGIN_CLASS_INTERNAL_NAME |
203 | #define K_PLUGIN_CLASS(classname) K_PLUGIN_FACTORY(KPLUGINFACTORY_PLUGIN_CLASS_INTERNAL_NAME, registerPlugin<classname>();) |
204 | #else |
205 | #define K_PLUGIN_CLASS(classname) K_PLUGIN_FACTORY(classname##Factory, registerPlugin<classname>();) |
206 | #endif |
207 | |
208 | /*! |
209 | * \class KPluginFactory |
210 | * \inmodule KCoreAddons |
211 | * |
212 | * \brief KPluginFactory provides a convenient way to provide factory-style plugins. |
213 | * |
214 | * Qt plugins provide a singleton object, but a common pattern is for plugins |
215 | * to generate as many objects of a particular type as the application requires. |
216 | * By using KPluginFactory, you can avoid implementing the factory pattern |
217 | * yourself. |
218 | * |
219 | * KPluginFactory also allows plugins to provide multiple different object |
220 | * types, indexed by keywords. |
221 | * |
222 | * The objects created by KPluginFactory must inherit QObject, and must have a |
223 | * standard constructor pattern: |
224 | * \list |
225 | * \li if the object is a KPart::Part, it must be of the form |
226 | * \code |
227 | * T(QWidget *parentWidget, QObject *parent, const QVariantList &args) |
228 | * \endcode |
229 | * or |
230 | * \code |
231 | * T(QWidget *parentWidget, QObject *parent, const KPluginMetaData &metaData, const QVariantList &args) |
232 | * \endcode |
233 | * \li if it is a QWidget, it must be of the form |
234 | * \code |
235 | * T(QWidget *parent, const QVariantList &args) |
236 | * \endcode |
237 | * or |
238 | * \code |
239 | * T(QWidget *parent, const KPluginMetaData &metaData, const QVariantList &args) |
240 | * \endcode |
241 | * \li otherwise it must be of the form |
242 | * \code |
243 | * T(QObject *parent, const QVariantList &args) |
244 | * \endcode |
245 | * or |
246 | * \code |
247 | * T(QObject *parent, const KPluginMetaData &metaData, const QVariantList &args) |
248 | * \endcode |
249 | * \endlist |
250 | * You should typically use either K_PLUGIN_CLASS() or |
251 | * K_PLUGIN_CLASS_WITH_JSON() in your plugin code to generate a factory. |
252 | * The typical pattern is: |
253 | * |
254 | * \code |
255 | * #include <KPluginFactory> |
256 | * #include <plugininterface.h> |
257 | * |
258 | * class MyPlugin : public PluginInterface |
259 | * { |
260 | * public: |
261 | * MyPlugin(QObject *parent, const QVariantList &args) |
262 | * : PluginInterface(parent) |
263 | * {} |
264 | * }; |
265 | * |
266 | * K_PLUGIN_CLASS(MyPlugin) |
267 | * #include <myplugin.moc> |
268 | * \endcode |
269 | * |
270 | * If you want to write a custom KPluginFactory not using the standard macro(s) |
271 | * you can reimplement the |
272 | * create(const char *iface, QWidget *parentWidget, QObject *parent, const QVariantList &args) |
273 | * method. |
274 | * |
275 | * Example: |
276 | * \code |
277 | * class SomeScriptLanguageFactory : public KPluginFactory |
278 | * { |
279 | * Q_OBJECT |
280 | * public: |
281 | * SomeScriptLanguageFactory() |
282 | * {} |
283 | * |
284 | * protected: |
285 | * virtual QObject *create(const char *iface, QWidget *parentWidget, QObject *parent, const QVariantList &args) |
286 | * { |
287 | * // Create an identifier based on the iface and given pluginId |
288 | * const QString identifier = QLatin1String(iface) + QLatin1Char('_') + metaData().pluginId(); |
289 | * // load scripting language module from the information in identifier and return it: |
290 | * return object; |
291 | * } |
292 | * }; |
293 | * \endcode |
294 | * |
295 | * To load the KPluginFactory from an installed plugin you can use loadFactory() and for |
296 | * directly creating a plugin instance from it instantiatePlugin() |
297 | * |
298 | */ |
299 | class KCOREADDONS_EXPORT KPluginFactory : public QObject |
300 | { |
301 | Q_OBJECT |
302 | |
303 | public: |
304 | /*! |
305 | * |
306 | */ |
307 | explicit KPluginFactory(); |
308 | |
309 | ~KPluginFactory() override; |
310 | |
311 | /*! |
312 | * \since 5.86 |
313 | * |
314 | * \value NO_PLUGIN_ERROR No error |
315 | * \value INVALID_PLUGIN The plugin could not be loaded |
316 | * \value INVALID_FACTORY The factory object could not be loaded |
317 | * \value INVALID_KPLUGINFACTORY_INSTANTIATION The target object could not be instantiated |
318 | */ |
319 | enum ResultErrorReason { |
320 | NO_PLUGIN_ERROR = 0, |
321 | INVALID_PLUGIN, |
322 | INVALID_FACTORY, |
323 | INVALID_KPLUGINFACTORY_INSTANTIATION, |
324 | }; |
325 | /*! |
326 | * \class KPluginFactory::Result |
327 | * \inmodule KCoreAddons |
328 | * Holds the result of a plugin load operation, i.e. the loaded plugin on success or information about the error on failure |
329 | * \since 5.86 |
330 | */ |
331 | template<typename T> |
332 | class Result |
333 | { |
334 | public: |
335 | /*! |
336 | * \variable KPluginFactory::Result::plugin |
337 | * \brief The loaded object, or \c nullptr if loading fails |
338 | */ |
339 | T *plugin = nullptr; |
340 | |
341 | /*! |
342 | * \variable KPluginFactory::Result::errorString |
343 | * \brief The translated, user-visible error string |
344 | */ |
345 | QString errorString; |
346 | |
347 | /*! |
348 | * \variable KPluginFactory::Result::errorText |
349 | * \brief The untranslated error text |
350 | */ |
351 | QString errorText; |
352 | |
353 | /*! |
354 | * \variable KPluginFactory::Result::errorReason |
355 | * \brief The error reason |
356 | */ |
357 | ResultErrorReason errorReason = NO_PLUGIN_ERROR; |
358 | |
359 | /*! |
360 | * |
361 | */ |
362 | explicit operator bool() const |
363 | { |
364 | return plugin != nullptr; |
365 | } |
366 | }; |
367 | |
368 | /*! |
369 | * Attempts to load the KPluginFactory from the given metadata. |
370 | * |
371 | * The errors will be logged using the kf.coreaddons debug category. |
372 | * |
373 | * \a data KPluginMetaData from which the plugin should be loaded |
374 | * |
375 | * Returns a result object which contains the plugin instance and potentially error information |
376 | * |
377 | * \since 5.86 |
378 | */ |
379 | static Result<KPluginFactory> loadFactory(const KPluginMetaData &data); |
380 | |
381 | /*! |
382 | * Attempts to load the KPluginFactory and create a T instance from the given metadata. |
383 | * |
384 | * KCoreAddons will log error messages automatically, meaning you only need to implement your |
385 | * own logging in case you want to give it more context info or have a custom category. |
386 | * |
387 | * \code |
388 | * if (auto result = KPluginFactory::instantiatePlugin<MyClass>(metaData, parent, args)) { |
389 | * // The plugin is valid and result.plugin contains the object |
390 | * } else { |
391 | * // We can access the error related properties, but result.plugin is a nullptr |
392 | * qCWarning(MYCATEGORY) << result.errorString; |
393 | * } |
394 | * \endcode |
395 | * |
396 | * If there is no extra error handling needed the plugin can be directly accessed and checked if it is a nullptr |
397 | * \code |
398 | * if (auto plugin = KPluginFactory::instantiatePlugin<MyClass>(metaData, parent, args).plugin) { |
399 | * } |
400 | * \endcode |
401 | * |
402 | * \a data KPluginMetaData from which the plugin should be loaded |
403 | * |
404 | * \a args arguments which get passed to the plugin's constructor |
405 | * |
406 | * Returns a Result object which contains the plugin instance and potentially error information |
407 | * |
408 | * \since 5.86 |
409 | */ |
410 | template<typename T> |
411 | static Result<T> instantiatePlugin(const KPluginMetaData &data, QObject *parent = nullptr, const QVariantList &args = {}) |
412 | { |
413 | Result<T> result; |
414 | KPluginFactory::Result<KPluginFactory> factoryResult = loadFactory(data); |
415 | if (!factoryResult.plugin) { |
416 | result.errorString = factoryResult.errorString; |
417 | result.errorText = factoryResult.errorText; |
418 | result.errorReason = factoryResult.errorReason; |
419 | return result; |
420 | } |
421 | T *instance = factoryResult.plugin->create<T>(parent, args); |
422 | if (!instance) { |
423 | const QLatin1String className(T::staticMetaObject.className()); |
424 | result.errorString = tr(s: "KPluginFactory could not create a %1 instance from %2" ).arg(args: className, args: data.fileName()); |
425 | result.errorText = QStringLiteral("KPluginFactory could not create a %1 instance from %2" ).arg(args: className, args: data.fileName()); |
426 | result.errorReason = INVALID_KPLUGINFACTORY_INSTANTIATION; |
427 | logFailedInstantiationMessage(T::staticMetaObject.className(), data); |
428 | } else { |
429 | result.plugin = instance; |
430 | } |
431 | return result; |
432 | } |
433 | |
434 | /*! |
435 | * Use this method to create an object. |
436 | * |
437 | * It will try to create an object which inherits T. |
438 | * |
439 | * If it has multiple choices it's not defined which object will be returned, so be careful |
440 | * to request a unique interface or use keywords. |
441 | * |
442 | * T the interface for which an object should be created. The object will inherit T. |
443 | * |
444 | * \a parent the parent of the object. If \a parent is a widget type, it will also passed |
445 | * to the parentWidget argument of the CreateInstanceFunction for the object. |
446 | * |
447 | * \a args additional arguments which will be passed to the object. |
448 | * |
449 | * Returns a pointer to the created object is returned, or \c nullptr if an error occurred. |
450 | */ |
451 | template<typename T> |
452 | T *create(QObject *parent = nullptr, const QVariantList &args = {}); |
453 | |
454 | /*! |
455 | * Use this method to create an object. It will try to create an object which inherits T |
456 | * This overload has an additional \a parentWidget argument, which is used by some plugins (e.g. Parts). |
457 | * |
458 | * T the interface for which an object should be created. The object will inherit T. |
459 | * |
460 | * \a parentWidget an additional parent widget. |
461 | * |
462 | * \a parent the parent of the object. If \a parent is a widget type, it will also passed |
463 | * to the parentWidget argument of the CreateInstanceFunction for the object. |
464 | * |
465 | * \a args additional arguments which will be passed to the object. Since 5.93 this has a default arg. |
466 | * Returns a pointer to the created object is returned, or \c nullptr if an error occurred. |
467 | */ |
468 | template<typename T> |
469 | T *create(QWidget *parentWidget, QObject *parent, const QVariantList &args = {}); |
470 | |
471 | /*! |
472 | * Returns the metadata of the plugin |
473 | * |
474 | * \since 5.77 |
475 | */ |
476 | KPluginMetaData metaData() const; |
477 | |
478 | /*! |
479 | * Set the metadata about the plugin this factory generates. |
480 | * |
481 | * \a metaData the metadata about the plugin |
482 | * |
483 | * \since 5.77 |
484 | */ |
485 | void setMetaData(const KPluginMetaData &metaData); |
486 | |
487 | protected: |
488 | /*! |
489 | * Function pointer type to a function that instantiates a plugin |
490 | * |
491 | * For plugins that don't support a KPluginMetaData parameter it is discarded |
492 | * \since 5.77 |
493 | */ |
494 | using CreateInstanceWithMetaDataFunction = QObject *(*)(QWidget *, QObject *, const KPluginMetaData &, const QVariantList &); |
495 | |
496 | /* |
497 | * This is used to detect the arguments need for the constructor of metadata-taking plugin classes. |
498 | * You can inherit it, if you want to add new classes and still keep support for the old ones. |
499 | */ |
500 | template<class impl> |
501 | struct InheritanceWithMetaDataChecker { |
502 | /// property to control the availability of the registerPlugin overload taking default values |
503 | static constexpr bool enabled = std::is_constructible<impl, QWidget *, QObject *, KPluginMetaData, QVariantList>::value // KParts |
504 | || std::is_constructible<impl, QWidget *, QObject *, KPluginMetaData>::value |
505 | || std::is_constructible<impl, QWidget *, KPluginMetaData, QVariantList>::value // QWidgets |
506 | || std::is_constructible<impl, QWidget *, KPluginMetaData>::value |
507 | || std::is_constructible<impl, QObject *, KPluginMetaData, QVariantList>::value // Nomal QObjects |
508 | || std::is_constructible<impl, QObject *, KPluginMetaData>::value; |
509 | |
510 | CreateInstanceWithMetaDataFunction createInstanceFunction(KParts::Part *) |
511 | { |
512 | return &createPartWithMetaDataInstance<impl>; |
513 | } |
514 | CreateInstanceWithMetaDataFunction createInstanceFunction(QWidget *) |
515 | { |
516 | return &createWithMetaDataInstance<impl, QWidget>; |
517 | } |
518 | CreateInstanceWithMetaDataFunction createInstanceFunction(...) |
519 | { |
520 | return &createWithMetaDataInstance<impl, QObject>; |
521 | } |
522 | }; |
523 | |
524 | /* |
525 | * This is used to detect the arguments need for the constructor of metadata-less plugin classes. |
526 | * You can inherit it, if you want to add new classes and still keep support for the old ones. |
527 | */ |
528 | template<class impl> |
529 | struct InheritanceChecker { |
530 | /// property to control the availability of the registerPlugin overload taking default values |
531 | static constexpr bool _canConstruct = std::is_constructible<impl, QWidget *, QVariantList>::value // QWidget plugin |
532 | || std::is_constructible<impl, QWidget *>::value // |
533 | || std::is_constructible<impl, QObject *, QVariantList>::value // QObject plugins |
534 | || std::is_constructible<impl, QObject *>::value; |
535 | static constexpr bool enabled = _canConstruct && !InheritanceWithMetaDataChecker<impl>::enabled; // Avoid ambiguity in case of default arguments |
536 | |
537 | CreateInstanceWithMetaDataFunction createInstanceFunction(QWidget *) |
538 | { |
539 | return &createInstance<impl, QWidget>; |
540 | } |
541 | CreateInstanceWithMetaDataFunction createInstanceFunction(...) |
542 | { |
543 | return &createInstance<impl, QObject>; |
544 | } |
545 | }; |
546 | |
547 | // Use std::enable_if_t once C++14 can be relied on |
548 | template<bool B, class T = void> |
549 | using enable_if_t = typename std::enable_if<B, T>::type; |
550 | |
551 | /*! |
552 | * Uses a default instance creation function depending on the type of interface. If the |
553 | * interface inherits from |
554 | * \c KParts::Part the function will call |
555 | * \code |
556 | * new T(QWidget *parentWidget, QObject *parent, const QVariantList &args) |
557 | * \endcode |
558 | * \c QWidget the function will call |
559 | * \code |
560 | * new T(QWidget *parent, const QVariantList &args) |
561 | * \endcode |
562 | * else the function will call |
563 | * \code |
564 | * new T(QObject *parent, const QVariantList &args) |
565 | * \endcode |
566 | * |
567 | * If those constructor methods are not callable this overload is not available. |
568 | */ |
569 | template<class T, enable_if_t<InheritanceChecker<T>::enabled, int> = 0> |
570 | void registerPlugin() |
571 | { |
572 | CreateInstanceWithMetaDataFunction instanceFunction = InheritanceChecker<T>().createInstanceFunction(static_cast<T *>(nullptr)); |
573 | registerPlugin(&T::staticMetaObject, instanceFunction); |
574 | } |
575 | |
576 | /*! |
577 | * Uses a default instance creation function depending on the type of interface. If the |
578 | * interface inherits from |
579 | * \c KParts::Part the function will call |
580 | * \code |
581 | * new T(QWidget *parentWidget, QObject *parent, const KPluginMetaData &metaData, const QVariantList &args) |
582 | * \endcode |
583 | * \c QWidget the function will call |
584 | * \code |
585 | * new T(QWidget *parent, const KPluginMetaData &metaData, const QVariantList &args) |
586 | * \endcode |
587 | * else the function will call |
588 | * \code |
589 | * new T(QObject *parent, const KPluginMetaData &metaData, const QVariantList &args) |
590 | * \endcode |
591 | * |
592 | * If those constructor methods are not callable this overload is not available. |
593 | */ |
594 | template<class T, enable_if_t<InheritanceWithMetaDataChecker<T>::enabled, int> = 0> |
595 | void registerPlugin() |
596 | { |
597 | CreateInstanceWithMetaDataFunction instanceFunction = InheritanceWithMetaDataChecker<T>().createInstanceFunction(static_cast<T *>(nullptr)); |
598 | registerPlugin(&T::staticMetaObject, instanceFunction); |
599 | } |
600 | |
601 | /*! |
602 | * Registers a plugin with the factory. Call this function from the constructor of the |
603 | * KPluginFactory subclass to make the create function able to instantiate the plugin when asked |
604 | * for an interface the plugin implements. |
605 | * |
606 | * \a T the name of the plugin class |
607 | * |
608 | * \a instanceFunction A function pointer to a function that creates an instance of the plugin. |
609 | * |
610 | * \since 5.96 |
611 | */ |
612 | template<class T> |
613 | void registerPlugin(CreateInstanceWithMetaDataFunction instanceFunction) |
614 | { |
615 | registerPlugin(&T::staticMetaObject, instanceFunction); |
616 | } |
617 | |
618 | /*! |
619 | * This function is called when the factory asked to create an Object. |
620 | * |
621 | * You may reimplement it to provide a very flexible factory. This is especially useful to |
622 | * provide generic factories for plugins implemented using a scripting language. |
623 | * |
624 | * \a iface the staticMetaObject::className() string identifying the plugin interface that |
625 | * was requested. E.g. for KCModule plugins this string will be "KCModule". |
626 | * |
627 | * \a parentWidget only used if the requested plugin is a KPart. |
628 | * |
629 | * \a parent the parent object for the plugin object. |
630 | * |
631 | * \a args a plugin specific list of arbitrary arguments. |
632 | */ |
633 | virtual QObject *create(const char *iface, QWidget *parentWidget, QObject *parent, const QVariantList &args); |
634 | |
635 | template<class impl, class ParentType> |
636 | static QObject *createInstance(QWidget * /*parentWidget*/, QObject *parent, const KPluginMetaData & /*metaData*/, const QVariantList &args) |
637 | { |
638 | ParentType *p = nullptr; |
639 | if (parent) { |
640 | p = qobject_cast<ParentType *>(parent); |
641 | Q_ASSERT(p); |
642 | } |
643 | if constexpr (std::is_constructible<impl, ParentType *, QVariantList>::value) { |
644 | return new impl(p, args); |
645 | } else { |
646 | return new impl(p); |
647 | } |
648 | } |
649 | |
650 | template<class impl, class ParentType> |
651 | static QObject *createWithMetaDataInstance(QWidget * /*parentWidget*/, QObject *parent, const KPluginMetaData &metaData, const QVariantList &args) |
652 | { |
653 | ParentType *p = nullptr; |
654 | if (parent) { |
655 | p = qobject_cast<ParentType *>(parent); |
656 | Q_ASSERT(p); |
657 | } |
658 | if constexpr (std::is_constructible<impl, ParentType *, KPluginMetaData, QVariantList>::value) { |
659 | return new impl(p, metaData, args); |
660 | } else { |
661 | return new impl(p, metaData); |
662 | } |
663 | } |
664 | |
665 | template<class impl> |
666 | static QObject *createPartWithMetaDataInstance(QWidget *parentWidget, QObject *parent, const KPluginMetaData &metaData, const QVariantList &args) |
667 | { |
668 | if constexpr (std::is_constructible<impl, QWidget *, QObject *, KPluginMetaData, QVariantList>::value) { |
669 | return new impl(parentWidget, parent, metaData, args); |
670 | } else { |
671 | return new impl(parentWidget, parent, metaData); |
672 | } |
673 | } |
674 | |
675 | private: |
676 | friend KPluginFactoryPrivate; |
677 | std::unique_ptr<KPluginFactoryPrivate> const d; |
678 | void registerPlugin(const QMetaObject *metaObject, CreateInstanceWithMetaDataFunction instanceFunction); |
679 | // The logging categories are not part of the public API, consequently this needs to be a private function |
680 | static void logFailedInstantiationMessage(KPluginMetaData data); |
681 | static void logFailedInstantiationMessage(const char *className, KPluginMetaData data); |
682 | }; |
683 | |
684 | template<typename T> |
685 | inline T *KPluginFactory::create(QObject *parent, const QVariantList &args) |
686 | { |
687 | QObject *o = create(T::staticMetaObject.className(), parent && parent->isWidgetType() ? reinterpret_cast<QWidget *>(parent) : nullptr, parent, args); |
688 | |
689 | T *t = qobject_cast<T *>(o); |
690 | if (!t) { |
691 | delete o; |
692 | } |
693 | return t; |
694 | } |
695 | |
696 | template<typename T> |
697 | inline T *KPluginFactory::create(QWidget *parentWidget, QObject *parent, const QVariantList &args) |
698 | { |
699 | QObject *o = create(T::staticMetaObject.className(), parentWidget, parent, args); |
700 | |
701 | T *t = qobject_cast<T *>(o); |
702 | if (!t) { |
703 | delete o; |
704 | } |
705 | return t; |
706 | } |
707 | |
708 | Q_DECLARE_INTERFACE(KPluginFactory, KPluginFactory_iid) |
709 | |
710 | #endif // KPLUGINFACTORY_H |
711 | |