KDevelop4 Extension architecture

Andreas Pakulat apaku at gmx.de
Mon Jan 22 01:12:04 UTC 2007


Hi,

I wanted to play around with the extension architecture that Alex
proposed and found that we can probably do all we need with it (see my
two examples in the KDevelop4 architecture rework thread). 

So I went ahead and tried to extend PluginController to allow the
loading of plugins for a given extension and let a plugin provide
information about the extensions it has. Also dependecy checking is
done.

The attached patch is for the sublime-integration branch and I also
attach a sample desktop file to desribe how the information can be made
available. The important thing here is that all plugins will have the
same service type, the difference will lie in the X-KDevelop-Interfaces
key, which contains all interfaces the plugin implements.

I'll be available during the whole day tomorrow on IRC, though I'd
prefer to do discussions in the evening (or here).

What needs to be done still is to provide a macro that 
a) creates the factory needed for the extension stuff to work
b) implements the register/unregisterManager functions, given a list of
interfaces (if thats possible with macros)

Andreas

-- 
Never be led astray onto the path of virtue.
-------------- next part --------------
Index: interfaces/iplugincontroller.h
===================================================================
--- interfaces/iplugincontroller.h	(Revision 0)
+++ interfaces/iplugincontroller.h	(Revision 0)
@@ -0,0 +1,184 @@
+/* This file is part of the KDE project
+Copyright (C) 2004, 2007 Alexander Dymo <adymo at kdevelop.org>
+Copyright (C) 2006 Matt Rogers <mattr at kde.org>
+Copyright (C) 2007 Andreas Pakulat <apaku at gmx.de>
+
+Based on code from Kopete
+Copyright (c) 2002-2003 by Martijn Klingens <klingens at kde.org>
+
+This library 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 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public License
+along with this library; see the file COPYING.LIB.  If not, write to
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.
+*/
+#ifndef IPLUGINCONTROLLER_H
+#define IPLUGINCONTROLLER_H
+
+#include <QObject>
+
+#include <kplugininfo.h>
+#include <kurl.h>
+#include <kservice.h>
+
+#include "kdevexport.h"
+
+class QExtensionManager;
+
+namespace Koncrete
+{
+class IPlugin;
+class ProfileEngine;
+
+/**
+ * The KDevelop plugin controller.
+ * The Plugin controller is responsible for querying, loading and unloading
+ * available plugins.
+ */
+class KDEVPLATFORM_EXPORT IPluginController : public QObject
+{
+
+Q_OBJECT
+
+public:
+    enum PluginType {
+        Global = 0,
+        Project
+    };
+
+    IPluginController( QObject* );
+
+    virtual ~IPluginController();
+
+    /**
+     * Get the plugin instance based on the ID. The ID should be whatever is
+     * in X-KDE-PluginInfo-Name
+     */
+    virtual IPlugin* plugin( const QString& ) = 0;
+
+    /**
+     * Get the plugin info for a loaded plugin
+     */
+    virtual KPluginInfo* pluginInfo( IPlugin* ) const = 0;
+
+    /**
+     * Get a list of currently loaded plugins
+     */
+    virtual QList<IPlugin*> loadedPlugins() const = 0;
+
+    /**
+     * Returns a uniquely specified plugin. If it isn't already loaded, it will be.
+     */
+    virtual IPlugin * loadPlugin( const QString & _pluginId ) = 0;
+
+    /**
+     * @brief Unloads the plugin specified by @p plugin
+     *
+     * @param plugin The name of the plugin as specified by the
+     * X-KDE-PluginInfo-Name key of the .desktop file for the plugin
+     */
+    virtual void unloadPlugin( const QString & plugin ) = 0;
+
+    /**
+     * Queries for the plugin which supports given extension interface.
+     * All already loaded plugins will be queried and the first one to support the extension interface
+     * will be returned. Any plugin can be an extension, only "ServiceTypes=..." entry is
+     * required in .desktop file for that plugin.
+     * @param extension The extension interface
+     * @return A KDevelop extension plugin for given service type or 0 if no plugin supports it
+     */
+    virtual IPlugin *pluginForExtension(const QString &extension ) = 0;
+    virtual IPlugin *pluginForExtension(const QString &extension, const QString& constraint ) = 0;
+
+    /**
+     * Queries KDevelop services. Version is checked automatically
+     * by adding proper X-KDevelop-Version=N statement into the query.
+     * @param serviceType The service type to query, for example "KDevelop/Plugin" or
+     * "KDevelop/SourceFormatter."
+     * @param constraint A constraint for the service. Do not include plugin version number - it
+     * is done automatically.
+     * @return The list of plugin offers.
+     */
+    static KPluginInfo::List query( const QString &serviceType, const QString &constraint );
+
+    /**
+     * Queries KDevelop plugins. Works like KDevPluginController::query
+     * with serviceType set to "KDevelop/Plugin".
+     * @param constraint A constraint for the service. Do not include plugin version number - it
+     * is done automatically.
+     * @return The list of plugin offers.
+     */
+    static KPluginInfo::List queryPlugins( const QString &constraint );
+
+    /**
+     * Reimplement this function only if your shell supports plugin profiles.
+     * @return The list of URLs to the profile resources (files) with given @p extension.
+     * @param nameFilter Name filter for files. @see QDir::setNameFilter documentation
+     * for name filters syntax.
+     */
+    virtual KUrl::List profileResources( const QString &nameFilter ) = 0;
+
+    /**
+     * Reimplement this function only if your shell supports plugin profiles.
+     * @return The list of URLs to the resources (files) with given @p extension.
+     * This list is obtained by a recursive search that process given profile
+     * and all it's subprofiles.
+     * @param nameFilter Name filter for files. @see QDir::setNameFilter documentation
+     * for name filters syntax.
+     */
+    virtual KUrl::List profileResourcesRecursive( const QString &nameFilter ) = 0;
+
+    static QStringList argumentsFromService( const KService::Ptr &service );
+
+    virtual QString currentProfile() const = 0;
+
+    virtual void loadPlugins( PluginType offer ) = 0;
+    virtual void unloadPlugins( PluginType offer ) = 0;
+
+    virtual ProfileEngine &engine() const = 0;
+
+    //returns the name of an old profile that was unloaded
+    virtual QString changeProfile( const QString &newProfile ) = 0;
+
+    virtual QExtensionManager* extensionManager() = 0;
+
+    virtual void shutdown() = 0;
+
+Q_SIGNALS:
+    void loadingPlugin( const QString& );
+    void pluginLoaded( IPlugin* );
+
+    /**
+     * Emitted when a plugin profile was changed (reloaded, other profile opened, etc.).
+     * Should work only on shells with plugin profiles support.
+     */
+    void profileChanged();
+
+private Q_SLOTS:
+    ///A plugin has been destroyed. Cleanup our data structures
+    virtual void pluginDestroyed( QObject* ) = 0;
+
+    ///A plugin is ready to unload. Unload it
+    virtual void pluginReadyForUnload( IPlugin* ) = 0;
+
+    ///Our timeout timer has expired
+    virtual void shutdownTimeout() = 0;
+
+    virtual void shutdownDone() = 0;
+
+};
+
+}
+#endif
+
+
+// kate: space-indent on; indent-width 4; tab-width: 4; replace-tabs on; auto-insert-doxygen on
Index: interfaces/icore.h
===================================================================
--- interfaces/icore.h	(Revision 625743)
+++ interfaces/icore.h	(Arbeitskopie)
@@ -55,7 +55,7 @@ public:
     virtual IUiController *uiController() = 0;
 
     /** @return plugin controller.*/
