Plug-ins development
Tulip has been built to be easily extensible. Therefore a mechanism of plug-ins has been set up. It enables to directly add new functionalities into the Tulip kernel. One must keeps in mind that a plug-in have access to all the parts of Tulip. Thus, one must write plug-ins very carefully to prevent memory leak and also errors. A bug in plug-in can result in a "core dump" in the software that uses it. To enable the use of plug-ins, a program must call the initialization functions of the plug-ins. This function loads dynamically all the plug-ins and register them into a factory that will enable to directly access to it.
To develop a plug-in, you need to create a new class that will inherits from a specific algorithm class. Algorithms classes are separated in 4 different types :

Basic classes :
Property algorithms :
This kind of plug-ins will only affect a specific property of any type. See The PropertyAlgorithm class..
Generic algorithms :
This kind of plug-ins can be used to modify the entire graph. In other case it is preferable to use a specific class of algorithms to implement your plug-in. See The Algorithm class..
Importation algorithms :
Plug-ins to import a specific graph. For example a plug-in that will create a graph from a file directory system. See Import plug-ins.
Export algorithms :
Plug-ins to save a graph to a specific type of file. See Export plug-ins.

The PropertyAlgorithm class.
The PropertyAlgorithm class, is the class from which inherits different types of algorithms such as the BooleanAlgorithm class or the LayoutAlgorithm class (see picture below). This class is important in the way that every specific algorithm that you will develop will have to inherit from one of those classes. For example, if you write a plug-in to update the graph layout, your new class will have to inherit from the LayoutAlgorithm class which inherits from this PropertyAlgorithm class.
Each one of the 8 classes presented above has a public member, TypeNameProperty* typeNameResult, which is the data member that which have to be updated by your plug-in. After a successful run tulip will automatically copy this data member into the corresponding property of the graph. Following is a table showing the data member, graph property and 'Algorithms' GUI submenu corresponding to each subclass of Algorithm :
Class name	Data member	Graph property replaced	Algorithms GUI submenu
BooleanAlgorithm	booleanResult	viewSelection	Selection
ColorAlgorithm	colorResult	viewColor	Color
DoubleAlgorithm	doubleResult	viewMetric	Measure
Algorithm	NA	NA	General
IntegerAlgorithm	integerResult	viewInt	Integer
LayoutAlgorithm	layoutResult	viewLayout	Layout
SizeAlgorithm	sizeResult	viewSize	Size
StringAlgorithm	stringResult	viewLabel	Label
Note that at anytime, if the user clicks on the "cancel" button ( see The PluginProgress class. for more details ), none of your algorithm's actions will changes the graph since the variable typeNameResult is not copied in the corresponding property.

Overview of the class
A quick overview of the functions and data members of the class PropertyAlgorithm is needed in order to have a generic understanding of its 8 derived classes.

Public members
Following is a list of all public members :
PropertyAlgorithm (const PropertyContext& context) :
The constructor is the right place to declare the parameters needed by the algorithm.
addParameter<DoubleProperty>("metric", paramHelp[0], 0, false);
And to declare the algorithm dependencies.
addDependency<Algorithm>("Quotient Clustering", "1.0");
~PropertyAlgorithm () : Destructor of the class.
bool run () :
This is the main method :
- It will be called out if the pre-condition method (bool check (..)) returned true.
- It is the starting point of your algorithm.
The returned value must be true if your algorithm succeeded.
bool check (std::string& errMsg) :
This method can be used to check what you need about topological properties of the graph, metric properties on graph elements or anything else.

Protected members
Following is a list of all protected members :
Graph* graph :
This graph is the one given in parameters, the one on which the algorithm will be applied.
PluginProgress* pluginProgress :
This instance of the class PluginProgress can be used to have an interaction between the user and our algorithm. See the next section for more details.
DataSet* dataSet :
This member contains all the parameters needed to run the algorithm. The class DataSet is a container which allows insertion of values of different types. The inserted data must have a copy-constructor well done. See the section called DataSet for more details.
The methods of the TypeNameAlgorithm class, will be redefined in your plug-in as shown in Example of a plugin skeleton.

