How to: Create an NCL Composer Plugin

This page is a draft
This tutorial assumes you are familiar with C/C++ programming languages and have basic knowledge about Qt framework (mainly the qmake build system and signals & slots mechanism).

A plugin is a piece of software distributed separated from other software (the main or host) aiming to extend its functionalities. In order to allow extensions and customizations NCL Composer architecture is based on plugins.

A common way to extend the NCL Composer functionalities is creating new Views to documents being developed. A View is a plugin that brings out a representation of this document (e.g. showing its entities in a tree, or showing how this document is represented in a timeline, etc.).

An NCL Composer plugins is based on two main C++ interfaces that must to be implemented: IPluginFactory and IPlugin.

IPluginFactory

The IPluginFactory is responsible to create new instances of IPlugin's, and keep global informations about the plugin, like its vendor, version, etc. Every time a document is open, the NCL Composer will try to create a new instance of the plugin calling IPluginFactory's method. But if your plugin is a singleton, you can always returns the same instance.

IPlugin

The IPlugin is the NCL Composer plugin itself. When a document is open by NCL Composer, a new instance of the plugin will be required by NCL Composer. The IPlugin is linked with the Document instance and will be called every time this document is changed. Likewise, the IPlugin is also able to require changes in the Document.

An example: Debug Plugin

As a simple example, let's create a Debug Plugin. This plugin will print all the messages that it receives from NCL Composer core.

First of all, let's create our DebugConsolePlugin.h:

#ifndef DEBUGCONSOLEPLUGIN_H
#define DEBUGCONSOLEPLUGIN_H
 
#include <QObject>
#include <core/extensions/IPlugin.h>
 
using namespace composer::core::extension::plugin;
 
class DebugConsolePlugin : public IPlugin
{
        Q_OBJECT
    private:
        QWidget *window;
 
    public:
        explicit DebugConsolePlugin();
        ~DebugConsolePlugin();
 
        QWidget* getWidget();
	bool init();
 
    public slots:
        void onEntityAdded(QString ID, Entity *);
        void onEntityChanged(QString ID, Entity *);
        void onEntityRemoved(QString ID, QString entityID);
 
        void errorMessage(QString error);
};
 
#endif // DEBUGCONSOLEPLUGIN_H

And the DebugConsole.cpp:

#include "DebugConsolePlugin.h"
 
DebugConsolePlugin::DebugConsolePlugin()
{
  // Do nothing
}
 
DebugConsolePlugin::~DebugConsolePlugin()
{
  // Do nothing
}
 
void DebugConsolePlugin::init()
{
  // Do nothing
}
 
QWidget* DebugConsolePlugin::getWidget()
{
    return NULL; /*This tell to NCL Composer that our plugin doesn't have a GUI*/
}
 
void DebugConsolePlugin::onEntityAdded(QString ID, Entity *entity)
{
    QString line = "PLUGIN (" + ID + ") added the Entity (" +
                   entity->getType() + " - " + entity->getUniqueId() +")";
    qDebug() << line;
}
 
void DebugConsolePlugin::errorMessage(QString error)
{
    qDebug() << "ERROR:" << error;
}
 
void DebugConsolePlugin::onEntityChanged(QString ID, Entity * entity)
{
    QString line = "PLUGIN (" + ID + ") changed the Entity (" +
                    entity->getType() + " - " + entity->getUniqueId() +")";
    qDebug() << line;
}
 
void DebugConsolePlugin::onEntityRemoved(QString ID, QString entityID)
{
    QString line = "PLUGIN (" + ID + ") removed Entity (" +
                   entityID + ")";
    qDebug() << line;
}

In order to NCL Composer know how to create new instances of our DebugPlugin, we have to provide a Factory class:

#ifndef DEBUGCONSOLE_H
#define DEBUGCONSOLE_H
 
#include "DebugConsole_global.h"
#include "DebugConsolePlugin.h"
 
#include <core/extensions/IPluginFactory.h>
using namespace composer::extension;
 
class DebugConsoleFactory : public QObject,
                            public IPluginFactory
{
    Q_OBJECT
    Q_INTERFACES(IPluginFactory)
 
    public:
         DebugConsoleFactory();
         ~DebugConsoleFactory();
         IPlugin* createPluginInstance();
         void releasePluginInstance(IPlugin *);
 
         /* Global information about DebugPlugin. */
         QString id() const {return "br.puc-rio.telemidia.DebugPlugin";};
         QString name() const {return "Debug Plugin";};
 
         QString version() { return "0.1"; }
         QString compatVersion() {return "0.1";}
         QString vendor() {return "Telemidia Lab";}
         QString copyright() {return "Telemidia/PUC-Rio";}
         QString description() {return "Debug Console View prints all the messages send by NCL Composer to plugins.";}
         QString url() {return "http://composer.telemidia.puc-rio.br/debug";}
         QString category() {return "Debug";}
 
};
#include "DebugConsoleFactory.h"
 
namespace composer {
    namespace plugin {
        namespace debug {
 
DebugConsoleFactory::DebugConsoleFactory()
{
  //Do nothing
}
 
DebugConsoleFactory::~DebugConsoleFactory()
{
  //Do nothing
}
 
IPlugin* DebugConsoleFactory::createPluginInstance()
{
    return new DebugConsolePlugin();
}
 
void DebugConsoleFactory::releasePluginInstance(IPlugin *plugin)
{
    DebugConsolePlugin *debug = qobject_cast<DebugConsolePlugin*>(plugin);
 
    if (debug)
    {
        delete debug;
        debug = NULL;
    }
 
}
 
// This is very important, and will allow to Qt framework recognize your
// plugin
Q_EXPORT_PLUGIN2(DebugConsole,DebugConsoleFactory)
 
} } } //end namespace