diff options
Diffstat (limited to 'libkdepim/komposer/core/pluginmanager.cpp')
-rw-r--r-- | libkdepim/komposer/core/pluginmanager.cpp | 489 |
1 files changed, 0 insertions, 489 deletions
diff --git a/libkdepim/komposer/core/pluginmanager.cpp b/libkdepim/komposer/core/pluginmanager.cpp deleted file mode 100644 index dcfea6f4..00000000 --- a/libkdepim/komposer/core/pluginmanager.cpp +++ /dev/null @@ -1,489 +0,0 @@ -// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2; -*- -/** - * pluginmanager.cpp - * Most of this code has been lifted from Martijn's KopetePluginManager class - * - * Copyright (C) 2004 Zack Rusin <zack@kde.org> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301 USA - */ -#include "pluginmanager.h" - -#include "plugin.h" - -#include <tqapplication.h> -#include <tqfile.h> -#include <tqregexp.h> -#include <tqtimer.h> -#include <tqvaluestack.h> - -#include <kapplication.h> -#include <kdebug.h> -#include <kparts/componentfactory.h> -#include <kplugininfo.h> -#include <ksettings/dispatcher.h> -#include <ksimpleconfig.h> -#include <kstandarddirs.h> -#include <kstaticdeleter.h> -#include <kurl.h> - - -namespace Komposer -{ - -class PluginManager::Private -{ -public: - // All available plugins, regardless of category, and loaded or not - TQValueList<KPluginInfo*> plugins; - - // Dict of all currently loaded plugins, mapping the KPluginInfo to - // a plugin - TQMap<KPluginInfo*, Plugin*> loadedPlugins; - - // The plugin manager's mode. The mode is StartingUp until loadAllPlugins() - // has finished loading the plugins, after which it is set to Running. - // ShuttingDown and DoneShutdown are used during Komposer shutdown by the - // async unloading of plugins. - enum ShutdownMode { StartingUp, Running, ShuttingDown, DoneShutdown }; - ShutdownMode shutdownMode; - - KSharedConfig::Ptr config; - // Plugins pending for loading - TQValueStack<TQString> pluginsToLoad; -}; - -PluginManager::PluginManager( TQObject *parent ) - : TQObject( parent ) -{ - d = new Private; - - // We want to add a reference to the application's event loop so we - // can remain in control when all windows are removed. - // This way we can unload plugins asynchronously, which is more - // robust if they are still doing processing. - kapp->ref(); - d->shutdownMode = Private::StartingUp; - - KSettings::Dispatcher::self()->registerInstance( KGlobal::instance(), - this, TQT_SLOT( loadAllPlugins() ) ); - - d->plugins = KPluginInfo::fromServices( - KTrader::self()->query( TQString::tqfromLatin1( "Komposer/Plugin" ), - TQString::tqfromLatin1( "[X-Komposer-Version] == 1" ) ) ); -} - -PluginManager::~PluginManager() -{ - if ( d->shutdownMode != Private::DoneShutdown ) { - slotShutdownTimeout(); -#if 0 - kdWarning() << k_funcinfo - << "Destructing plugin manager without going through " - << "the shutdown process!" - << endl - << kdBacktrace(10) << endl; -#endif - } - - // Quick cleanup of the remaining plugins, hope it helps - TQMap<KPluginInfo*, Plugin*>::ConstIterator it; - for ( it = d->loadedPlugins.begin(); it != d->loadedPlugins.end(); /* EMPTY */ ) - { - // Remove causes the iterator to become invalid, so pre-increment first - TQMap<KPluginInfo*, Plugin*>::ConstIterator nextIt( it ); - ++nextIt; - kdWarning() << k_funcinfo << "Deleting stale plugin '" - << it.data()->name() << "'" << endl; - delete it.data(); - it = nextIt; - } - - delete d; -} - -TQValueList<KPluginInfo*> -PluginManager::availablePlugins( const TQString &category ) const -{ - if ( category.isEmpty() ) - return d->plugins; - - TQValueList<KPluginInfo*> result; - TQValueList<KPluginInfo*>::ConstIterator it; - for ( it = d->plugins.begin(); it != d->plugins.end(); ++it ) - { - if ( ( *it )->category() == category ) - result.append( *it ); - } - - return result; -} - -TQMap<KPluginInfo*, Plugin*> -PluginManager::loadedPlugins( const TQString &category ) const -{ - TQMap<KPluginInfo*, Plugin*> result; - TQMap<KPluginInfo*, Plugin*>::ConstIterator it; - for ( it = d->loadedPlugins.begin(); it != d->loadedPlugins.end(); ++it ) - { - if ( category.isEmpty() || it.key()->category() == category ) - result.insert( it.key(), it.data() ); - } - - return result; -} - -void -PluginManager::shutdown() -{ - d->shutdownMode = Private::ShuttingDown; - - // Remove any pending plugins to load, we're shutting down now :) - d->pluginsToLoad.clear(); - - // Ask all plugins to unload - if ( d->loadedPlugins.empty() ) { - d->shutdownMode = Private::DoneShutdown; - } else { - TQMap<KPluginInfo*, Plugin*>::ConstIterator it; - for ( it = d->loadedPlugins.begin(); it != d->loadedPlugins.end(); /* EMPTY */ ) - { - // Remove causes the iterator to become invalid, so pre-increment first - TQMap<KPluginInfo*, Plugin*>::ConstIterator nextIt( it ); - ++nextIt; - it.data()->aboutToUnload(); - it = nextIt; - } - } - - TQTimer::singleShot( 3000, this, TQT_SLOT(slotShutdownTimeout()) ); -} - -void -PluginManager::slotPluginReadyForUnload() -{ - // Using TQObject::sender() is on purpose here, because otherwise all - // plugins would have to pass 'this' as parameter, which makes the API - // less clean for plugin authors - Plugin* plugin = dynamic_cast<Plugin*>( const_cast<TQObject*>( sender() ) ); - if ( !plugin ) - { - kdWarning() << k_funcinfo << "Calling object is not a plugin!" << endl; - return; - - } - kdDebug()<<"manager unloading"<<endl; - plugin->deleteLater(); -} - -void -PluginManager::slotShutdownTimeout() -{ - // When we were already done the timer might still fire. - // Do nothing in that case. - if ( d->shutdownMode == Private::DoneShutdown ) - return; - -#ifndef NDEBUG - TQStringList remaining; - for ( TQMap<KPluginInfo*, Plugin*>::ConstIterator it = d->loadedPlugins.begin(); - it != d->loadedPlugins.end(); ++it ) - remaining.append( it.key()->pluginName() ); - - kdWarning() << k_funcinfo << "Some plugins didn't shutdown in time!" << endl - << "Remaining plugins: " - << remaining.join( TQString::tqfromLatin1( ", " ) ) << endl - << "Forcing Komposer shutdown now." << endl; -#endif - - slotShutdownDone(); -} - -void -PluginManager::slotShutdownDone() -{ - d->shutdownMode = Private::DoneShutdown; - - kapp->deref(); -} - -void -PluginManager::loadAllPlugins() -{ - // FIXME: We need session management here - Martijn - - if ( !d->config ) - d->config = KSharedConfig::openConfig( "komposerrc" ); - - TQMap<TQString, TQString> entries = d->config->entryMap( - TQString::tqfromLatin1( "Plugins" ) ); - - TQMap<TQString, TQString>::Iterator it; - for ( it = entries.begin(); it != entries.end(); ++it ) - { - TQString key = it.key(); - if ( key.endsWith( TQString::tqfromLatin1( "Enabled" ) ) ) - { - key.setLength( key.length() - 7 ); - //kdDebug() << k_funcinfo << "Set " << key << " to " << it.data() << endl; - - if ( it.data() == TQString::tqfromLatin1( "true" ) ) - { - if ( !plugin( key ) ) - d->pluginsToLoad.push( key ); - } - else - { - // FIXME: Does this ever happen? As loadAllPlugins is only called on startup - // I'd say 'no'. If it does, it should be made async - // though. - Martijn - if ( plugin( key ) ) - unloadPlugin( key ); - } - } - } - - // Schedule the plugins to load - TQTimer::singleShot( 0, this, TQT_SLOT( slotLoadNextPlugin() ) ); -} - -void PluginManager::slotLoadNextPlugin() -{ - if ( d->pluginsToLoad.isEmpty() ) - { - if ( d->shutdownMode == Private::StartingUp ) - { - d->shutdownMode = Private::Running; - emit allPluginsLoaded(); - } - return; - } - - TQString key = d->pluginsToLoad.pop(); - loadPluginInternal( key ); - - // Schedule the next run unconditionally to avoid code duplication on the - // allPluginsLoaded() signal's handling. This has the added benefit that - // the signal is delayed one event loop, so the accounts are more likely - // to be instantiated. - TQTimer::singleShot( 0, this, TQT_SLOT( slotLoadNextPlugin() ) ); -} - -Plugin* -PluginManager::loadPlugin( const TQString &pluginId, - PluginLoadMode mode /* = LoadSync */ ) -{ - if ( mode == LoadSync ) { - return loadPluginInternal( pluginId ); - } else { - d->pluginsToLoad.push( pluginId ); - TQTimer::singleShot( 0, this, TQT_SLOT( slotLoadNextPlugin() ) ); - return 0; - } -} - -Plugin* -PluginManager::loadPluginInternal( const TQString &pluginId ) -{ - KPluginInfo* info = infoForPluginId( pluginId ); - if ( !info ) { - kdWarning() << k_funcinfo << "Unable to find a plugin named '" - << pluginId << "'!" << endl; - return 0; - } - - if ( d->loadedPlugins.contains( info ) ) - return d->loadedPlugins[ info ]; - - int error = 0; - Plugin *plugin = KParts::ComponentFactory::createInstanceFromQuery<Komposer::Plugin>( - TQString::tqfromLatin1( "Komposer/Plugin" ), - TQString::tqfromLatin1( "[X-KDE-PluginInfo-Name]=='%1'" ).tqarg( pluginId ), - this, 0, TQStringList(), &error ); - - if ( plugin ) { - d->loadedPlugins.insert( info, plugin ); - info->setPluginEnabled( true ); - - connect( plugin, TQT_SIGNAL(destroyed(TQObject*)), - this, TQT_SLOT(slotPluginDestroyed(TQObject*)) ); - connect( plugin, TQT_SIGNAL(readyForUnload()), - this, TQT_SLOT(slotPluginReadyForUnload()) ); - - kdDebug() << k_funcinfo << "Successfully loaded plugin '" - << pluginId << "'" << endl; - - emit pluginLoaded( plugin ); - } else { - switch ( error ) { - case KParts::ComponentFactory::ErrNoServiceFound: - kdDebug() << k_funcinfo << "No service implementing the given mimetype " - << "and fullfilling the given constraint expression can be found." - << endl; - break; - - case KParts::ComponentFactory::ErrServiceProvidesNoLibrary: - kdDebug() << "the specified service provides no shared library." << endl; - break; - - case KParts::ComponentFactory::ErrNoLibrary: - kdDebug() << "the specified library could not be loaded." << endl; - break; - - case KParts::ComponentFactory::ErrNoFactory: - kdDebug() << "the library does not export a factory for creating components." - << endl; - break; - - case KParts::ComponentFactory::ErrNoComponent: - kdDebug() << "the factory does not support creating components " - << "of the specified type." - << endl; - break; - } - - kdDebug() << k_funcinfo << "Loading plugin '" << pluginId - << "' failed, KLibLoader reported error: '" - << KLibLoader::self()->lastErrorMessage() - << "'" << endl; - } - - return plugin; -} - -bool -PluginManager::unloadPlugin( const TQString &spec ) -{ - TQMap<KPluginInfo*, Plugin*>::ConstIterator it; - for ( it = d->loadedPlugins.begin(); it != d->loadedPlugins.end(); ++it ) - { - if ( it.key()->pluginName() == spec ) - { - it.data()->aboutToUnload(); - return true; - } - } - - return false; -} - -void -PluginManager::slotPluginDestroyed( TQObject *plugin ) -{ - TQMap<KPluginInfo*, Plugin*>::Iterator it; - for ( it = d->loadedPlugins.begin(); it != d->loadedPlugins.end(); ++it ) - { - if ( it.data() == plugin ) - { - d->loadedPlugins.erase( it ); - break; - } - } - - if ( d->shutdownMode == Private::ShuttingDown && d->loadedPlugins.isEmpty() ) - { - // Use a timer to make sure any pending deleteLater() calls have - // been handled first - TQTimer::singleShot( 0, this, TQT_SLOT(slotShutdownDone()) ); - } -} - -Plugin* -PluginManager::plugin( const TQString &pluginId ) const -{ - KPluginInfo *info = infoForPluginId( pluginId ); - if ( !info ) - return 0; - - if ( d->loadedPlugins.contains( info ) ) - return d->loadedPlugins[ info ]; - else - return 0; -} - -TQString -PluginManager::pluginName( const Plugin *plugin ) const -{ - TQMap<KPluginInfo*, Plugin*>::ConstIterator it; - for ( it = d->loadedPlugins.begin(); it != d->loadedPlugins.end(); ++it ) - { - if ( it.data() == plugin ) - return it.key()->name(); - } - - return TQString::tqfromLatin1( "Unknown" ); -} - -TQString -PluginManager::pluginId( const Plugin *plugin ) const -{ - TQMap<KPluginInfo*, Plugin*>::ConstIterator it; - for ( it = d->loadedPlugins.begin(); it != d->loadedPlugins.end(); ++it ) - { - if ( it.data() == plugin ) - return it.key()->pluginName(); - } - - return TQString::tqfromLatin1( "unknown" ); -} - -TQString -PluginManager::pluginIcon( const Plugin *plugin ) const -{ - TQMap<KPluginInfo*, Plugin*>::ConstIterator it; - for ( it = d->loadedPlugins.begin(); it != d->loadedPlugins.end(); ++it ) - { - if ( it.data() == plugin ) - return it.key()->icon(); - } - - return TQString::tqfromLatin1( "Unknown" ); -} - -KPluginInfo* -PluginManager::infoForPluginId( const TQString &pluginId ) const -{ - TQValueList<KPluginInfo*>::ConstIterator it; - for ( it = d->plugins.begin(); it != d->plugins.end(); ++it ) - { - if ( ( *it )->pluginName() == pluginId ) - return *it; - } - - return 0; -} - -bool -PluginManager::setPluginEnabled( const TQString &pluginId, bool enabled /* = true */ ) -{ - if ( !d->config ) - d->config = KSharedConfig::openConfig( "komposerrc" ); - - d->config->setGroup( "Plugins" ); - - - if ( !infoForPluginId( pluginId ) ) - return false; - - d->config->writeEntry( pluginId + TQString::tqfromLatin1( "Enabled" ), enabled ); - d->config->sync(); - - return true; -} - -} - -#include "pluginmanager.moc" |