You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
libkipi/libkipi/libkipi/pluginloader.cpp

389 lines
11 KiB

/* ============================================================
* 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 <tqstringlist.h>
#include <ktrader.h>
#include <tdeparts/componentfactory.h>
#include <kdebug.h>
#include <kdialog.h>
#include "plugin.h"
#include "pluginloader.h"
#include "interface.h"
#include <tdeconfig.h>
#include <tqcheckbox.h>
#include <tqlayout.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( TQString::fromLatin1("file_actions") );
unplugActionList( TQString::fromLatin1("image_actions") );
unplugActionList( TQString::fromLatin1("tool_actions") );
TQPtrList<TDEAction> fileActions;
TQPtrList<TDEAction> imageActions;
TQPtrList<TDEAction> 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<TDEAction>* 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<Plugin>(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<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"