| 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 | |