How to: Create an NCL Composer Plugin

This page is a draft
This page describe NCL Composer plug-in API since version 0.2.x. If you are looking this tutorial for a previous version, please look at this page.
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.).

Since version 0.2.x NCL Composer plugins are based on Qt5 plug-in system. A plug-in is composed of one C++ interface (IPlug-in) implementation and a .json file that describe this plug-in.

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::extension;
 
class DebugConsolePlugin : public IPlugin
{
  Q_OBJECT
 
private:
  QWidget *window;
public:
  explicit DebugConsolePlugin();
  ~DebugConsolePlugin();
 
  void init();
  QWidget* getWidget();
 
public slots:
  void onEntityAdded(QString pluginID, Entity *);
  void onEntityChanged(QString pluginID, Entity *);
  void onEntityRemoved(QString pluginID, 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()
{
  qDebug() << "DEBUG MESSAGE:IT STARTED" ;
}
 
QWidget* DebugConsolePlugin::getWidget()
{
    return NULL;/*No window to return,
  This tells to NCL Composer that our plugin doesn't have a GUI*/
}
 
void DebugConsolePlugin::onEntityAdded(QString pluginID, Entity *entity)
{
  QString line = "DEBUG MESSAGE:PLUGIN (" + pluginID + ") added the Entity (" +
      entity->getType() + " - " + entity->getUniqueId() +")";
  qDebug() << line;
}
 
void DebugConsolePlugin::errorMessage(QString error)
{
  qDebug() << "DEBUG MESSAGE:ERROR - " << error;
}
 
void DebugConsolePlugin::onEntityChanged(QString pluginID, Entity * entity)
{
  QString line = "DEBUG MESSAGE: PLUGIN (" + pluginID + ") changed the Entity (" +
      entity->getType() + " - " + entity->getUniqueId() +")";
  qDebug() << line;
}
 
void DebugConsolePlugin::onEntityRemoved(QString pluginID, QString entityID)
{
  QString line = "DEBUG MESSAGE: (" + pluginID + ") 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: a DebugConsoleFactory.h

#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)
 
#if QT_VERSION >= 0x050000
  Q_PLUGIN_METADATA(IID IPluginFactory_iid FILE "DebugConsole.json")
#endif
 
public:
  DebugConsoleFactory();
  ~DebugConsoleFactory();
  IPlugin* createPluginInstance();
  void releasePluginInstance(IPlugin *);
  QList<LanguageType> getSupportedLanguages();
  QString id() const ;
  QIcon icon() const;
  QWidget* getPreferencePageWidget();
 
#if QT_VERSION < 0x050000
  QString name() { return tr("Debug Console"); }
  QString version() { return NCLCOMPOSER_PLUGINS_VERSION; }
  QString compatVersion() {return "0.1";}
  QString vendor() {return "Telemidia Lab";}
  QString copyright() {return "Telemidia/PUC-Rio";}
  QString license() {return "LGPL";}
  QString description() {return tr("Debug Console View prints all the "
                                   " messages send by composer-core to plugins.");}
  QString url() {return "http://composer.telemidia.puc-rio.br/debug";}
  QString category() {return tr("General");}
#endif
 
};
#endif // DEBUGCONSOLE_H

and its DebugConsoleFactory.cpp

#include "DebugConsoleFactory.h"
 
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;
    }
}
 
QList<LanguageType> DebugConsoleFactory::getSupportedLanguages()
{
  QList<LanguageType> lTypes;
  lTypes.append(NCL);
  return lTypes;
}
 
QString DebugConsoleFactory::id() const
{
  return "br.puc-rio.telemidia.DebugConsole";
}
 
QIcon DebugConsoleFactory::icon()  const
{
  return QIcon(":/images/icon.png");
}
 
QWidget* DebugConsoleFactory::getPreferencePageWidget()
{
  return NULL;
}
#if QT_VERSION < 0x050000
Q_EXPORT_PLUGIN2(DebugConsole,DebugConsoleFactory)
#endif

the DebugConsole_global.h used by the factory file:

#ifndef DEBUGCONSOLE_GLOBAL_H
#define DEBUGCONSOLE_GLOBAL_H
 
#include <QtCore/qglobal.h>
 
#if defined(DEBUGCONSOLE_LIBRARY)
#  define DEBUGCONSOLESHARED_EXPORT Q_DECL_EXPORT
#else
#  define DEBUGCONSOLESHARED_EXPORT Q_DECL_IMPORT
#endif
 
#endif // DEBUGCONSOLE_GLOBAL_H

Additionally, you will also need to define the debugplugin.json file describing your plug-in:

{
  "name" : "Debug Console Plug-in",
  "version" : "0.2.0",
  "compatVersion" : "0.2.0",
  "vendor" : "TeleMidia Lab",
  "description" : "Debug Console View prints all the messages sent by NCL Composer to plugins.",
  "url" : "http://composer.telemidia.puc-rio.br/plugin/debug",
  "category" : "Debug"  
  "dependencies" : []
}