File indexing completed on 2024-05-05 04:33:16

0001 /*
0002     SPDX-FileCopyrightText: 2004-2018 Gilles Caulier <caulier dot gilles at gmail dot com>
0003     SPDX-FileCopyrightText: 2004-2005 Renchi Raju <renchi dot raju at gmail dot com>
0004     SPDX-FileCopyrightText: 2009 Andi Clemens <andi dot clemens at googlemail dot com>
0005     SPDX-FileCopyrightText: 2009 Aleix Pol Gonzalez <aleixpol at kde dot org>
0006     SPDX-FileCopyrightText: 2012 Victor Dodon <dodonvictor at gmail dot com>
0007 
0008     SPDX-License-Identifier: GPL-2.0-or-later
0009 */
0010 
0011 #ifndef KIPI_PLUGINLOADER_H
0012 #define KIPI_PLUGINLOADER_H
0013 
0014 // Std includes
0015 
0016 #include <memory>
0017 
0018 // Qt includes
0019 
0020 #include <QList>
0021 
0022 // KF includes
0023 
0024 #include <KService>
0025 #include <KXmlGuiWindow>
0026 
0027 // Local includes
0028 
0029 #include "libkipi_export.h"
0030 
0031 namespace KIPI
0032 {
0033 
0034 class Plugin;
0035 class Interface;
0036 class ConfigWidget;
0037 
0038 /**
0039     \author Gilles Caulier
0040     \par Maintainer: Victor Dodon
0041     \class PluginLoader pluginloader.h <KIPI/PluginLoader>
0042     This is the class that will help host applications to load plugins.
0043     
0044     This is a singleton and host applications should create the PluginLoader
0045     just once, and then use the instance() static method to access it.
0046 
0047     The host application must create an instance of the plugin loader, and
0048     call the method loadPlugins() to get the plugins loaded. To ensure that
0049     plugins are correctly removed from menus and toolbars when loaded and
0050     unloaded after constructions, the application must connect to either the
0051     signals plug() / unplug() or the signal replug(). These signals are
0052     emitted when a plugin is to be inserted into the menus.
0053 
0054     If your application is using KDE XMLGUI, the easiest(nicest) way to get the
0055     plugins inserted into the menus is by adding an item in your application XML
0056     ui.rc file looking like this:
0057 
0058     \code
0059 
0060     <!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
0061     <gui version="1" name="MyKipiApplication" >
0062 
0063         <MenuBar>
0064 
0065             <Menu name="Image" ><text>&amp;Image</text>
0066                 <DefineGroup name="kipi_image_group" append="kipi_image_group" />
0067             </Menu>
0068 
0069             <Menu name="Tools"><text>&amp;Tools</text>
0070                 <DefineGroup name="kipi_album_group" append="kipi_album_group" />
0071                 <Separator/>
0072                 <DefineGroup name="kipi_tool_group" append="kipi_tool_group" />
0073                 <Separator/>
0074                 <DefineGroup name="kipi_batch_group" append="kipi_batch_group" />
0075             </Menu>
0076 
0077             <Merge/>
0078 
0079         </MenuBar>
0080 
0081         <ToolBar name="mainToolBar">
0082             <text>Main Toolbar</text>
0083         </Toolbar>
0084 
0085         <ActionProperties/>
0086 
0087     </gui>
0088 
0089     \endcode
0090 
0091     Then loading plugins into menus could be done with code similar to this implementation:
0092 
0093     \code
0094 
0095     class MyKipiApplication : public KXmlGuiWindow
0096     {
0097         Q_OBJECT
0098 
0099     public:
0100 
0101         MyKipiApplication();
0102 
0103     private Q_SLOTS:
0104 
0105         void slotKipiPluginPlug();
0106 
0107     private:
0108 
0109         KIPI::Interface*    m_iface;
0110         KIPI::PluginLoader* m_loader;
0111     };
0112 
0113     // -------------------------------------------------------------------------------
0114 
0115     MyKipiApplication::MyKipiApplication() : KXmlGuiWindow(0)
0116     {
0117         m_iface  = new KIPI::Interface(this, "MyKipiApplication_KIPI_interface");
0118         m_loader = new KIPI::PluginLoader(this);
0119         m_loader->setInterface(m_iface);
0120         m_loader->init();
0121 
0122         connect(m_loader, SIGNAL(replug()),
0123                 this, SLOT(slotKipiPluginPlug()));
0124 
0125         m_loader->loadPlugins();
0126         // Do not delete m_loader as long as any of the plugins are in use
0127     }
0128 
0129     void MyKipiApplication::slotKipiPluginPlug()
0130     {
0131         QList<QAction*> kipiImageActions, kipiExportActions, kipiToolsActions;
0132         PluginLoader::PluginList list = m_loader->pluginList();
0133 
0134         // We need to remove loaded plugins from the gui factory
0135         for (PluginLoader::PluginList::ConstIterator it = list.constBegin(); it != list.constEnd(); ++it )
0136         {
0137             Plugin* plugin = (*it)->plugin();
0138             if ( !plugin || !(*it)->shouldLoad() )
0139                 continue;
0140 
0141             guiFactory()->removeClient(plugin);
0142         }
0143 
0144         for (PluginLoader::PluginList::ConstIterator it = list.constBegin(); it != list.constEnd(); ++it )
0145         {
0146             Plugin* plugin = (*it)->plugin();
0147             if ( !plugin || !(*it)->shouldLoad() )
0148                 continue;
0149 
0150             plugin->setup(this);
0151         }
0152 
0153         // We add plugins to the factory
0154         for (PluginLoader::PluginList::ConstIterator it = list.constBegin(); it != list.constEnd(); ++it )
0155         {
0156             Plugin* plugin = (*it)->plugin();
0157             if ( !plugin || !(*it)->shouldLoad() )
0158                 continue;
0159 
0160             guiFactory()->addClient(plugin);
0161         }
0162     }
0163 
0164     \endcode
0165 
0166     For a implementation sample used to manage Kipi-plugins in host application,
0167     look the code of the kxmlkipicmd test application in the "test" folder from libkipi.
0168 
0169     To configure which plugins should be loaded, simply call
0170     PluginLoader::configWidget(), and insert the widget into your normal
0171     configuration dialog.
0172 */
0173 class LIBKIPI_EXPORT PluginLoader : public QObject
0174 {
0175     Q_OBJECT
0176 
0177 public:
0178 
0179     /**
0180      * \class Info pluginloader.h <KIPI/PluginLoader>
0181      *
0182      * Info about a plugin.
0183      */
0184     class LIBKIPI_EXPORT Info
0185     {
0186 
0187     public:
0188 
0189         Info(KXmlGuiWindow* const parent, const KService::Ptr& service, bool shouldLoad);
0190         ~Info();
0191 
0192         QString       name()             const;
0193         QString       uname()            const;
0194         QString       author()           const;
0195         QString       comment()          const;
0196         QIcon         icon()             const;
0197         QString       library()          const;
0198         KService::Ptr service()          const;
0199         Plugin*       plugin()           const;
0200         QStringList   pluginCategories() const;
0201 
0202         void reload();
0203         bool shouldLoad() const;
0204         void setShouldLoad(bool);
0205 
0206     private:
0207 
0208         class Private;
0209         std::unique_ptr<Private> const d;
0210     };
0211 
0212 public:
0213 
0214     typedef QList<Info*> PluginList;
0215 
0216 public:
0217 
0218     /**
0219      * Use this constructor if your application does not use KDE XML GUI technology.
0220      * 
0221      * Note that the PluginLoader is intended to be a singleton, so you
0222      * should create only one and then use instance().
0223      */
0224     PluginLoader();
0225 
0226     /**
0227      * Standard constructor. You must pass the instance of KDE XML GUI application as argument.
0228      * 
0229      * Note that the PluginLoader is intended to be a singleton, so you
0230      * should create only one and then use instance().
0231      * 
0232      * @param parent the pointer to the KXmlGuiWindow of your application
0233      */
0234     PluginLoader(KXmlGuiWindow* const parent);
0235 
0236     /**
0237      * Standard destructor
0238      * 
0239      * Since PluginLoader is a singleton, you should not call this
0240      * in client code.
0241      */
0242     ~PluginLoader() override;
0243 
0244     /**
0245      * Set KIPI interface instance from host application.
0246      */
0247     void setInterface(Interface* const interface);
0248 
0249     /**
0250      * Return KIPI host interface instance.
0251      */
0252     Interface* interface() const;
0253 
0254     /**
0255      * Set Plugins ignore list, with name of obsoletes plugins to not load through init().
0256      */
0257     void setIgnoredPluginsList(const QStringList& ignores);
0258 
0259     /**
0260      * Set disabled plugin actions that will not be plugged into the gui,
0261      */
0262     void setDisabledPluginActions(const QStringList& disabledActions);
0263 
0264     /**
0265      * Return the list of disabled plugin actions
0266      */
0267     QStringList disabledPluginActions() const;
0268 
0269     /**
0270      * Init plugin loader. Call this method to parse relevant plugins installed on your system.
0271      * Before to call this method, you must setup KIPI interface instance.
0272      * Optionally, setup list of plugins to ignore, the constraint list, and
0273      * the disabled plugin actions
0274      */
0275     void init();
0276 
0277     /**
0278      * Call this method to load relevant plugins installed on your system to your KIPI host application
0279      * @note Plugins can be loaded through Info item.
0280      */
0281     void loadPlugins();
0282 
0283     /**
0284      * Returns the list of loaded plugins
0285      */
0286     const PluginList& pluginList();
0287 
0288     /**
0289      * Return the kipi-plugins version installed on your computer if it's found through kipiplugins.desktop file.
0290      */
0291     QString kipiPluginsVersion() const;
0292 
0293     /**
0294      * Return the config widget with list of plugins to manage.
0295      */
0296     ConfigWidget* configWidget(QWidget* const parent) const;
0297 
0298     /**
0299      * Returns plugin loader instance.
0300      */
0301     static PluginLoader* instance();
0302 
0303 Q_SIGNALS:
0304 
0305     void plug(KIPI::PluginLoader::Info*);
0306     void unplug(KIPI::PluginLoader::Info*);
0307 
0308     /// @note Plugin can be plugged through Info item.
0309     void replug();
0310 
0311 private:
0312 
0313     class Private;
0314     std::unique_ptr<Private> const d;
0315 
0316 private:
0317 
0318     friend class ConfigWidget;
0319 };
0320 
0321 } // namespace KIPI
0322 
0323 #endif /* KIPI_PLUGINLOADER_H */