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