Logo Search packages:      
Sourcecode: kamefu version File versions

systemmanager.cpp

/*
    systemmanager.cpp - Singleton class to manager loaded System plugins.

    Copyright (c) 2005      by Michaƫl Larouche       <michael.larouche@kdemail.net>

    Portions from Kopete
    Copyright (c) 2001-2005 Kopete Developers <kopete-devel@kde.org>

    *************************************************************************
    *                                                                       *
    * This program is free software; you can redistribute it and/or modify  *
    * it under the terms of the GNU General Public License as published by  *
    * the Free Software Foundation; either version 2 of the License, or     *
    * (at your option) any later version.                                   *
    *                                                                       *
    *************************************************************************
*/
#include "systemmanager.h"

// Qt include
#include <qmap.h>
#include <qtimer.h>
#include <qvaluestack.h>

// KDE includes
#include <kdebug.h>
#include <kparts/componentfactory.h>
#include <kplugininfo.h>
#include <kapplication.h>
#include <kstaticdeleter.h>

// Kamefu include
#include "system.h"

namespace Kamefu 
{

class SystemManager::Private
{
public:
      Private() : isAllSystemsLoaded(false)
      {}
      /**
       * It's all the registred MIME type loaded by the system plugins.
       */
      QStringList registredMimeTypes;
      /**
       * All available systems, and loaded or not.
       */
      QValueList<KPluginInfo *> systems;
      /**
       * Map of all loaded systems and their KPluginInfo,
       */
      typedef QMap<KPluginInfo*, System*> InfoToSystemMap;
      InfoToSystemMap loadedSystems;
      /**
       * Pending systems to load.
       */
      QValueStack<QString> systemsToLoad;
      bool isAllSystemsLoaded;
};

static KStaticDeleter<SystemManager> systemManagerDeleter;

SystemManager *SystemManager::s_self = 0L;
SystemManager *SystemManager::self()
{
      if(!s_self)
      {
            systemManagerDeleter.setObject(s_self, new SystemManager);
      }

      return s_self;
}

SystemManager::SystemManager(QObject *parent, const char *name)
 : QObject(parent, name), d(new Private())
{
      d->systems = KPluginInfo::fromServices( KTrader::self()->query( QString::fromUtf8( "Kamefu/System" ) ) );

      // 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();
}

SystemManager::~SystemManager()
{
      kdDebug() << k_funcinfo << endl;

      while ( !d->loadedSystems.empty() )
      {
            Private::InfoToSystemMap::ConstIterator it = d->loadedSystems.begin();
            kdWarning() << k_funcinfo << "Deleting system plugin '" << it.data()->name() << "'" << endl;
            delete it.data();
      }
      delete d;
}

00101 bool SystemManager::isAllSystemsLoaded() const
{
      return d->isAllSystemsLoaded;
}

00106 QStringList SystemManager::getRegistredMimeTypes() const
{
      return d->registredMimeTypes;
}

00111 QString SystemManager::guessSystemNameFromMimeType(const QString &mimeType) const
{
      QString systemDisplayName;
      Private::InfoToSystemMap::ConstIterator it;
      Private::InfoToSystemMap::ConstIterator end = d->loadedSystems.end();

      for( it = d->loadedSystems.begin(); it != end; ++it )
      {
            QStringList mimeTypeList = it.data()->getRegistredSystemMimeTypes();
            for(QStringList::Iterator stringIt = mimeTypeList.begin(); stringIt != mimeTypeList.end(); ++stringIt)
            {
                  // Current system use that mime type.
                  if(*stringIt == mimeType)
                  {
                        systemDisplayName = it.data()->displayName();
                        break;
                  }
            }
      }

      return systemDisplayName;
}

00134 System *SystemManager::getSystemFromMimeType(const QString &mimeType) const
{
      Private::InfoToSystemMap::ConstIterator it;
      Private::InfoToSystemMap::ConstIterator end = d->loadedSystems.end();

      for( it = d->loadedSystems.begin(); it != end; ++it )
      {
            QStringList mimeTypeList = it.data()->getRegistredSystemMimeTypes();
            for(QStringList::Iterator stringIt = mimeTypeList.begin(); stringIt != mimeTypeList.end(); ++stringIt)
            {
                  // Current system use that mime type.
                  if(*stringIt == mimeType)
                  {
                        return it.data();
                        break;
                  }
            }
      }

      return 0;
}


00157 QValueList<KPluginInfo *> SystemManager::availableSystems() const
{
      return d->systems;
}

00162 SystemList SystemManager::loadedSystems() const
{
      SystemList result;
      
      for ( Private::InfoToSystemMap::ConstIterator it = d->loadedSystems.begin();
            it != d->loadedSystems.end(); ++it )
      {
                  result.append( it.data() );
      }
      
      return result;
}


00176 KPluginInfo *SystemManager::systemInfo(const System *system) const
{
      for ( Private::InfoToSystemMap::ConstIterator it = d->loadedSystems.begin();
            it != d->loadedSystems.end(); ++it )
      {
            if ( it.data() == system )
                  return it.key();
      }
      return 0;
}

00187 void SystemManager::loadSystem(const QString &pluginId)
{
      d->systemsToLoad.push(pluginId);
      QTimer::singleShot( 0, this, SLOT( slotLoadNextSystem() ) );
}

00193 void SystemManager::loadAllSystems()
{
      QValueList<KPluginInfo *> plugins = availableSystems();
      QValueList<KPluginInfo *>::ConstIterator it = plugins.begin();
      QValueList<KPluginInfo *>::ConstIterator end = plugins.end();
      for ( ; it != end; ++it )
      {
            d->systemsToLoad.push( (*it)->pluginName() );
      }

      // Schedule the plugins to load
      QTimer::singleShot( 0, this, SLOT( slotLoadNextSystem() ) );
}

00207 void SystemManager::slotLoadNextSystem()
{
      if ( d->systemsToLoad.isEmpty() )
      {
            d->isAllSystemsLoaded = true;
            emit allSystemsLoaded();
            return;
      }

      QString key = d->systemsToLoad.pop();
      loadSystemInternal( 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.
      QTimer::singleShot( 0, this, SLOT( slotLoadNextSystem() ) );
}

00226 System *SystemManager::loadSystemInternal(const QString &pluginId)
{
      KPluginInfo *info = infoForPluginId(pluginId);
      if(!info)
      {
            kdWarning() << k_funcinfo << "Unable to find a plugin named '" << pluginId << "'!" << endl;
            return 0L;
      }

      if ( d->loadedSystems.contains(info) )
            return d->loadedSystems[info];

      int error = 0;
      System *system = KParts::ComponentFactory::createInstanceFromQuery<System>( QString( "Kamefu/System" ),
            QString( "[X-KDE-PluginInfo-Name]=='%1'" ).arg( pluginId ), this, 0, QStringList(), &error );

      if( system )
      {
            d->loadedSystems.insert(info, system);
            info->setPluginEnabled(true);
            system->setPluginInfo(info);
            // Add the system MIME types to the global MIME type registry.
            d->registredMimeTypes += system->getRegistredSystemMimeTypes();

            connect(system, SIGNAL( destroyed( QObject * ) ), this, SLOT( slotSystemDestroyed( QObject * ) ) );
            //connect( plugin, SIGNAL( readyForUnload() ), this, SLOT( slotPluginReadyForUnload() ) );

            kdDebug() << k_funcinfo << "Successfully loaded plugin '" << pluginId << "'" << endl;

            emit systemLoaded(system);
      }
      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: '" << endl <<
                  KLibLoader::self()->lastErrorMessage() << "'" << endl;
      }

      return system;
}

00290 System* SystemManager::system(const QString &pluginId) const
{
      KPluginInfo *info = infoForPluginId( pluginId );
      if ( !info )
            return 0L;

      if ( d->loadedSystems.contains( info ) )
            return d->loadedSystems[ info ];
      else
            return 0L;
}

00302 KPluginInfo *SystemManager::infoForPluginId(const QString &pluginId) const
{
      QValueList<KPluginInfo *>::ConstIterator it;
      for ( it = d->systems.begin(); it != d->systems.end(); ++it )
      {
            if ( ( *it )->pluginName() == pluginId )
                  return *it;
      }

      return 0L;
}

00314 void SystemManager::shutdown()
{
      kdDebug() << k_funcinfo << endl;
      // Remove any pending plugins to load, we're shutting down now :)
      d->systemsToLoad.clear();
      
      // Ask all plugins to unload
      for ( Private::InfoToSystemMap::ConstIterator it = d->loadedSystems.begin();
            it != d->loadedSystems.end(); /* EMPTY */ )
      {
            // Plugins could emit their ready for unload signal directly in response to this,
            // which would invalidate the current iterator. Therefore, we copy the iterator
            // and increment it beforehand.
            Private::InfoToSystemMap::ConstIterator current( it );
            ++it;
            current.data()->deleteLater();
      }
      
      QTimer::singleShot(3000, this, SLOT( slotShutdownDone() ) );
}

00335 void SystemManager::slotShutdownDone()
{
      kapp->deref();
}

00340 bool SystemManager::unloadSystem( const QString &spec )
{
      //kdDebug(14010) << k_funcinfo << spec << endl;
      if( System *aSystem = system( spec ) )
      {
            aSystem->deleteLater();
            return true;
      }
      else
            return false;
}

00352 void SystemManager::slotSystemDestroyed(QObject *system)
{
      for ( Private::InfoToSystemMap::Iterator it = d->loadedSystems.begin();
            it != d->loadedSystems.end(); ++it )
      {
            if ( it.data() == system )
            {
                  d->loadedSystems.erase( it );
                  break;
            }
      }
}

}
#include "systemmanager.moc"

Generated by  Doxygen 1.6.0   Back to index