summaryrefslogtreecommitdiffstats
path: root/libkipi/libkipi/pluginloader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libkipi/libkipi/pluginloader.cpp')
-rw-r--r--libkipi/libkipi/pluginloader.cpp388
1 files changed, 388 insertions, 0 deletions
diff --git a/libkipi/libkipi/pluginloader.cpp b/libkipi/libkipi/pluginloader.cpp
new file mode 100644
index 0000000..f7f8aa5
--- /dev/null
+++ b/libkipi/libkipi/pluginloader.cpp
@@ -0,0 +1,388 @@
+/* ============================================================
+ * File : pluginloader.cpp
+ * Author: Renchi Raju <renchi@pooh.tam.uiuc.edu>
+ * Date : 2004-02-19
+ * Description :
+ *
+ * Copyright 2004 by Renchi Raju
+
+ * This program is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU Library General
+ * Public License as published by the Free Software Foundation;
+ * either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * ============================================================ */
+
+/** @file pluginloader.cpp */
+
+#include <qstringlist.h>
+
+#include <ktrader.h>
+#include <kparts/componentfactory.h>
+#include <kdebug.h>
+#include <kdialog.h>
+
+#include "plugin.h"
+#include "pluginloader.h"
+#include "interface.h"
+#include <kconfig.h>
+#include <qcheckbox.h>
+#include <qlayout.h>
+
+/**
+ \author Renchi Raju
+ \class KIPI::PluginLoader
+ This is the class that will help host applications to load plugins.
+
+ The host application must create an instance of the plugin loader, and
+ call the method loadPlugins() to get the plugins loaded. To ensure that
+ plugins are correctly removed from menus and toolbars when loaded and
+ unloaded after constructions, the application must connect to either the
+ signals plug() / unplug() or the signal replug(). These signals are
+ emitted when a plugin is to be inserted into the menus.
+
+ If your application is using XMLGUI, the easiest way to get the plugins
+ inserted into the menus is by adding an item in the ui.rc file looking
+ list this:
+ &lt;ActionList name="image_actions"/&gt;
+
+ Then plugin plugins into menus could be done with code similiar to this from KimDaBa:
+ \code
+ void slotReplug() {
+ unplugActionList( QString::fromLatin1("file_actions") );
+ unplugActionList( QString::fromLatin1("image_actions") );
+ unplugActionList( QString::fromLatin1("tool_actions") );
+
+ QPtrList<KAction> fileActions;
+ QPtrList<KAction> imageActions;
+ QPtrList<KAction> toolsActions;
+
+ KIPI::PluginLoader::PluginList list = _pluginLoader->pluginList();
+ for( KIPI::PluginLoader::PluginList::Iterator it = list.begin(); it != list.end(); ++it ) {
+ KIPI::Plugin* plugin = (*it)->plugin;
+ if ( !plugin || !(*it)->shouldLoad )
+ continue;
+
+ plugin->setup( this );
+ QPtrList<KAction>* popup = 0;
+ if ( plugin->category() == KIPI::IMAGESPLUGIN )
+ popup = &imageActions;
+
+ else if ( plugin->category() == KIPI::EXPORTPLUGIN ||
+ plugin->category() == KIPI::IMPORTPLUGIN )
+ popup = &fileActions;
+
+ else if ( plugin->category() == KIPI::TOOLSPLUGIN )
+ popup = &toolsActions;
+
+ if ( popup ) {
+ KActionPtrList actions = plugin->actions();
+ for( KActionPtrList::Iterator it = actions.begin(); it != actions.end(); ++it ) {
+ popup->append( *it );
+ }
+ }
+ else {
+ kdDebug() << "No menu found\n";
+ }
+ plugin->actionCollection()->readShortcutSettings();
+ }
+
+ // For this to work I need to pass false as second arg for createGUI
+ plugActionList( QString::fromLatin1("file_actions"), fileActions );
+ plugActionList( QString::fromLatin1("image_actions"), imageActions );
+ plugActionList( QString::fromLatin1("tool_actions"), toolsActions );
+ }
+ \endcode
+
+ To configure which plugins should be loaded, simply call
+ PluginLoader::configWidget(), and insert the widget into your normal
+ configuration dialog.
+*/
+namespace KIPI {
+
+//---------------------------------------------------------------------
+//
+// PluginLoader::Info
+//
+//---------------------------------------------------------------------
+struct PluginLoader::Info::Private {
+ QString m_name;
+ QString m_comment;
+ QString m_library;
+ Plugin* m_plugin;
+ bool m_shouldLoad;
+};
+
+
+PluginLoader::Info::Info(const QString& name, const QString& comment, const QString& library, bool shouldLoad)
+{
+ d=new Private;
+ d->m_name=name;
+ d->m_comment=comment;
+ d->m_library=library;
+ d->m_plugin=0;
+ d->m_shouldLoad=shouldLoad;
+}
+
+
+PluginLoader::Info::~Info()
+{
+ delete d;
+}
+
+
+QString PluginLoader::Info::name() const
+{
+ return d->m_name;
+}
+
+
+QString PluginLoader::Info::comment() const
+{
+ return d->m_comment;
+}
+
+
+QString PluginLoader::Info::library() const
+{
+ return d->m_library;
+}
+
+
+Plugin* PluginLoader::Info::plugin() const
+{
+ return d->m_plugin;
+}
+
+
+void PluginLoader::Info::setPlugin(Plugin* plugin)
+{
+ d->m_plugin=plugin;
+}
+
+
+bool PluginLoader::Info::shouldLoad() const
+{
+ return d->m_shouldLoad;
+}
+
+
+void PluginLoader::Info::setShouldLoad(bool value)
+{
+ d->m_shouldLoad=value;
+}
+
+
+//---------------------------------------------------------------------
+//
+// PluginLoader
+//
+//---------------------------------------------------------------------
+static PluginLoader* s_instance = 0;
+
+
+struct PluginLoader::Private
+{
+ PluginList m_pluginList;
+ Interface* m_interface;
+ QStringList m_ignores;
+};
+
+
+PluginLoader::PluginLoader( const QStringList& ignores, Interface* interface )
+{
+ Q_ASSERT( s_instance == 0 );
+ s_instance = this;
+
+ d=new Private;
+ d->m_interface = interface;
+ d->m_ignores = ignores;
+
+ KTrader::OfferList offers = KTrader::self()->query("KIPI/Plugin");
+ KConfig* config = KGlobal::config();
+ config->setGroup( QString::fromLatin1( "KIPI/EnabledPlugin" ) );
+
+ KTrader::OfferList::ConstIterator iter;
+ for(iter = offers.begin(); iter != offers.end(); ++iter) {
+
+ KService::Ptr service = *iter;
+ QString name = service->name();
+ QString comment = service->comment();
+ QString library = service->library();
+ QStringList reqFeatures = service->property( QString::fromLatin1( "X-KIPI-ReqFeatures" ) ).toStringList();
+
+ if (library.isEmpty() || name.isEmpty() ) {
+ kdWarning( 51001 ) << "KIPI::PluginLoader: Plugin had an empty name or library file - this should not happen." << endl;
+ continue;
+ }
+
+ if ( d->m_ignores.contains( name ) ) {
+ kdDebug( 51001 ) << "KIPI::PluginLoader: plugin " << name << " is in the ignore list for host application" << endl;
+ continue;
+ }
+
+ bool appHasAllReqFeatures=true;
+ for( QStringList::Iterator featureIt = reqFeatures.begin(); featureIt != reqFeatures.end(); ++featureIt ) {
+ if ( !d->m_interface->hasFeature( *featureIt ) ) {
+ kdDebug( 51001 ) << "Plugin " << name << " was not loaded because the host application is missing\n"
+ << "the feature " << *featureIt << endl;
+ appHasAllReqFeatures=false;
+ break;
+ }
+ }
+
+ bool load = config->readBoolEntry( name, true );
+
+ if (!appHasAllReqFeatures)
+ continue;
+
+ Info* info = new Info( name, comment, library, load );
+ d->m_pluginList.append( info );
+ }
+}
+
+PluginLoader::~PluginLoader()
+{
+ delete d;
+}
+
+void PluginLoader::loadPlugins()
+{
+ for( PluginList::Iterator it = d->m_pluginList.begin(); it != d->m_pluginList.end(); ++it ) {
+ loadPlugin( *it );
+ }
+ emit replug();
+}
+
+void PluginLoader::loadPlugin( Info* info )
+{
+ if ( info->plugin() == 0 && info->shouldLoad() ) {
+ Plugin *plugin = 0;
+ int error;
+ plugin = KParts::ComponentFactory
+ ::createInstanceFromLibrary<Plugin>(info->library().local8Bit().data(),
+ d->m_interface, 0, QStringList(), &error);
+
+ if (plugin)
+ kdDebug( 51001 ) << "KIPI::PluginLoader: Loaded plugin " << plugin->name()<< endl;
+ else
+ {
+ kdWarning( 51001 ) << "KIPI::PluginLoader:: createInstanceFromLibrary returned 0 for "
+ << info->name()
+ << " (" << info->library() << ")"
+ << " with error number "
+ << error << endl;
+ if (error == KParts::ComponentFactory::ErrNoLibrary)
+ kdWarning( 51001 ) << "KLibLoader says: "
+ << KLibLoader::self()->lastErrorMessage() << endl;
+ }
+ info->setPlugin(plugin);
+ }
+ if ( info->plugin() ) // Do not emit if we had trouble loading the plugin.
+ emit PluginLoader::instance()->plug( info );
+}
+
+
+const PluginLoader::PluginList& PluginLoader::pluginList()
+{
+ return d->m_pluginList;
+}
+
+PluginLoader* PluginLoader::instance()
+{
+ Q_ASSERT( s_instance != 0);
+ return s_instance;
+}
+
+
+//---------------------------------------------------------------------
+//
+// ConfigWidget
+//
+//---------------------------------------------------------------------
+ConfigWidget* PluginLoader::configWidget( QWidget* parent )
+{
+ return new ConfigWidget( parent );
+}
+
+
+class PluginCheckBox :public QCheckBox
+{
+public:
+ PluginCheckBox( PluginLoader::Info* info, QWidget* parent )
+ : QCheckBox( info->comment(), parent ), info( info )
+ {
+ setChecked( info->shouldLoad() );
+ }
+ PluginLoader::Info* info;
+};
+
+
+struct ConfigWidget::Private
+{
+ QValueList< PluginCheckBox* > _boxes;
+};
+
+
+ConfigWidget::ConfigWidget( QWidget* parent )
+ :QScrollView( parent, "KIPI::PluginLoader::ConfigWidget" )
+{
+ d=new Private;
+ QWidget* top = new QWidget( viewport() );
+ addChild( top );
+ setResizePolicy( AutoOneFit );
+
+ QVBoxLayout* lay = new QVBoxLayout( top, KDialog::marginHint(), KDialog::spacingHint() );
+
+ PluginLoader::PluginList list = PluginLoader::instance()->d->m_pluginList;
+ for( PluginLoader::PluginList::Iterator it = list.begin(); it != list.end(); ++it ) {
+ PluginCheckBox* cb = new PluginCheckBox( *it, top );
+ lay->addWidget( cb );
+ d->_boxes.append( cb );
+ }
+
+ lay->addStretch(10);
+}
+
+
+ConfigWidget::~ConfigWidget()
+{
+ delete d;
+}
+
+
+void ConfigWidget::apply()
+{
+ KConfig* config = KGlobal::config();
+ config->setGroup( QString::fromLatin1( "KIPI/EnabledPlugin" ) );
+ bool changes = false;
+
+ for( QValueList<PluginCheckBox*>::Iterator it = d->_boxes.begin(); it != d->_boxes.end(); ++it ) {
+ bool orig = (*it)->info->shouldLoad();
+ bool load = (*it)->isChecked();
+ if ( orig != load ) {
+ changes = true;
+ config->writeEntry( (*it)->info->name(), load );
+ (*it)->info->setShouldLoad(load);
+ if ( load ) {
+ PluginLoader::instance()->loadPlugin( (*it)->info);
+ }
+ else {
+ if ( (*it)->info->plugin() ) // Do not emit if we had trouble loading plugin.
+ emit PluginLoader::instance()->unplug( (*it)->info);
+ }
+ }
+ }
+ emit PluginLoader::instance()->replug();
+}
+
+
+} // namespace
+
+#include "pluginloader.moc"