/* ============================================================ * File : pluginloader.cpp * Author: Renchi Raju * 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 #include #include #include #include #include "plugin.h" #include "pluginloader.h" #include "interface.h" #include #include #include /** \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: <ActionList name="image_actions"/> Then plugin plugins into menus could be done with code similiar to this from KimDaBa: \code void slotReplug() { unplugActionList( TQString::fromLatin1("file_actions") ); unplugActionList( TQString::fromLatin1("image_actions") ); unplugActionList( TQString::fromLatin1("tool_actions") ); TQPtrList fileActions; TQPtrList imageActions; TQPtrList 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 ); TQPtrList* 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 ) { TDEActionPtrList actions = plugin->actions(); for( TDEActionPtrList::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( TQString::fromLatin1("file_actions"), fileActions ); plugActionList( TQString::fromLatin1("image_actions"), imageActions ); plugActionList( TQString::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 { TQString m_name; TQString m_comment; TQString m_library; Plugin* m_plugin; bool m_shouldLoad; }; PluginLoader::Info::Info(const TQString& name, const TQString& comment, const TQString& 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; } TQString PluginLoader::Info::name() const { return d->m_name; } TQString PluginLoader::Info::comment() const { return d->m_comment; } TQString 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; TQStringList m_ignores; }; PluginLoader::PluginLoader( const TQStringList& ignores, Interface* interface ) { Q_ASSERT( s_instance == 0 ); s_instance = this; d=new Private; d->m_interface = interface; d->m_ignores = ignores; TDETrader::OfferList offers = TDETrader::self()->query("KIPI/Plugin"); TDEConfig* config = TDEGlobal::config(); config->setGroup( TQString::fromLatin1( "KIPI/EnabledPlugin" ) ); TDETrader::OfferList::ConstIterator iter; for(iter = offers.begin(); iter != offers.end(); ++iter) { KService::Ptr service = *iter; TQString name = service->name(); TQString comment = service->comment(); TQString library = service->library(); TQStringList reqFeatures = service->property( TQString::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( TQStringList::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(info->library().local8Bit().data(), d->m_interface, 0, TQStringList(), &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( TQWidget* parent ) { return new ConfigWidget( parent ); } class PluginCheckBox :public TQCheckBox { public: PluginCheckBox( PluginLoader::Info* info, TQWidget* parent ) : TQCheckBox( info->comment(), parent ), info( info ) { setChecked( info->shouldLoad() ); } PluginLoader::Info* info; }; struct ConfigWidget::Private { TQValueList< PluginCheckBox* > _boxes; }; ConfigWidget::ConfigWidget( TQWidget* parent ) :TQScrollView( parent, "KIPI::PluginLoader::ConfigWidget" ) { d=new Private; TQWidget* top = new TQWidget( viewport() ); addChild( top ); setResizePolicy( AutoOneFit ); TQVBoxLayout* lay = new TQVBoxLayout( 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() { TDEConfig* config = TDEGlobal::config(); config->setGroup( TQString::fromLatin1( "KIPI/EnabledPlugin" ) ); bool changes = false; for( TQValueList::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"