source: calamares/trunk/fuentes/src/libcalamares/utils/PluginFactory.h @ 7538

Last change on this file since 7538 was 7538, checked in by kbut, 13 months ago

sync with github

File size: 10.8 KB
Line 
1/* === This file is part of Calamares - <https://github.com/calamares> ===
2 *
3 *   Copyright 2015, Teo Mrnjavac <teo@kde.org>
4 *   Copyright 2017, Adriaan de Groot <groot@kde.org>
5 *
6 *   Based on KPluginFactory from KCoreAddons, KDE project
7 *   Copyright 2007, Matthias Kretz <kretz@kde.org>
8 *   Copyright 2007, Bernhard Loos <nhuh.put@web.de>
9 *
10 *   Calamares is free software: you can redistribute it and/or modify
11 *   it under the terms of the GNU General Public License as published by
12 *   the Free Software Foundation, either version 3 of the License, or
13 *   (at your option) any later version.
14 *
15 *   Calamares is distributed in the hope that it will be useful,
16 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
17 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 *   GNU General Public License for more details.
19 *
20 *   You should have received a copy of the GNU General Public License
21 *   along with Calamares. If not, see <http://www.gnu.org/licenses/>.
22 */
23
24#ifndef CALAMARESPLUGINFACTORY_H
25#define CALAMARESPLUGINFACTORY_H
26
27#include "DllMacro.h"
28
29#include <QtCore/QObject>
30#include <QtCore/QVariant>
31#include <QtCore/QStringList>
32
33namespace Calamares
34{
35class PluginFactoryPrivate;
36}
37
38#define CalamaresPluginFactory_iid "io.calamares.PluginFactory"
39
40/**
41 * \relates PluginFactory
42 *
43 * CALAMARES_PLUGIN_FACTORY_DECLARATION declares the PluginFactory subclass. This macro
44 * can be used in a header file.
45 *
46 * \param name The name of the PluginFactory derived class.
47 *
48 * \see CALAMARES_PLUGIN_FACTORY
49 * \see CALAMARES_PLUGIN_FACTORY_DEFINITION
50 */
51#define CALAMARES_PLUGIN_FACTORY_DECLARATION(name) \
52    class name : public Calamares::PluginFactory \
53    { \
54        Q_OBJECT \
55        Q_INTERFACES(Calamares::PluginFactory) \
56        Q_PLUGIN_METADATA(IID CalamaresPluginFactory_iid) \
57    public: \
58        explicit name(); \
59        ~name(); \
60    private: \
61        void init(); \
62    };
63
64/**
65 * \relates PluginFactory
66 * CALAMARES_PLUGIN_FACTORY_DEFINITION defines the PluginFactory subclass. This macro
67 * can <b>not</b> be used in a header file.
68 *
69 * \param name The name of the PluginFactory derived class.
70 *
71 * \param pluginRegistrations Code to be inserted into the constructor of the
72 * class. Usually a series of registerPlugin() calls.
73 *
74 * \see CALAMARES_PLUGIN_FACTORY
75 * \see CALAMARES_PLUGIN_FACTORY_DECLARATION
76 */
77#define CALAMARES_PLUGIN_FACTORY_DEFINITION(name, pluginRegistrations) \
78    name::name() \
79    { \
80        pluginRegistrations \
81    } \
82    name::~name() {}
83
84namespace Calamares
85{
86
87/**
88 * \class PluginFactory PluginFactory.h <PluginFactory.h>
89 *
90 * PluginFactory provides a convenient way to provide factory-style plugins.
91 * Qt plugins provide a singleton object, but a common pattern is for plugins
92 * to generate as many objects of a particular type as the application requires.
93 * By using PluginFactory, you can avoid implementing the factory pattern
94 * yourself.
95 *
96 * PluginFactory also allows plugins to provide multiple different object
97 * types, indexed by keywords.
98 *
99 * The objects created by PluginFactory must inherit QObject, and must have a
100 * standard constructor pattern:
101 * \li if the object is a KPart::Part, it must be of the form
102 * \code
103 * T(QWidget *parentWidget, QObject *parent, const QVariantList &args)
104 * \endcode
105 * \li if it is a QWidget, it must be of the form
106 * \code
107 * T(QWidget *parent, const QVariantList &args)
108 * \endcode
109 * \li otherwise it must be of the form
110 * \code
111 * T(QObject *parent, const QVariantList &args)
112 * \endcode
113 *
114 * You should typically use CALAMARES_PLUGIN_FACTORY_DEFINITION() in your plugin code to
115 * create the factory.  The pattern is
116 *
117 * \code
118 * #include "utils/PluginFactory.h"
119 *
120 * class MyPlugin : public PluginInterface
121 * {
122 * public:
123 *     MyPlugin(QObject *parent, const QVariantList &args)
124 *         : PluginInterface(parent)
125 *     {}
126 * };
127 *
128 * CALAMARES_PLUGIN_FACTORY_DEFINITION(MyPluginFactory,
129 *                  registerPlugin<MyPlugin>();
130 *                 )
131 * \endcode
132 *
133 * If you want to load a library use KPluginLoader.
134 * The application that wants to instantiate plugin classes can do the following:
135 * \code
136 * PluginFactory *factory = KPluginLoader("libraryname").factory();
137 * if (factory) {
138 *     PluginInterface *p1 = factory->create<PluginInterface>(parent);
139 *     OtherInterface *p2  = factory->create<OtherInterface>(parent);
140 *     NextInterface *p3   = factory->create<NextInterface>("keyword1", parent);
141 *     NextInterface *p3   = factory->create<NextInterface>("keyword2", parent);
142 * }
143 * \endcode
144 *
145 * \author Matthias Kretz <kretz\@kde.org>
146 * \author Bernhard Loos <nhuh.put\@web.de>
147 */
148class DLLEXPORT PluginFactory : public QObject
149{
150    Q_OBJECT
151    friend class PluginFactoryPrivate;
152public:
153    /**
154     * This constructor creates a factory for a plugin.
155     */
156    explicit PluginFactory();
157
158    /**
159     * This destroys the PluginFactory.
160     */
161    virtual ~PluginFactory();
162
163    /**
164     * Use this method to create an object. It will try to create an object which inherits
165     * \p T. If it has multiple choices, you will get a fatal error (kFatal()), so be careful
166     * to request a unique interface or use keywords.
167     *
168     * \tparam T The interface for which an object should be created. The object will inherit \p T.
169     * \param parent The parent of the object. If \p parent is a widget type, it will also passed
170     *               to the parentWidget argument of the CreateInstanceFunction for the object.
171     * \returns A pointer to the created object is returned, or 0 if an error occurred.
172     */
173    template<typename T>
174    T* create( QObject* parent = nullptr );
175
176    /**
177     * Use this method to create an object. It will try to create an object which inherits
178     * \p T and was registered with \p keyword.
179     *
180     * \tparam T The interface for which an object should be created. The object will inherit \p T.
181     * \param keyword The keyword of the object.
182     * \param parent The parent of the object. If \p parent is a widget type, it will also passed
183     *               to the parentWidget argument of the CreateInstanceFunction for the object.
184     * \returns A pointer to the created object is returned, or 0 if an error occurred.
185     */
186    template<typename T>
187    T* create( const QString& keyword, QObject* parent = nullptr );
188
189Q_SIGNALS:
190    void objectCreated( QObject* object );
191
192protected:
193    /**
194     * Function pointer type to a function that instantiates a plugin.
195     */
196    typedef QObject* ( *CreateInstanceFunction )( QWidget*, QObject* );
197
198    /**
199     * This is used to detect the arguments need for the constructor of plugin classes.
200     * You can inherit it, if you want to add new classes and still keep support for the old ones.
201     */
202    template<class impl>
203    struct InheritanceChecker
204    {
205        CreateInstanceFunction createInstanceFunction( QWidget* )
206        {
207            return &createInstance<impl, QWidget>;
208        }
209        CreateInstanceFunction createInstanceFunction( ... )
210        {
211            return &createInstance<impl, QObject>;
212        }
213    };
214
215    explicit PluginFactory( PluginFactoryPrivate& dd );
216
217    /**
218     * Registers a plugin with the factory. Call this function from the constructor of the
219     * PluginFactory subclass to make the create function able to instantiate the plugin when asked
220     * for an interface the plugin implements.
221     *
222     * \tparam T the name of the plugin class
223     *
224     * \param keyword An optional keyword as unique identifier for the plugin. This allows you to
225     * put more than one plugin with the same interface into the same library using the same
226     * factory. X-KDE-PluginKeyword is a convenient way to specify the keyword in a desktop file.
227     *
228     * \param instanceFunction A function pointer to a function that creates an instance of the
229     * plugin. The default function that will be used depends on the type of interface. If the
230     * interface inherits from
231     * \li \c KParts::Part the function will call
232     * \code
233     * new T(QWidget *parentWidget, QObject *parent)
234     * \endcode
235     * \li \c QWidget the function will call
236     * \code
237     * new T(QWidget *parent)
238     * \endcode
239     * \li else the function will call
240     * \code
241     * new T(QObject *parent)
242     * \endcode
243     */
244    template<class T>
245    void registerPlugin( const QString& keyword = QString(),
246                         CreateInstanceFunction instanceFunction
247                         = InheritanceChecker<T>().createInstanceFunction( reinterpret_cast<T*>( 0 ) ) )
248    {
249        doRegisterPlugin( keyword, &T::staticMetaObject, instanceFunction );
250    }
251
252    PluginFactoryPrivate* const pd_ptr;
253
254    /**
255     * This function is called when the factory asked to create an Object.
256     *
257     * You may reimplement it to provide a very flexible factory. This is especially useful to
258     * provide generic factories for plugins implemeted using a scripting language.
259     *
260     * \param iface The staticMetaObject::className() string identifying the plugin interface that
261     * was requested. E.g. for KCModule plugins this string will be "KCModule".
262     * \param parentWidget Only used if the requested plugin is a KPart.
263     * \param parent The parent object for the plugin object.
264     * \param keyword A string that uniquely identifies the plugin. If a KService is used this
265     * keyword is read from the X-KDE-PluginKeyword entry in the .desktop file.
266     */
267    virtual QObject* create( const char* iface, QWidget* parentWidget, QObject* parent, const QString& keyword );
268
269    template<class impl, class ParentType>
270    static QObject* createInstance( QWidget* parentWidget, QObject* parent )
271    {
272        Q_UNUSED( parentWidget );
273        ParentType* p = nullptr;
274        if ( parent )
275        {
276            p = qobject_cast<ParentType*>( parent );
277            Q_ASSERT( p );
278        }
279        return new impl( p );
280    }
281
282private:
283    void doRegisterPlugin( const QString& keyword, const QMetaObject* metaObject, CreateInstanceFunction instanceFunction );
284};
285
286template<typename T>
287inline T* PluginFactory::create( QObject* parent )
288{
289    QObject* o = create( T::staticMetaObject.className(),
290                         parent && parent->isWidgetType() ? reinterpret_cast<QWidget*>( parent ) : nullptr,
291                         parent,
292                         QString() );
293
294    T* t = qobject_cast<T*>( o );
295    if ( !t )
296        delete o;
297    return t;
298}
299
300template<typename T>
301inline T* PluginFactory::create( const QString& keyword, QObject* parent )
302{
303    QObject* o = create( T::staticMetaObject.className(),
304                         parent && parent->isWidgetType() ? reinterpret_cast<QWidget*>( parent ) : nullptr,
305                         parent,
306                         keyword );
307
308    T* t = qobject_cast<T*>( o );
309    if ( !t )
310        delete o;
311    return t;
312}
313
314}
315
316Q_DECLARE_INTERFACE( Calamares::PluginFactory, CalamaresPluginFactory_iid )
317
318#endif // CALAMARESPLUGINFACTORY_H
Note: See TracBrowser for help on using the repository browser.