Parameters :
Your algorithm may need some parameters, for example a boolean or a property name, that must be filled in by the user just before being launched. In this section, we will look at the methods and techniques to do so.

Adding parameters to an algorithm
The class PropertyAlgorithm inherits from a class called WithParameters that has a member function named template<typename Type> void addParameter (const char *name, const char *inHelp=0, const char *inDefValue=0, bool isMandatory=true) which is capable of adding a parameter. This method has to be called in the constructor of your class.
Following is a description of its parameters :
name : Name of the new parameter.
inHelp : This parameter can be used to add a documentation to the parameter (See example below).
inDefValue : Default value.
isMandatory : If false, the user must give a value.
On the following example, we declare a character buffer that will contain the documentation of our parameters.

 
namespace {
  const char * paramHelp[] = {
    // property
    HTML_HELP_OPEN() \
    HTML_HELP_DEF( "type", "DoubleProperty" ) \
    HTML_HELP_BODY() \
    "This metric is used to affect scalar values to graph items." \
    "The meaning of theses values depends of the choosen color model." \
    HTML_HELP_CLOSE(),
    // colormodel
    HTML_HELP_OPEN() \
    HTML_HELP_DEF( "type", "int" ) \
    HTML_HELP_DEF( "values", "[0,1]" ) \
    HTML_HELP_DEF( "default", "0" ) \
    HTML_HELP_BODY() \
    "This value defines the type of color interpolation. Following values are valid :" \
    "<ul><li>0: HSV interpolation ;</li><li>1: RGB interpolation</li></ul>" \
    HTML_HELP_CLOSE(),
    // color1
    HTML_HELP_OPEN() \
    HTML_HELP_DEF( "type", "Color" ) \
    HTML_HELP_DEF( "values", "[0,255]^4" ) \
    HTML_HELP_DEF( "default", "red" ) \
    HTML_HELP_BODY() \
    "This is the start color used in the interpolation process." \
    HTML_HELP_CLOSE(),
    // color2
    HTML_HELP_OPEN() \
    HTML_HELP_DEF( "type", "Color" ) \
    HTML_HELP_DEF( "values", "[0,255]^4" ) \
    HTML_HELP_DEF( "default", "green" ) \
    HTML_HELP_BODY() \
    "This is the end color used in the interpolation process." \
    HTML_HELP_CLOSE(),
    // Mapping type
    HTML_HELP_OPEN() \
    HTML_HELP_DEF( "type", "Boolean" ) \
    HTML_HELP_DEF( "values", "true / false" ) \
    HTML_HELP_DEF( "default", "true" ) \
    HTML_HELP_BODY() \
    "This value defines the type of mapping. Following values are valid :" \
    "<ul><li>true : linear mapping</li><li>false: uniform quantification</li></ul>" \
    HTML_HELP_CLOSE(),
  };
}

Then, we can add the parameters in the constructor by writing the following lines:

 
    addParameter<DoubleProperty>("property",paramHelp[0],"viewMetric");
    addParameter<int>("colormodel",paramHelp[1],"1");
    addParameter<bool>("type",paramHelp[4],"true");
    addParameter<Color>("color1",paramHelp[2],"(255,255,0,128)");
    addParameter<Color>("color2",paramHelp[3],"(0,0,255,228)");

The picture below is the result of the sample of code above.

Accessing a parameter
The class PropertyAlgorithm has a protected member called dataSet that contains all the parameters value.The DataSet class implements a container which allows insertion of values of different types and implements the following methods :
template<typename T> bool get (const std::string& name, T value) const :
Returns a copy of the value of the variable with name name. If the variable name doesn't exist return false else true.
template<typename T> bool getAndFree (const std::string& name, T value) :
Returns a copy of the value of the variable with name name. If the variable name doesn't exist return false else true. The data is removed after the call.
template<typename T> void set (const std::string& name, const T value) :
Set the value of the variable name.
bool exist (const std::string& name) const :
Returns true if name exists else false.
Iterator<std::pair<std::string, DataType> >* getValues () const :
Returns an iterator on all values
Has you could have guess, the one important to access a parameter is get() which allows to access to a specific parameter. Following is an example of its use :

 
  DoubleProperty* metricS;
  int colorModel;
  Color color1;
  Color color2;
  bool mappingType = true;
  
  if ( dataSet!=0 ) {
    dataSet->get("property", metricS);
    dataSet->get("colormodel", colorModel);
    dataSet->get("color1", color1);
    dataSet->get("color2", color2);
    dataSet->get("type", mappingType);
  }