-//     virtual IPluginController *pluginController() = 0;
+    virtual IPluginController *pluginController() = 0;
 
 
 protected:
Index: interfaces/iplugin.cpp
===================================================================
--- interfaces/iplugin.cpp	(Revision 625743)
+++ interfaces/iplugin.cpp	(Arbeitskopie)
@@ -9,6 +9,7 @@
  Copyright (C) 2003 Mario Scalas <mario.scalas at libero.it>
  Copyright (C) 2003-2004,2007 Alexander Dymo <adymo at kdevelop.org>
  Copyright (C) 2006 Adam Treat <treat at kde.org>
+ Copyright (C) 2007 Andreas Pakulat <apaku at gmx.de>
 
  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Library General Public
@@ -32,6 +33,7 @@
 #include <kiconloader.h>
 #include "iplugin.h"
 #include "icore.h"
+#include "iplugincontroller.h"
 // #include "kdevmainwindow.h"
 // #include "kdevIPlugincontroller.h"
 
@@ -112,6 +114,13 @@ ICore *IPlugin::core() const
     return d->core;
 }
 
+QExtensionManager* IPlugin::extensionManager()
+{
+    return core()->pluginController()->extensionManager();
+}
+
 }
 
 #include "iplugin.moc"
+
+// kate: space-indent on; indent-width 4; tab-width: 4; replace-tabs on; auto-insert-doxygen on
Index: interfaces/iplugincontroller.cpp
===================================================================
--- interfaces/iplugincontroller.cpp	(Revision 0)
+++ interfaces/iplugincontroller.cpp	(Revision 0)
@@ -0,0 +1,75 @@
+/* This file is part of the KDE project
+Copyright (C) 2004 Alexander Dymo <adymo at kdevelop.org>
+Copyright     2006 Matt Rogers <mattr at kde.org
+Copyright (C) 2007 Andreas Pakulat <apaku at gmx.de>
+
+Based on code from Kopete
+Copyright (c) 2002-2003 by Martijn Klingens <klingens at kde.org>
+
+This library 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 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public License
+along with this library; see the file COPYING.LIB.  If not, write to
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.
+*/
+#include "iplugincontroller.h"
+
+#include <kservicetypetrader.h>
+#include "iplugin.h"
+
+namespace Koncrete
+{
+
+IPluginController::IPluginController( QObject* parent )
+: QObject( parent )
+{
+}
+
+
+IPluginController::~IPluginController()
+{
+}
+
+KPluginInfo::List IPluginController::query( const QString &serviceType,
+        const QString &constraint )
+{
+
+    KPluginInfo::List infoList;
+    KService::List serviceList = KServiceTypeTrader::self() ->query( serviceType,
+            QString( "%1 and [X-KDevelop-Version] == %2" ).arg( constraint ).arg( KDEVELOP_PLUGIN_VERSION ) );
+
+    infoList = KPluginInfo::fromServices( serviceList );
+    return infoList;
+}
+
+KPluginInfo::List IPluginController::queryPlugins( const QString &constraint )
+{
+    return query( "KDevelop/Plugin", constraint );
+}
+
+QStringList IPluginController::argumentsFromService( const KService::Ptr &service )
+{
+    QStringList args;
+    if ( !service )
+        // service is a reference to a pointer, so a check whether it is 0 is still required
+        return args;
+    QVariant prop = service->property( "X-KDevelop-Args" );
+    if ( prop.isValid() )
+        args = prop.toString().split( " " );
+    return args;
+}
+
+}
+
+#include "iplugincontroller.moc"
+
+// kate: space-indent on; indent-width 4; tab-width: 4; replace-tabs on; auto-insert-doxygen on
Index: interfaces/CMakeLists.txt
===================================================================
--- interfaces/CMakeLists.txt	(Revision 625743)
+++ interfaces/CMakeLists.txt	(Arbeitskopie)
@@ -7,6 +7,7 @@ set(koncreteinterfaces_LIB_SRCS
     iplugin.cpp
     icore.cpp
     iuicontroller.cpp
+    iplugincontroller.cpp
 )
 
 kde4_automoc(${koncreteinterfaces_LIB_SRCS})
