|
|
|
/* ============================================================
|
|
|
|
* 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:
|
|
|
|
<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<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"
|