The PluginProgress class.
The class PluginProgress can be used to interact with the user. Following is a list of its members

Public members
Following is a list of all Public members :
ProgressState progress (int step, int max_step) :
This method can be used to know the global progress of or algorithm, the number of steps accomplished.
void showPreview (bool) :
Enables to specify if the preview check box has to be visible or not.
bool isPreviewMode () :
Enables to know if the user has checked the preview box.
ProgressState state () const :
Indicates the state of the 'Cancel', 'Stop' buttons of the dialog
void setError (std::string error) :
Shows an error message to the user
void setComment (std::string msg) :
Shows a comment message to the user

PluginProgress example
In following small example, we will iterate over all nodes and notify the user of the progression.

 
  unsigned int i=0;
  unsigned int nbNodes = graph->numberOfNodes ();
  
  const unsigned int STEP = 10;
  
  node n; 
  forEach(n, graph->getInEdges(n))
  {
    ...
    ... // Do what you want
    ...
    if(i%STEP==0)
    {
       pluginProgress->progress(i, nbNodes); //Says to the user that the algorithm has progressed.
        
       //exit if the user has pressed on Cancel or Stop
       if(pluginProgress->state() != TLP_CONTINUE)
       {
          returnForEach pluginProgress->state()!=TLP_CANCEL;
       }
    }    
    i++;
        	
  }

Before exiting, we check if the user pressed stop or cancel. If he pressed "cancel", the graph will not be modified. If he pressed "stop", all values computed till now will be saved to the graph.

Example of a plugin skeleton
Following is an example of a dummy color algorithm ( you can find more example in the tulip tarball ):

 
#include <tulip/TulipPlugin.h>
#include <string>

using namespace std;
using namespace tlp;

/** Algorithm documentation */
// MyColorAlgorithm is just an example
/*@{*/


class MyColorAlgorithm:public ColorAlgorithm { 
public:

  // The constructor below has to be defined,
  // it is the right place to declare the parameters
  // needed by the algorithm,
  // addParameter<DoubleProperty>("metric", paramHelp[0], 0, false);
  // and declare the algorithm dependencies too.
  // addDependency<Algorithm>("Quotient Clustering", "1.0");
  MyColorAlgorithm(PropertyContext& context):ColorAlgorithm(context) {
  }

  // Define the destructor only if needed 
  // ~MyColorAlgorithm() {
  // }

  // Define the check method only if needed.
  // It can be used to check topological properties of the graph,
  // metric properties on graph elements or anything else you need.
  // bool check(string& errorMsg) {
  //   errorMsg="";
  //   return true;
  // }

  // The run method is the main method : 
  //     - It will be called out if the pre-condition method (bool check (..)) returned true.
  //     - It is the starting point of your algorithm.
  // The returned value must be true if your algorithm succeeded.
  bool run() {
    return true;
  }
};
/*@}*/

// This line is very important because it's the only way to register your algorithm in tulip.
// It automatically builds the plugin object that will embed the algorithm.
COLORPLUGIN(MyColorAlgorithm, "My Color Algorithm", "Authors", "07/07/07", "Comments", "1.0")
// If you want to present your algorithm in a dedicated submenu of the Tulip GUI,
// use the declaration below where the last parameter specified the name of submenu.
// COLORPLUGINOFGROUP(MyColorAlgorithm, "My Color Algorithm", "Authors", "07/07/07", "Comments", "1.0", "My algorithms");

The Algorithm class.
The class Algorithm is the class from which your algorithm will inherits if you want to write a more general algorithm. Instead of modifying just a specific property, it can be used to modify the entire graph. In this section, we will list all its members to have a global overview on what we can use to develop such a plug-in.

