Extension Interfaces and Plugins
From KDevelop
The idea behind extension interfaces is to provide following features:
- To allow plugins to expose their functionality via abstract interfaces and at the same time do not care about BC and do not force other plugins to link with them. Documentation plugin would be a good example of non-core but still sometimes useful functionality that might be exported via IDocumentation extension interface with methods like lookupInDocumentation(const QString &) and others. KDevelop4's outputview plugin with IOutputView interface is also a good and actually working example of such use-case.
- To have implementations of important functionality not in a shell, but in plugins. Good examples are buildsystem managers, builders and language supports in KDevelop4. When a project is opened, a buildsystem manager plugin (that implements either IBuildSystemManager interface or IProjectFileManager) is looked for by the shell an loaded.
- To forget about BC issues of dependent plugins. In case the plugin has something new to expose, the new version of extension interface has to be defined. All other plugins will either continue using old interface or ask for the new one.
The extension interfaces framework is implemented with QExtensionManager and Co. See the Qt documentation for reference.
Contents |
[edit] To declare extension interface
- Create an abstract class
- Include <iextension.h>
- Add following macros to the header file with a class (if you use a namespace):
KDEV_DECLARE_EXTENSION_INTERFACE_NS( KDevelop, IMyInterface, "org.kdevelop.IMyInterface")
Q_DECLARE_INTERFACE( KDevelop::IMyInterface, "org.kdevelop.IMyInterface" )
- or use (when the interface is not in a namespace)
KDEV_DECLARE_EXTENSION_INTERFACE( IMyInterface, "org.kdevelop.IMyInterface" )
Q_DECLARE_INTERFACE( IMyInterface, "org.kdevelop.IMyInterface" )
[edit] To implement extension interface
- Create a plugin as usual
- Subclass it from your interface
- Use Q_INTERFACES macro in class declaration
- use KDEV_USE_EXTENSION_INTERFACE macro in the constructor of the plugin
KDEV_USE_EXTENSION_INTERFACE( IMyInterface )
- declare in plugin's .desktop file:
X-KDevelop-Interfaces=IMyInterface
- Code Example:
class MyPlugin: public KDevelop::IPlugin, public KDevelop::IMyInterface {
Q_OBJECT
Q_INTERFACES(KDevelop::IMyInterface)
public:
MyPlugin( QObject* parent ) : IPlugin( parent )
{
KDEV_USE_EXTENSION_INTERFACE( KDevelop::IMyInterface )
}
};
[edit] To load a plugin that supports extension interface
- Use IPluginController::pluginForExtension() method if you have only one possible plugin implementing the extension interface
- Or use IPluginController::allPluginsForExtension() method to return a list of plugins. Note, that those methods will load plugins if they are not yet loaded
- Once IPlugin pointer is returned by one of two methods above, it can be asked for an extension using Plugin::extension<>() method ( like plugin->extension<IMyInterface>() )
[edit] To set a dependency between plugins
- Set the list of required interfaces in plugin's .desktop file
X-KDevelop-IRequired=IMyInterface,IMyOtherInterface
- It is not possible to set direct inter-plugin dependencies. The plugin shall never expect another plugin, it shall only expect an interface.