Index: interfaces/iplugin.h
===================================================================
--- interfaces/iplugin.h	(Revision 625743)
+++ interfaces/iplugin.h	(Arbeitskopie)
@@ -2,6 +2,7 @@
    Copyright (C) 1999-2001 Bernd Gehrmann <bernd at kdevelop.org>
    Copyright (C) 2004,2007 Alexander Dymo <adymo at kdevelop.org>
    Copyright (C) 2006 Adam Treat <treat at kde.org>
+   Copyright (C) 2007 Andreas Pakulat <apaku at gmx.de>
 
    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
@@ -26,7 +27,7 @@
 
 #include <QList>
 #include <QPointer>
-
+#include <QtDesigner/QExtensionManager>
 #include "kdevexport.h"
 
 class QWidget;
@@ -164,6 +165,16 @@ public:
 
     ICore *core() const;
 
+    virtual void registerExtensions() = 0;
+    virtual void unregisterExtensions() = 0;
+
+    virtual QStringList extensions() = 0;
+
+    template<class Extension> Extension* extension()
+    {
+        return qt_extension<Extension*>( extensionManager(), this );
+    }
+
 public Q_SLOTS:
     /**
      * Re-initialize the global icon loader
@@ -180,9 +191,11 @@ Q_SIGNALS:
 private:
     class Private;
     Private* d;
+
+    QExtensionManager* extensionManager();
 };
 
 }
 #endif
 
-//kate: auto-insert-doxygen on;
+// kate: space-indent on; indent-width 4; tab-width: 4; replace-tabs on; auto-insert-doxygen on
Index: shell/plugincontroller.cpp
===================================================================
--- shell/plugincontroller.cpp	(Revision 625743)
+++ shell/plugincontroller.cpp	(Arbeitskopie)
@@ -1,6 +1,7 @@
 /* This file is part of the KDE project
 Copyright (C) 2004 Alexander Dymo <adymo at kdevelop.org>
 Copyright     2006 Matt Rogers <mattr at kde.org
+Copyright (C) 2007 Andreas Pakulat <apaku at gmx.de>
 
 Based on code from Kopete
 Copyright (c) 2002-2003 by Martijn Klingens <klingens at kde.org>
@@ -48,15 +49,15 @@ Boston, MA 02110-1301, USA.
 #include "profileengine.h"
 #include "mainwindow.h"
 
-
 #include "core.h"
 /*#include "partselectwidget.h"*/
 #include "shellextension.h"