Public members
Following is a list of all public members :
Algorithm (AlgorithmContext context) :
The constructor is the right place to declare the parameters needed by the algorithm.
addParameter<DoubleProperty>("metric", paramHelp[0], 0, false);
And to declare the algorithm dependencies.
addDependency<Algorithm>("Quotient Clustering", "1.0");
~Algorithm () :
Destructor of the class.
bool run () :
This is the main method :
- It will be called out if the pre-condition method (bool check (..)) returned true.
- It is the starting point of your algorithm.
The returned value must be true if your algorithm succeeded.
bool check (std::string) :
This method can be used to check what you need about topological properties of the graph, metric properties on graph elements or anything else.
The methods below, will be redefined in our plugin (See section plug-in skeleton).

Protected members
Following is a list of all protected members :
Graph* graph :
This graph is the one given in parameters, the one on which the algorithm will be applied.
PluginProgress* pluginProgress :
The class PluginProgress can be used to have an interaction between the user and our algorithm. See The PluginProgress class. for more details.
DataSet* dataSet :
This member contains all the parameters needed to run the algorithm. The class DataSet is a container which allows insertion of values of different types. The inserted data must have a copy-constructor well done. See the section called DataSet for more details.

Import plug-ins
In this section, we will learn how to create import plug-ins. Those plug-ins will inherit from ImportModule.
Following is a small description of the class ImportModule :

Public members
Following is a list of all public members :
ImportModule (AlgorithmContext context) :
The constructor is the right place to declare the parameters needed by the algorithm.
addParameter<DoubleProperty>("metric", paramHelp[0], 0, false);
And to declare the algorithm dependencies.
addDependency<Algorithm>("Quotient Clustering", "1.0");
~ImportModule () :
Destructor of the class.
bool import (const std::string name) :
This is the main method, the starting point of your algorithm.
The returned value must be true if your algorithm succeeds.
The methods below, will be redefined in our plugin (See section plug-in skeleton).

Protected members
Following is a list of all protected members :
Graph* graph :
This graph is the one given in parameters, the one on which the algorithm will be applied.
PluginProgress* pluginProgress :
The class PluginProgress can be used to have an interaction between the user and our algorithm. See The PluginProgress class. for more details.
DataSet* dataSet :
This member contains all the parameters needed to run the algorithm. The class DataSet is a container which allows insertion of values of different types. The inserted data must have a copy-constructor well done. See the section called DataSet for more details.

Skeleton an ImportModule derived class

 #include <tulip/TulipPlugin.h>
#include <string>

using namespace std;
using namespace tlp;

/** Import module documentation */
// MyImportModule is just an example
/*@{*/


class MyImportModule:public ImportModule { 
public:

  // The constructor below has to be defined,
  // it is the right place to declare the parameters
  // needed by the algorithm,
  // addParameter<DoubleProperty>("metric", paramHelp[0], 0, false);
  // and declare the algorithm dependencies too.
  // addDependency<Algorithm>("Quotient Clustering", "1.0");
  MyImportModule(AlgorithmContext context):ImportModule(context) {
  }

  // Define the destructor only if needed 
  // ~MyImportModule() {
  // }

  // The import method is the starting point of your import module.
  // The returned value must be true if it succeeded.
  bool import(const string &name) {
    return true;
  }
};
/*@}*/

// This line is very important because it's the only way to register your import module in tulip.
// It automatically builds the plugin object that will embed the algorithm.
IMPORTPLUGIN(MyImportModule, "My Import Module", "Authors", "07/07/07", "Comments", "1.0")
// If you want to present your algorithm in a dedicated submenu of the Tulip GUI,
// use the declaration below where the last parameter specified the name of submenu.
// IMPORTPLUGINOFGROUP(MyImportModule, "My Import Module", "Authors", "07/07/07", "Comments", "1.0", "My algorithms");

Export plug-ins
In this section, we will learn how to create export plug-ins. Those plug-ins will inherit from ExportModule.
Following is a small description of the class ExportModule :

Public members
Following is a list of all public members :
ExportModule (AlgorithmContext context) :
The constructor is the right place to declare the parameters needed by the algorithm.
addParameter<DoubleProperty>("metric", paramHelp[0], 0, false);
And to declare the algorithm dependencies.
addDependency<Algorithm>("Quotient Clustering", "1.0");
~ExportModule () :
Destructor of the class.
bool import (const std::string name) :
This is the main method, the starting point of your algorithm.
The returned value must be true if your algorithm succeeded.
The methods below, will be redefined in our plugin (See section plug-in skeleton).

