Blokkal
an Extendable KDE Blogging Client
SourceForge.net Logo

blokkalpluginmanager.cpp

00001 /***************************************************************************
00002  *   Copyright (C) 2006 by Martin Müller   *
00003  *   orvio@orvio.de   *
00004  *                                                                         *
00005  *   This program is free software; you can redistribute it and/or modify  *
00006  *   it under the terms of the GNU General Public License as published by  *
00007  *   the Free Software Foundation; either version 2 of the License, or     *
00008  *   (at your option) any later version.                                   *
00009  *                                                                         *
00010  *   This program is distributed in the hope that it will be useful,       *
00011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00013  *   GNU General Public License for more details.                          *
00014  *                                                                         *
00015  *   You should have received a copy of the GNU General Public License     *
00016  *   along with this program; if not, write to the                         *
00017  *   Free Software Foundation, Inc.,                                       *
00018  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
00019  ***************************************************************************/
00020 #include "blokkalpluginmanager.h"
00021 #include "blokkalpluginmanager.moc"
00022 
00023 #include "blokkalprotocol.h"
00024 #include "blokkalplugin.h"
00025 #include "blokkalui/editentryviewfactory.h"
00026 #include "blokkalui/browseentryviewfactory.h"
00027 
00028 #include <kparts/componentfactory.h>
00029 #include <ktrader.h>
00030 #include <kdebug.h>
00031 
00032 #include <qtimer.h>
00033 
00034 #include <iostream>
00035 
00036 
00037 class Blokkal::PluginManagerPrivate {
00038 public:
00039         PluginManagerPrivate( void ):
00040         availablePlugins( KPluginInfo::fromServices( KServiceTypeTrader::self()->query( QString::fromLatin1(  "Blokkal/Plugin" ) ) ) ),
00041         shuttingDown( FALSE )
00042         {}
00043 
00044         KPluginInfo::List availablePlugins;
00045         QMap<KPluginInfo, Plugin *> infoPluginMap;
00046 
00047         bool shuttingDown;
00048 
00049         PluginManager instance;
00050 
00057         KPluginInfo::List filterPlugins( const QString & serviceType )
00058         {
00059                 if( availablePlugins.isEmpty() ) {
00060                         return availablePlugins;
00061                 }
00062         
00063                 KPluginInfo::List filteredPluginList;
00064                 for( KPluginInfo::List::ConstIterator it = availablePlugins.begin();
00065                      it != availablePlugins.end();
00066                      ++it )
00067                 {
00068                         if( (*it).service()->serviceTypes().contains( serviceType ) ) {
00069                                 filteredPluginList.append( *it );
00070                         }
00071                 }
00072 
00073                 return filteredPluginList;
00074         }
00075 };
00076 
00077 K_GLOBAL_STATIC( Blokkal::PluginManagerPrivate, _bpmp );
00078 
00079 Blokkal::PluginManager::PluginManager( void ):
00080 QObject( 0 )
00081 {
00082         setObjectName( "PluginManger" );
00083         KGlobal::ref();
00084 }
00085 
00086 Blokkal::PluginManager::~PluginManager( void )
00087 {
00088 }
00089 
00090 Blokkal::PluginManager * Blokkal::PluginManager::self( void )
00091 {
00092 
00093         return &_bpmp->instance;
00094 }
00095 
00096 KPluginInfo::List Blokkal::PluginManager::availablePlugins( void ) const
00097 {
00098         return _bpmp->availablePlugins;
00099 }
00100 
00101 KPluginInfo::List Blokkal::PluginManager::availableProtocols( void ) const
00102 {
00103         return _bpmp->filterPlugins( "Blokkal/Protocol" );
00104 }
00105 
00106 
00107 KPluginInfo::List Blokkal::PluginManager::availableEditEntryViewFactorys( void ) const
00108 {
00109         return _bpmp->filterPlugins( "Blokkal/EditEntryViewFactory" );
00110 }
00111 
00112 Blokkal::Protocol * Blokkal::PluginManager::protocol( const QString & pluginName )
00113 {
00114         Blokkal::Plugin * plugin = this->loadPlugin( pluginName );
00115 
00116         if( !plugin ) {
00117                 return 0;
00118         }
00119 
00120         KPluginInfo info = pluginInfo( plugin );
00121         if( info.service()->serviceTypes().contains( "Blokkal/Protocol" ) ) {
00122                 return (Blokkal::Protocol*) plugin;
00123         }
00124         
00125         kError() << pluginName << " does not provide service type Blokkal/Protocol";
00126         return 0 ;
00127 }
00128 
00129 
00130 Blokkal::Ui::EditEntryViewFactory * Blokkal::PluginManager::editEntryViewFactory( const QString & pluginName )
00131 {
00132         Blokkal::Plugin * plugin = loadPlugin( pluginName.isEmpty() ? "blokkal_eevp" : pluginName );
00133         if( !plugin ) {
00134                 return 0;
00135         }
00136 
00137         KPluginInfo info = pluginInfo( plugin );
00138         if( info.service()->serviceTypes().contains( "Blokkal/EditEntryViewFactory" ) ) {
00139                 return (Blokkal::Ui::EditEntryViewFactory*) plugin;
00140         }
00141         
00142         kError() << pluginName << " does not provide service type Blokkal/EditEntryViewFactory";
00143         return 0 ;
00144 }
00145 
00146 Blokkal::Plugin * Blokkal::PluginManager::plugin( const QString & pluginName )
00147 {
00148         return loadPlugin( pluginName );
00149 }
00150 
00151 KPluginInfo Blokkal::PluginManager::pluginInfo( const QString & pluginName ) const
00152 {
00153         for( KPluginInfo::List::ConstIterator it = _bpmp->availablePlugins.begin();
00154              it != _bpmp->availablePlugins.end();
00155              ++it )
00156         {
00157                 if( (*it).pluginName() == pluginName ) {
00158                         return *it;
00159                 }
00160         }
00161 
00162         return KPluginInfo();
00163 }
00164 
00165 KPluginInfo Blokkal::PluginManager::pluginInfo( const Plugin * plugin ) const
00166 {
00167         if( !plugin ) {
00168                 kError() << "called with 0 pointer!" << endl;
00169         }
00170 
00171         if( _bpmp->infoPluginMap.isEmpty() ) {
00172                 kError() << "trying to get plugin info while no plugins are loaded" << endl;
00173                 return KPluginInfo();
00174         }
00175         
00176         //kdDebug() << "Starting search" << endl;
00177         KPluginInfo::List keys = _bpmp->infoPluginMap.keys();
00178         for( KPluginInfo::List::ConstIterator it = keys.begin();
00179              it != keys.end();
00180              ++it )
00181         {
00182                 //kdDebug() << *it << endl;
00183                 //kdDebug() << _bpmp->infoPluginMap[ *it ] << " <?> " << plugin << endl;
00184                 if( _bpmp->infoPluginMap[ *it ] == plugin ) {
00185                         return *it;
00186                 }
00187         }
00188 
00189         kError() << "unable to find info for loaded plugin!" << endl;
00190         if( plugin ) {
00191                 kError() <<  "Problem caused by: " << plugin->metaObject()->className() << endl;
00192         }
00193         return KPluginInfo();
00194 }
00195 
00196 void Blokkal::PluginManager::unloadPlugin( const QString & pluginName )
00197 {
00198         //kDebug() << "unloading plugin: " << pluginName << endl;
00199         KPluginInfo info = pluginInfo( pluginName );
00200         if( !info.isValid() ) {
00201                 kWarning() << "Trying to unload nonexistent plugin with name " << pluginName << endl;
00202         }
00203         
00204         if( _bpmp->infoPluginMap.contains( info ) ) {
00205                 //the plugin will emit readyToUnload and eventually
00206                 //then it is deleted which will in turn case
00207                 //QObject::destroyed() to be emitted. This will
00208                 //call removePlugin()
00209                 _bpmp->infoPluginMap[ info ]->prepareToUnload();
00210         }
00211 }
00212 
00213 void Blokkal::PluginManager::unloadAllPlugins( void )
00214 {
00215         for( QMap<KPluginInfo, Plugin *>::Iterator it = _bpmp->infoPluginMap.begin();
00216              it != _bpmp->infoPluginMap.end() ;
00217               )
00218         {
00219                 QString pluginName = it.key().pluginName();
00220                 ++it;
00221                 unloadPlugin( pluginName );
00222         }
00223 }
00224 
00225 void Blokkal::PluginManager::deletePlugin( Blokkal::Plugin * plugin )
00226 {
00227         QTimer::singleShot( 0, plugin, SLOT( deleteLater( void ) ) );
00228 }
00229 
00230 Blokkal::Plugin * Blokkal::PluginManager::loadPlugin( const QString & pluginName )
00231 {
00232         KPluginInfo info = pluginInfo( pluginName );
00233         if( !info.isValid() ) {
00234                 kError() << "No plugin found with name " << pluginName << endl;
00235                 return 0;
00236         }
00237 
00238         Blokkal::Plugin * plugin = 0;
00239         if( _bpmp->infoPluginMap.contains( info ) ) {
00240                 plugin = _bpmp->infoPluginMap[ info ];
00241                 return plugin;
00242         }
00243         
00244         QString error;
00245         plugin = KServiceTypeTrader::createInstanceFromQuery<Blokkal::Plugin>( QString::fromLatin1( "Blokkal/Plugin" ), QString::fromLatin1( "[X-KDE-PluginInfo-Name]=='%1'" ).arg( pluginName ), this, QVariantList(), & error );
00246 
00247         if( plugin ) {
00248                 _bpmp->infoPluginMap.insert( info, plugin );
00249                 connect( plugin, SIGNAL( readyToUnload( Blokkal::Plugin * ) ),
00250                          this, SLOT( deletePlugin( Blokkal::Plugin * ) ) );
00251                 connect( plugin, SIGNAL( destroyed ( QObject * ) ),
00252                          this, SLOT( removePlugin( QObject * ) ) );
00253                 emit pluginLoaded( plugin );
00254                 return plugin;
00255         }
00256         else {
00257                 kError() << "error loading plugin " << pluginName << endl;
00258         }
00259 
00260         return plugin;
00261 }
00262 
00263 void Blokkal::PluginManager::removePlugin( QObject * plugin )
00264 {
00265         if( _bpmp->infoPluginMap.isEmpty() ) {
00266                 return;
00267         }
00268         
00269         for( QMap<KPluginInfo, Plugin *>::Iterator it = _bpmp->infoPluginMap.begin();
00270              it != _bpmp->infoPluginMap.end();
00271              ++it )
00272         {
00273                 if( it.value() == plugin ) {
00274                         _bpmp->infoPluginMap.remove( it.key() );
00275                         break;
00276                 }
00277         }
00278 
00279         if( _bpmp->shuttingDown && _bpmp->infoPluginMap.isEmpty() ) {
00280                 KGlobal::deref();
00281         }
00282 }
00283 
00284 void Blokkal::PluginManager::shutdown( void )
00285 {
00286         _bpmp->shuttingDown = TRUE;
00287         unloadAllPlugins();
00288 }
00289 
00290 KPluginInfo::List Blokkal::PluginManager::availableBrowseEntryViewFactorys( void ) const
00291 {
00292         return _bpmp->filterPlugins( "Blokkal/BrowseEntryViewFactory" );
00293 }
00294 
00295 Blokkal::Ui::BrowseEntryViewFactory * Blokkal::PluginManager::browseEntryViewFactory( const QString & pluginName )
00296 {
00297         Blokkal::Plugin * plugin = loadPlugin( pluginName.isEmpty() ? "blokkal_bevp" : pluginName );
00298         if( !plugin ) {
00299                 return 0;
00300         }
00301 
00302         KPluginInfo info = pluginInfo( plugin );
00303         if( info.service()->serviceTypes().contains( "Blokkal/BrowseEntryViewFactory" ) ) {
00304                 return (Blokkal::Ui::BrowseEntryViewFactory*) plugin;
00305         }
00306                 
00307         kError() << pluginName << " does not provide service type Blokkal/BrowseEntryViewFactory";
00308         return 0 ;
00309 }