+#include <QtDesigner/QExtensionManager>
 
 namespace Koncrete
 {
 
-class PluginController::Private
+struct PluginControllerPrivate
 {
 public:
     QList<KPluginInfo*> plugins;
@@ -74,35 +75,22 @@ public:
 
     QString profile;
     ProfileEngine engine;
-
-    static KStaticDeleter<PluginController> deleter;
 };
 
-KStaticDeleter<PluginController> PluginController::Private::deleter;
-PluginController* PluginController::s_self = 0L;
-
-PluginController* PluginController::self()
-{
-    if ( !s_self )
-        Private::deleter.setObject( s_self, new PluginController() );
-
-    return s_self;
-}
-
 PluginController::PluginController()
-    : QObject( qApp )
+    : IPluginController( qApp )
 {
-    d = new Private;
+    d = new PluginControllerPrivate;
     d->profile = ShellExtension::getInstance() ->defaultProfile();
     d->plugins = KPluginInfo::fromServices( KServiceTypeTrader::self()->query( QLatin1String( "KDevelop/Plugin" ),
         QLatin1String( "[X-KDevelop-Version] == 4" ) ) );
-    d->shutdownMode = Private::Running;
-    KGlobal::ref();
+    d->shutdownMode = PluginControllerPrivate::Running;
+    m_manager = new QExtensionManager();
 }
 
 PluginController::~PluginController()
 {
-    if ( d->shutdownMode != Private::DoneShutdown )
+    if ( d->shutdownMode != PluginControllerPrivate::DoneShutdown )
         kWarning(9000) << k_funcinfo << "Destructing plugin controller without going through the shutdown process! Backtrace is: " << endl << kBacktrace() << endl;
 
     // Quick cleanup of the remaining plugins, hope it helps
@@ -110,12 +98,12 @@ PluginController::~PluginController()
     // removes the plugin from the list of loaded plugins.
     while ( !d->loadedPlugins.empty() )
     {
-        Private::InfoToPluginMap::ConstIterator it = d->loadedPlugins.begin();
+        PluginControllerPrivate::InfoToPluginMap::ConstIterator it = d->loadedPlugins.begin();
         kWarning(9000) << k_funcinfo << "Deleting stale plugin '" << it.key()->pluginName()
                 << "'" << endl;
         delete it.value();
     }
-
+    delete m_manager;
     delete d;
 }
 
@@ -131,7 +119,7 @@ ProfileEngine& PluginController::engine(
 
 KPluginInfo* PluginController::pluginInfo( IPlugin* plugin ) const
 {
-    for ( Private::InfoToPluginMap::ConstIterator it = d->loadedPlugins.begin();
+    for ( PluginControllerPrivate::InfoToPluginMap::ConstIterator it = d->loadedPlugins.begin();
           it != d->loadedPlugins.end(); ++it )
     {
         if ( it.value() == plugin )
@@ -142,23 +130,23 @@ KPluginInfo* PluginController::pluginInf
 
 void PluginController::shutdown()
 {
-    if(d->shutdownMode != Private::Running)
+    if(d->shutdownMode != PluginControllerPrivate::Running)
     {
         kDebug(9000) << k_funcinfo << "called when not running. state = " << d->shutdownMode << endl;
         return;
     }
 
-    d->shutdownMode = Private::ShuttingDown;
+    d->shutdownMode = PluginControllerPrivate::ShuttingDown;
 
 
     // Ask all plugins to unload
-    for ( Private::InfoToPluginMap::ConstIterator it = d->loadedPlugins.begin();
+    for ( PluginControllerPrivate::InfoToPluginMap::ConstIterator it = d->loadedPlugins.begin();
           it != d->loadedPlugins.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::InfoToPluginMap::ConstIterator current( it );
+        PluginControllerPrivate::InfoToPluginMap::ConstIterator current( it );
         ++it;
 
         //Let the plugin do some stuff before unloading
@@ -176,23 +164,6 @@ void PluginController::shutdown()
     QTimer::singleShot( 3000, this, SLOT( shutdownTimeout() ) );
 }
 
-KPluginInfo::List PluginController::query( const QString &serviceType,
-        const QString &constraint )
-{
-
-    KPluginInfo::List infoList;
-    KService::List serviceList = KServiceTypeTrader::self() ->query( serviceType,
-            QString( "%1 and [X-KDevelop-Version] == %2" ).arg( constraint ).arg( KDEVELOP_PLUGIN_VERSION ) );
-
-    infoList = KPluginInfo::fromServices( serviceList );
-    return infoList;
-}
-
-KPluginInfo::List PluginController::queryPlugins( const QString &constraint )
-{
-    return query( "KDevelop/Plugin", constraint );
-}
-
 IPlugin* PluginController::loadPlugin( const QString& pluginId )
 {
     return loadPluginInternal( pluginId );
@@ -221,39 +192,11 @@ void PluginController::unloadPlugins( Pl
     }
 }
 
-QStringList PluginController::argumentsFromService( const KService::Ptr &service )
-{
-    QStringList args;
-    if ( !service )
-        // service is a reference to a pointer, so a check whether it is 0 is still required
-        return args;
-    QVariant prop = service->property( "X-KDevelop-Args" );
-    if ( prop.isValid() )
-        args = prop.toString().split( " " );
-    return args;
-}
-
 QList<IPlugin *> PluginController::loadedPlugins() const
 {
     return d->loadedPlugins.values();
 }
 
-IPlugin * PluginController::getExtension( const QString & serviceType, const QString & constraint )
-{
-    KPluginInfo::List offers = PluginController::query( serviceType, constraint );
-    IPlugin* ext = 0;
-    for ( KPluginInfo::List::const_iterator it = offers.constBegin(); it != offers.constEnd(); ++it )
-    {
-        if  ( d->loadedPlugins.contains( (*it) ) )
-        {
-            ext = d->loadedPlugins[(*it)];
-            break;
-        }
-    }
-    return ext;
-}
-
-
 void PluginController::unloadPlugin( const QString & pluginId )
 {
     if( IPlugin *thePlugin = plugin( pluginId ) )
@@ -328,12 +271,19 @@ IPlugin *PluginController::loadPluginInt
     kDebug(9000) << k_funcinfo << "Attempting to load '" << pluginId << "'" << endl;
     emit loadingPlugin( info->name() );
     int error = 0;
-    IPlugin *plugin = KServiceTypeTrader::createInstanceFromQuery<IPlugin>( QLatin1String( "KDevelop/Plugin" ),
+    IPlugin *plugin = 0;
+    QStringList missingInterfaces;
+    if ( checkForDependecies( info, missingInterfaces ) )
+    {
+        plugin = KServiceTypeTrader::createInstanceFromQuery<IPlugin>( QLatin1String( "KDevelop/Plugin" ),
             QString::fromLatin1( "[X-KDE-PluginInfo-Name]=='%1'" ).arg( pluginId ), this, QStringList(), &error );
+        loadDependecies( info );
+    }
 
     if ( plugin )
     {
         d->loadedPlugins.insert( info, plugin );
+        plugin->registerExtensions();
         info->setPluginEnabled( true );
 
         connect( plugin, SIGNAL( destroyed( QObject * ) ),
@@ -347,6 +297,13 @@ IPlugin *PluginController::loadPluginInt
     }
     else
     {
+        if( !error && !missingInterfaces.isEmpty() )
+        {
+            kDebug(9000) << k_funcinfo << "Can't load plugin '" << pluginId
+                    << "' some of its required dependecies could not be fullfilled:" << endl
+                    << missingInterfaces.join(",") << endl;
+        }else
+        {
         switch( error )
         {
             case KLibLoader::ErrNoServiceFound:
@@ -375,6 +332,7 @@ IPlugin *PluginController::loadPluginInt
                 << "' failed, KLibLoader reported error: '" << endl <<
                 KLibLoader::self()->lastErrorMessage() << "'" << endl;
     }
+    }
 
     return plugin;
 }
@@ -394,7 +352,7 @@ IPlugin* PluginController::plugin( const
 
 void PluginController::pluginDestroyed( QObject* deletedPlugin )
 {
-    for ( Private::InfoToPluginMap::Iterator it = d->loadedPlugins.begin();
+    for ( PluginControllerPrivate::InfoToPluginMap::Iterator it = d->loadedPlugins.begin();
           it != d->loadedPlugins.end(); ++it )
     {
         if ( it.value() == deletedPlugin )
@@ -404,7 +362,7 @@ void PluginController::pluginDestroyed( 
         }
     }
 
-    if ( d->shutdownMode == Private::ShuttingDown && d->loadedPlugins.isEmpty() )
+    if ( d->shutdownMode == PluginControllerPrivate::ShuttingDown && d->loadedPlugins.isEmpty() )
     {
         // Use a timer to make sure any pending deleteLater() calls have
         // been handled first
@@ -422,11 +380,11 @@ void PluginController::shutdownTimeout()
 {
     // When we were already done the timer might still fire.
     // Do nothing in that case.
-    if ( d->shutdownMode == Private::DoneShutdown )
+    if ( d->shutdownMode == PluginControllerPrivate::DoneShutdown )
         return;
 
     QStringList remaining;
-    Private::InfoToPluginMap::ConstIterator it, itEnd;
+    PluginControllerPrivate::InfoToPluginMap::ConstIterator it, itEnd;
     it = d->loadedPlugins.begin();
     itEnd = d->loadedPlugins.end();
     for ( ; it != itEnd; ++it )
@@ -441,9 +399,67 @@ void PluginController::shutdownTimeout()
 
 void PluginController::shutdownDone()
 {
-    d->shutdownMode = Private::DoneShutdown;
+    d->shutdownMode = PluginControllerPrivate::DoneShutdown;
     KGlobal::deref();
 }
 
+bool PluginController::checkForDependecies( KPluginInfo* info, QStringList& missing ) const
+{
+    QVariant prop = info->property( "X-KDevelop-IRequired" );
+    bool result;
+    if( prop.canConvert<QStringList>() )
+    {
+        QStringList deps = prop.toStringList();
+        foreach( QString iface, deps )
+        {
+            KPluginInfo::List l = queryPlugins( QString("%1 in X-KDevelop-Interfaces").arg(iface) );
+            if( l.isEmpty() )
+            {
+                result = false;
+                missing << iface;
+            }
+        }
+    }
+    return result;
+}
+
+void PluginController::loadDependecies( KPluginInfo* info )
+{
+    QVariant prop = info->property( "X-KDevelop-IRequired" );
+    if( prop.canConvert<QStringList>() )
+    {
+        QStringList deps = prop.toStringList();
+        foreach( QString iface, deps )
+        {
+            KPluginInfo* info = queryPlugins( QString("%1 in X-KDevelop-Interfaces").arg(iface) ).first();
+            loadPluginInternal( info->pluginName() );
+        }
+    }
+}
+
+IPlugin* PluginController::pluginForExtension( const QString& extension )
+{
+    return pluginForExtension( extension, "" );
+}
+
+IPlugin* PluginController::pluginForExtension( const QString& extension, const QString& constraint )
+{
+    KPluginInfo* info = queryPlugins( QString("%1 in X-KDevelop-Interfaces and %2").arg( extension ).arg( constraint ) ).first();
+    if( d->plugins.contains( info ) )
+    {
+        return d->loadedPlugins[ info ];
+    }else
+    {
+        return loadPluginInternal( info->pluginName() );
+    }
+}
+
+QExtensionManager* PluginController::extensionManager()
+{
+    return m_manager;
+}
+
 }
 #include "plugincontroller.moc"
+
+// kate: space-indent on; indent-width 4; tab-width: 4; replace-tabs on; auto-insert-doxygen on
Index: shell/plugincontroller.h
===================================================================
--- shell/plugincontroller.h	(Revision 625743)
+++ shell/plugincontroller.h	(Arbeitskopie)
@@ -1,4 +1,5 @@
 /* This file is part of the KDE project
+Copyright (C) 2007 Andreas Pakulat <apaku at gmx.de>
 Copyright (C) 2004, 2007 Alexander Dymo <adymo at kdevelop.org>
 Copyright (C) 2006 Matt Rogers <mattr at kde.org
 
@@ -23,7 +24,7 @@ Boston, MA 02110-1301, USA.
 #ifndef KDEVPLUGINCONTROLLER_H
 #define KDEVPLUGINCONTROLLER_H
 
-#include <QObject>
+#include "iplugincontroller.h"
 
 #include <QHash>
 #include <QList>
@@ -43,25 +44,23 @@ namespace Koncrete
 class IPlugin;
 class ProjectInfo;
 class ProfileEngine;
+class PluginControllerPrivate;
 
 /**
  * The KDevelop plugin controller.
  * The Plugin controller is responsible for querying, loading and unloading
  * available plugins.
  */
-class KDEVPLATFORM_EXPORT PluginController: public QObject
+class KDEVPLATFORM_EXPORT PluginController: public IPluginController
 {
 
     Q_OBJECT
 
 public:
-    enum PluginType {
-        Global = 0,
-        Project
-    };
 
-    static PluginController* self();
-    virtual ~PluginController();
+    PluginController();
+
+    ~PluginController();
 
     /**
      * Get the plugin instance based on the ID. The ID should be whatever is
@@ -93,40 +92,15 @@ public:
     void unloadPlugin( const QString & plugin );
 
     /**
-     * Queries for the plugin which supports given service type.
-     * All already loaded plugins will be queried and the first one to support the service type
+     * Queries for the plugin which supports given extension interface.
+     * All already loaded plugins will be queried and the first one to support the extension interface
      * will be returned. Any plugin can be an extension, only "ServiceTypes=..." entry is
      * required in .desktop file for that plugin.
-     * @param serviceType The service type of an extension (like "KDevelop/SourceFormatter")
-     * @param constraint The constraint which is applied when quering for the service. This
-     * constraint is a usual KTrader constraint statement (like "[X-KDevelop-Foo]=='MyFoo'").
+     * @param extension The extension interface
      * @return A KDevelop extension plugin for given service type or 0 if no plugin supports it
      */
-    template <class Extension>
-    Extension *extension(const QString &serviceType, const QString &constraint = QString() )
-    {
-        return static_cast<Extension*>(getExtension( serviceType, constraint ) );
-    }
-
-    /**
-     * Queries KDevelop services. Version is checked automatically
-     * by adding proper X-KDevelop-Version=N statement into the query.
-     * @param serviceType The service type to query, for example "KDevelop/Plugin" or
-     * "KDevelop/SourceFormatter."
-     * @param constraint A constraint for the service. Do not include plugin version number - it
-     * is done automatically.
-     * @return The list of plugin offers.
-     */
-    static KPluginInfo::List query( const QString &serviceType, const QString &constraint );
-
-    /**
-     * Queries KDevelop plugins. Works like KDevPluginController::query
-     * with serviceType set to "KDevelop/Plugin".
-     * @param constraint A constraint for the service. Do not include plugin version number - it
-     * is done automatically.
-     * @return The list of plugin offers.
-     */
-    static KPluginInfo::List queryPlugins( const QString &constraint );
+    IPlugin *pluginForExtension(const QString &extension );
+    IPlugin *pluginForExtension(const QString &extension, const QString& constraint );
 
     /**
      * Reimplement this function only if your shell supports plugin profiles.
@@ -146,8 +120,6 @@ public:
      */
     KUrl::List profileResourcesRecursive( const QString &nameFilter );
 
-    static QStringList argumentsFromService( const KService::Ptr &service );
-
     QString currentProfile() const;
 
     void loadPlugins( PluginType offer );
@@ -158,17 +130,9 @@ public:
     //returns the name of an old profile that was unloaded
     QString changeProfile( const QString &newProfile );
 
-    void shutdown();
+    QExtensionManager* extensionManager();
 
-Q_SIGNALS:
-    void loadingPlugin( const QString& );
-    void pluginLoaded( IPlugin* );
-
-    /**
-     * Emitted when a plugin profile was changed (reloaded, other profile opened, etc.).
-     * Should work only on shells with plugin profiles support.
-     */
-    void profileChanged();
+    void shutdown();
 
 private Q_SLOTS:
     ///A plugin has been destroyed. Cleanup our data structures
@@ -202,22 +166,17 @@ private:
      */
     KPluginInfo * infoForPluginId( const QString &pluginId ) const;
 
-    /**
-     * @internal
-     *
-     * Used for the extension template function
-     */
-    IPlugin* getExtension( const QString&, const QString& );
+    bool checkForDependecies( KPluginInfo* info, QStringList& missing ) const;
 
-private:
-    class Private;
-    Private* d;
+    void loadDependecies( KPluginInfo* );
 
-    PluginController();
-    static PluginController *s_self;
+private:
+    PluginControllerPrivate* d;
+    QExtensionManager* m_manager;
 };
 
 }
 #endif
 
-//kate: auto-insert-doxygen on;
+
+// kate: space-indent on; indent-width 4; tab-width: 4; replace-tabs on; auto-insert-doxygen on
Index: shell/mainwindow.cpp
===================================================================
--- shell/mainwindow.cpp	(Revision 625743)
+++ shell/mainwindow.cpp	(Arbeitskopie)
@@ -91,7 +91,7 @@ MainWindow::MainWindow( Sublime::Control
     setupActions();
 //     setStatusBar( new Koncrete::StatusBar( this ) );
 
-    connect( PluginController::self(), SIGNAL(pluginLoaded(IPlugin*)),
+    connect( Core::self()->pluginController(), SIGNAL(pluginLoaded(IPlugin*)),
              this, SLOT(addPlugin(IPlugin*)));
 
 /*    createGUI( ShellExtension::getInstance() ->xmlFile() );*/
@@ -418,7 +418,7 @@ void MainWindow::newToolbarConfig()
 
 bool MainWindow::queryClose()
 {
-    PluginController::self()->shutdown();
+    Core::self()->pluginController()->shutdown();
     //All Core API objects must release all resources which
     //depend upon one another.
 //     Core::cleanup();
Index: shell/core.cpp
===================================================================
--- shell/core.cpp	(Revision 625743)
+++ shell/core.cpp	(Arbeitskopie)
@@ -20,6 +20,7 @@
 
 #include "mainwindow.h"
 #include "uicontroller.h"
+#include "plugincontroller.h"
 
 namespace Koncrete {
 
@@ -28,8 +29,8 @@ Core *Core::m_self = 0;
 struct CorePrivate {
     CorePrivate()
     {
+        pluginController = new PluginController();
         uiController = new UiController();
-
         mainWindow = new MainWindow(uiController);
         mainWindow->show();
     }
@@ -41,6 +42,7 @@ struct CorePrivate {
 
     UiController *uiController;
     MainWindow *mainWindow;
+    PluginController* pluginController;
 };
 
 void Core::initialize()
@@ -74,5 +76,10 @@ IUiController *Core::uiController()
     return d->uiController;
 }
 
+IPluginController* Core::pluginController()
+{
+  return d->pluginController;
+}
+
 }
 
Index: shell/CMakeLists.txt
===================================================================
--- shell/CMakeLists.txt	(Revision 625743)
+++ shell/CMakeLists.txt	(Arbeitskopie)
@@ -16,6 +16,6 @@ set(koncreteshell_LIB_SRCS
 kde4_automoc(${koncreteshell_LIB_SRCS})
 
 kde4_add_library(koncreteshell SHARED ${koncreteshell_LIB_SRCS})
-target_link_libraries(koncreteshell ${KDE4_KIO_LIBS} ${KDE4_KUTILS_LIBS} ${KDE4_KPARTS_LIBS} ${KDE4_KNOTIFYCONFIG_LIBS} ktexteditor ${KDE4_THREADWEAVER_LIBRARIES} ${BERKELEY_DB_LIBRARIES} koncreteinterfaces sublime )
+target_link_libraries(koncreteshell ${KDE4_KIO_LIBS} ${KDE4_KUTILS_LIBS} ${KDE4_KPARTS_LIBS} ${KDE4_KNOTIFYCONFIG_LIBS} ktexteditor ${KDE4_THREADWEAVER_LIBRARIES} ${BERKELEY_DB_LIBRARIES} ${QT_QTDESIGNER_LIBRARY} koncreteinterfaces sublime )
 set_target_properties(koncreteshell PROPERTIES VERSION 4.0.0 SOVERSION 4)
 install(TARGETS koncreteshell DESTINATION ${LIB_INSTALL_DIR} )
Index: shell/core.h
===================================================================
--- shell/core.h	(Revision 625743)
+++ shell/core.h	(Arbeitskopie)
@@ -35,6 +35,7 @@ public:
 
     virtual KMainWindow *mainWindow();
     virtual IUiController *uiController();
+    virtual IPluginController *pluginController();
 
 private:
     Core(QObject *parent = 0);
-------------- next part --------------
[Desktop Entry]
Type=Service
Name=KDevelop QMake Importer
Comment=Imports and edits qmake projects
Comment[el]=???????????????? ?????? ?????????????????????? ?????????? qmake
Comment[fr]=Importe et modifie des projets qmake
Comment[x-test]=xxImports and edits qmake projectsxx
Icon=gear
ServiceTypes=KDevelop/Plugin
X-KDE-Library=kdevqmakeimporter
X-KDE-PluginInfo-Name=KDevQMakeImporter
X-KDevelop-FileManager=QMake
X-KDevelop-Version=4
X-KDevelop-Interfaces=IBuildManager;IFileManager
X-KDevelop-Required=IProjectBuilder


More information about the KDevelop-devel mailing list