Protected members
Following is a list of all protected members :
Graph* graph :
This graph is the one given in parameters, the one on which the algorithm will be applied.
PluginProgress* pluginProgress :
The class PluginProgress can be used to have an interaction between the user and our algorithm. See The PluginProgress class. for more details.
DataSet* dataSet :
This member contains all the parameters needed to run the Algorithm. The class DataSet is a container which allows insertion of values of different types. The inserted data must have a copy-constructor well done. See the section called DataSet for more details.

Skeleton of an ExportModule derived class

 

#include <tulip/TulipPlugin.h>
#include <string>
#include <iostream>

using namespace std;
using namespace tlp;

/** Export module documentation */
// MyExportModule is just an example
/*@{*/


class MyExportModule:public ExportModule { 
public:

  // The constructor below has to be defined,
  // it is the right place to declare the parameters
  // needed by the algorithm,
  // addParameter<DoubleProperty>("metric", paramHelp[0], 0, false);
  // and declare the algorithm dependencies too.
  // addDependency<Algorithm>("Quotient Clustering", "1.0");
  MyExportModule(AlgorithmContext context):ExportModule(context) {
  }

  // Define the destructor only if needed 
  // ~MyExportModule() {
  // }

  // The exportGraph method is the starting point of your export module.
  // The returned value must be true if it succeeded.
  bool exportGraph(ostream &os,Graph *graph) {
    return true;
  }
};
/*@}*/

// This line is very important because it's the only way to register your export module in tulip.
// It automatically builds the plugin object that will embed the algorithm.
EXPORTPLUGIN(MyExportModule, "My Export Module", "Authors", "07/07/07", "Comments", "1.0")
// If you want to present your algorithm in a dedicated submenu of the Tulip GUI,
// use the declaration below where the last parameter specified the name of submenu.
// EXPORTPLUGINOFGROUP(MyExportModule, "My Export Module", "Authors", "07/07/07", "Comments", "1.0", "My algorithms");

Compilation ( Makefiles )
You can download plugins skeletons here .
Following is a Makefile that compiles a plug-in :

 
 # Update the line below according to the tulip installation directory you choosed
TULIP_DIR=/usr/local/bin  
TULIP_CONFIG=$(TULIP_DIR)/tulip-config
TULIP_VERSION=$(shell ${TULIP_CONFIG} --version)
LIB_EXTENSION=$(shell ${TULIP_CONFIG} --pluginextension)

# To limit, crash problems when loading a plugin library
# Tulip only load those whose names end with a compatible version number
TARGET= libmyalgorithm-$(TULIP_VERSION).$(LIB_EXTENSION)

# a plugin library may contain more than one algorithm
# so you can have several source files on the line below
SRCS = MyGeneralAlgorithm.cpp

CXX=g++
CXXFLAGS = -O3 -Wall -DNDEBUG `${TULIP_CONFIG} --cxxflags --plugincxxflags`
LDFLAGS=  `${TULIP_CONFIG} --pluginldflags` `${TULIP_CONFIG} --libs`

OBJS=$(SRCS:.cpp=.o)

DEPS=$(SRCS:.cpp=.d)

all: $(TARGET)

$(TARGET): $(OBJS)
	$(CXX) $(OBJS) -o $@ $(LDFLAGS) $(LIBS) 

clean :
	-rm -f $(TARGET) *.o *.d

install: all
	install $(TARGET) `${TULIP_CONFIG} --pluginpath`

%.d: %.cpp
	$(CXX) -M $(CXXFLAGS) $< \
	| sed 's!\($*\)\.o[ :]*!\1.o $@ : !g' > $@; \
	 [ -s $@ ] 2>/dev/null || rm $@

-include $(DEPS)

Compile and install your plugin

[user@localhost ]$ make

Type make in a terminal.

 [user@localhost ]$ make install

Type make install in a terminal. Be careful that you may need root privileges to do this.

[user@localhost ]$ make clean

'make clean', will remove all generated files (libraries, *.o , ...)