Tulip Devhandbook
Tulip Devhandbook
iii
Tulip
De-
vel-
oper
Hand-
book 3.15.2. 2. The Main function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
4. Tulip Open GL Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
4.1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
4.2. 2D/3D for Tulip . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
4.2.1. Augmented Displays with GlEntity system . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
4.2.2. GlSimpleEntity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
4.2.3. Gl 2D/3D classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
4.2.4. Scene and layers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
4.2.5. Examples of Gl shape uses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
5. Tulip QT Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
5.1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
5.2. Interactors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
5.2.1. Interactor example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
5.2.2. Interactor Component . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
5.2.3. Interactor itself . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
5.2.4. INTERACTORPLUGIN macro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
5.3. Views . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
5.3.1. View example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
5.3.2. How to create a view . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
5.3.3. An other solution : Use AbstractView or GlMainView . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
5.4. Controllers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
5.4.1. Empty Controller . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
5.4.2. Controller example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
5.4.3. ControllerPluginExample . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
5.4.4. ControllerAlgorithmTools class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
5.4.5. ControllerViewsTools class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
5.4.6. ControllerViewsManager class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
6. Plug-ins development . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
6.1. The PropertyAlgorithm class. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
6.1.1. Overview of the class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
6.1.2. Parameters : . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
6.1.3. The PluginProgress class. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
6.1.4. Example of a plugin skeleton . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
6.2. The Algorithm class. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
6.2.1. Public members . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
6.2.2. Protected members . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
6.3. Import plug-ins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
6.3.1. Public members . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
6.3.2. Protected members . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
6.3.3. Skeleton an ImportModule derived class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
6.4. Export plug-ins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
6.4.1. Public members . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
6.4.2. Protected members . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
6.4.3. Skeleton of an ExportModule derived class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
6.5. Compilation ( Makefiles ) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
7. Tulip graph format . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
7.1. Nodes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
7.2. Edges . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
7.3. Clusters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
7.4. Definitions of properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
7.4.1. Property Type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
7.5. Properties of Tulip . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
7.6. GlScene . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
8. Programming Guidelines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
8.1. Generalities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
8.2. Naming conventions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
8.3. Code Comments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
8.4. Integration in Tulip project . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
iv
Tulip
De-
vel-
oper
Hand-
book 8.4.1. GNU Build system . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
8.4.2. File adds . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
8.4.3. Compilation directives : Makefile.am . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
8.4.4. Variable prefix . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
8.4.5. References . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
9. Documentation Guidelines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
9.1. Definitions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
9.2. Tools installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
9.2.1. Docbook XSL Stylesheet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
9.2.2. Doxygen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
9.3. Handwriting for the manuals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
9.3.1. Some Tricks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
9.3.2. Docbook FAQ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
9.4. Code documentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
9.4.1. Presentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
9.4.2. Developer comments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
9.4.3. Doxygen FAQ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
9.5. References . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
v
List of Examples
9.1. Doxygen : A simple source file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
vi
Chapter 1. Introduction
Tulip is a software system for the area of the Information visualization. It is becoming more and more
useful for the correct analysis of existing data sets. This need results from progress in data acquisition
methods, and from the huge effort made to build computer access to the human knowledge. As an
example, for the human genome database, the raw data acquisition phase seems to be completed;
however, to reach the ultimate goal of providing new medical treatment, it is necessary to understand
these data. In such an application, the information visualization views of the data in order to explore
and extend knowledge.
Here we focus on data that can be represented by a graph. In most of cases a graph structure can be
extracted from existing data sets. The most well-known is the World Wide Web where links between
pages can be considered as edges and pages as nodes. Another one is the human metabolism data-set
where chemical reactions can be embedded in a Petri net, literature co-citations are modeled as edges
between nodes of this network, and metabolic pathway are considered as clusters of the resulting
graph.
Systems to visualize graphs have come to the fore during the last ten years. To our knowledge, no one
provides the following capabilities simultaneously :
• Management of clusters
To experiment with tools to handle graphs of the size of those induced by the human genome data
set, one needs a software solution with all these capabilities. That’s why we decided to build our own
graph visualization software that meets these requirements. Tulip has been developed in C++, and
uses two well-known libraries, OpenGL and Qt. The final program enables visualization, clustering
and automatic drawing of graphs with up to 1.000.000 elements on personal computer.
This manual is an help necessary for the developers of an application using Tulip libraries and for
the developers of the Tulip Team. It explains how to compile the libraries and the software, it does
a presentation of the main methods available on the libraries. Chapters relate the programming and
documentation guidelines.
1
Chapter 2. Installation
The “configure” shell script attempts to guess correct values for various system-dependent variables
used during compilation. It uses those values to create a Makefile in each directory of the package.
It may also create one or more .h files containing system-dependent definitions. Finally, it creates a
shell script config.status that you can run in the future to recreate the current configuration, a file
config.cache that saves the results of its tests to speed up reconfiguring, and a file config.log
containing compiler output (useful mainly for debugging configure).
If you need to do unusual things to compile the package, please try to configure out how configure
could check whether to do them, and mail diffs or instructions to the address given in the README so
they can be considered for the next release. If at some point config.cache contains results you
don’t want to keep, you may remove or edit it.
The file configure.in is used to create configure by a program called autoconf. You
only need “configure.in” if you want to change it or regenerate configure using a newer version of
autoconf.
1. cd to the directory containing the package’s source code and type ./configure to configure
the package for your system. If you’re using csh on an old version of System V, you might need to
type sh ./configure instead to prevent csh from trying to execute configure itself. To know all
of the possible options, type ./configure --help or read the next section about options.Running
configure takes awhile. While running, it prints some messages telling which features it is checking
for.
3. Optionally, type make check to run any self-tests that come with the package.
4. Type make install to install the programs, data files and documentation.
5. You can remove the program binaries and object files from the source code directory by typing
make clean. To also remove the files that configure created (so you can compile the package for
a different kind of computer), type make distclean. There is also a make maintainer-clean
target, but that is intended mainly for the package’s developers. If you use it, you may have to get all sorts
of other programs in order to regenerate files that came with the distribution.
If you don’t find the configure shell, you have to generate it with gen-conf.sh. The processing
using the GNU build sytem gives a configure shell.
Caution
Verify QTDIR is properly set : QTDIR/bin should contain moc, qtconfig... , QTDIR/lib the libs
and QTDIR/include the Qt headers ...
To compile the documentations, type make html and make install to install the documentation
the share directory.
2.1. Options
In this section, you can find the most used options. To know all of the possible options, type
./configure --help
2
In-
stal-
la-
tion
--prefix = value
The value is the path where you want to install Tulip. bin, include, lib directories was
created in this location. By default, it is /usr/local/.
--enable-debug
Add compilation flags to allow debugging.
--enable-maintainer-mode = value
Enable make rules and dependencies not useful (and sometimes confusing) to the casual installer.
For example, if you modify a Makefile.am file, it is detected and the Makefile is updated.
--CXXFLAGS
Enable to specify special tags for the g++ compiler. It is an important part to have great
performings. For example, you can specify the architecture of your PC : --CXXFLAGS="-
DNDEBUG -O3 --funroll-loops -mtune=pentium4 -narch=pentium4 -pipe". For more
informations about the options of compilations for g++, see the web site of gcc, here1 .
1 http://gcc.gnu.org/onlinedocs/gcc-4.0.1/gcc/Submodel-Options.html#Submodel-Options
3
Chapter 3. Tulip Library
3.1. Introduction
Efficient visualization of graphs and their usage for data analysis implies
• the computation of intrinsic parameters (parameters derived from a graph’s structure, e.g. in a
filesystem graph (directory tree): number of files in a directory, can be computed by counting outgoing edges)
• the computation of extrinsic parameters (parameters derived from external information, e.g. in a
filesystem graph: file size)
This chapter describes the Tulip data structure that takes into account all the requirement of a graph
visualization system. For each part we describe the general principle and then we give examples
explaining how to do it with the Tulip library.
3.2. Graphs
The core of the Tulip library provides an interface for the manipulation of graphs. It enables one to
access and modify the structure of a graph. The aim of this library is to be as general as possible and
thus it manipulates a general class of graphs called directed pseudo-graphs. In a pseudo graph, there
can be more than one edge between two nodes, and loops are permitted. A loop is an edge that links
a node to itself. Furthermore, edges are directed, thus an edge u->v is distinct from an edge v->u.
Because we use pseudo-graphs, there can be more than one edge u->v, so it is not possible to
distinguish two edges using only source and target (u,v). To make this possible, all the elements
in Tulip are entities (C++ objects). Thus, even if two edges have the same source and the same target,
they are distinct.
The elements of a graph are encapsulated in the graph. It is therefore not possible to access the graph’s
structure through elements, all operations must be done by querying the graph. For example, to know
the source of an edge e of graph G, one must ask G, not e, what e’s source is. This makes the use of
the library less intuitive, but it minimizes memory usage for entities and allows to share them between
subgraphs. Building a container of elements is cheap, because to handle elements, Tulip uses objects
which use the same amount of storage as integers.
The library supports access and modification of the graph structure. The access to the structure are
made by using iterators, one very important point is that the iterator are not persistent. Thus, if one
modify the graph structure all the iterators on the graph structure can be invalid. This property enables
to prevent from cloning the data structure and thus enables better access to it. For ease of use, Tulip
includes mechanism that enables to transform an iterator into stable iterator, one must keep in mind
that it corresponds to clone the data structure and thus, it should be use only if it is necessary.
If one uses Tulip only for the manipulation of one graph (no graph hierarchy), the list of available
operations on the graph is given afterward. In the next section we will enhance the set of operations
and the actions that they perform in order to manage a hierarchy of subgraphs
4
Tulip
Library
• node addNode() : creates a new node in the graph and returns its identifier.
• edge addEdge(node,node) : create a new edge in the graph, given the source and target.
• unsigned int outdeg(node) : returns the out degree of a node (number of times it is a
source).
One of the strong point of Tulip is to ensure efficiently that all elements are shared between graphs
in a hierarchy of graphs. Thus, if a node n is an element of a graph G and of a graph G’, the entity n
is the same in both graphs. Of course, the parameters of the entity can change between graphs. For
instance, the degree of n can be smaller for a subgraph, as it can have less edges.
The subgraph relation in the hierarchy is preserved when one modifies a graph. This means that if one
adds a node to a graph, this node is automatically added to all its ancestors as well. If one deletes a
node, this node is automatically deleted from all the descendants of the graph. If one reverses an edge,
this edge is reversed in all the graphs of the hierarchy.
In order to manipulate a hierarchy of graphs, more functions have been added to those introduced
above. They provide navigation and modification for the hierarchy. The access to the hierarchy is
provided by iterators, which are not persistent and thus, if the hierarchy is modified, the iterators are
invalid.
5
Tulip
Library
• edge addEdge(edge) : adds an edge element from another graph in the hierarchy.
• void addNode(node) : adds a node element from another graph in the hierarchy.
• Graph * getSuperGraph() : returns the parent of the graph. If the graph has no parent, it
returns the graph itself.
3.4. Attributes
An attributes is a kind of property that can be associated to a graph. An attributes has a name (a string)
and a value of any type. It can be, for example ,the name of a graph, or a date of creation of the graph.
Attributes can be added and accessed with those three following member functions :
3.5. Properties
In Tulip, a property is an attribute of an element of a graph. It is called a property in order to prevent
confusion with attributes of a graph: properties are for elements and attributes are for graphs. In Tulip,
a property is always defined for both kinds of elements (nodes and edges), so one can always query
for the value of the property associated with any edge or node.
To access the value of an elements one must query the graph for a property. This makes the use of the
library less intuitive, but it minimizes memory usage for properties.
A property can be seen as an associative table where you can set and get the value for every element.
All property operations have a TYPE argument, so there is no need to cast the result of a property
query. The standard operations of a property are:
6
Tulip
Li-
brary
For each property type there is a specific implementation (subclass) that allows operations which are
specific to the property type (see Tulip libraries documentation). For instance, it is possible to obtain
the maximum value of a property if the property type is double.
For the property mechanism described above to work with a hierarchy of graphs, a mechanism have
been added to share properties between graphs, which works like this: if a property exists in an
ancestor of a graph G, it also exists in the graph G. Thus, properties of graphs are inherited like
members of objects in object-oriented languages. In order to facilitate the navigation/edition of
properties, a set of function is accessible through the graph interface.
7
Tulip
Li-
brary
• Follow the tutorials, one by one, from the first one to the last one.
• You can find at the end of each tutorial, the integral source code that we used.
• If you want more details on a specific function or class please read the Tulip Graph library
documentation1 .
#include <iostream>
#include <tulip/Graph.h>
1 ../../doxygen/tulip.html
8
Tulip
Library
• iostream : This "file" contains the C++ standard declarations for in and out streams. We need
it in this tutorial to print the final graph on the standard output.
• tulip/Graph.h : This file is the core of the tulip graph API. It provides declarations for
graphs (edges , nodes) and functions to load one from a file, to save one, and a lot more. You can find a list in
the Tulip Graph library documentation2 .
int main() {
//create an empty graph
Graph *graph = tlp::newGraph();
2 ../../doxygen/tulip-lib/Graph_8h.html
9
Tulip
Library
Note
The edge is also added in all the super-graph of the graph to maintain the sub-graph relation between
graphs.
The first parameter is the "source node", and, of course, the second is the "target node" (in tulip, every
edge are oriented but you can choose not to consider the orientation). We will see later (TUTORIAL
005) that the edges enumeration order is the one in which they are added.
Following is a picture of the graph that we just have created. It is being displayed with tulip.
10
Tulip
Li-
brary
Note
The class Graph implements member functions like void delAllNode (const node), and,
void delAllEdge (const edge).
//delete an edge
graph->delEdge(e1);
//delete a node
graph->delNode(n2);
11
Tulip
Library
./tutorial001
/**
*
* Tutorial 001
*
* Create a graph
* add three nodes and three edges
* remove an edge and a node
* print the result on the standard output
*
*/
int main() {
//create an empty graph
Graph *graph = tlp::newGraph();
//delete an edge
graph->delEdge(e1);
12
Tulip
Li-
brary
//delete a node
graph->delNode(n2);
tlp::saveGraph(graph,"tuto1.tlp");
In this tutorial, the graph created is the same that in Tutorial 1 (after the 3 edges were added) see the
following picture :
13
Tulip
Library
#include <iostream>
#include <tulip/Graph.h>
• iostream : This "file" contains the C++ standard declarations for in and out streams. We need
it in this tutorial to print the final graph on the standard output.
• tulip/Graph.h : This file is the core of the tulip graph API. It provides declarations for
graphs (edges , nodes) and functions to load one from a file, to save one, and a lot more. You can find a list in
the doxygen documentation3 .
As you can see, we just need the "Graph.h" header file to create a graph and iterate over its nodes,
even though the declaration of the abstract class "Iterator" is in Iterator.h
With the functions template <class itType > bool tlp::Iterator< itType
>::hasNext ( ) and node next ( ), we can iterate through our graph nodes with a simple
while :
while(itNodes->hasNext()) {
node n = itNodes->next();
At the end of the loop, we will need to delete the iterator: delete itNodes;
14
Tulip
Library
node: 0
degree: 2
in-degree: 1
out-degree: 1
node: 1
degree: 2
in-degree: 1
out-degree: 1
node: 2
degree: 2
in-degree: 1
out-degree: 1
//===========================
//iterate all predecessors of a node
cout << " predecessors: {";
Iterator<node> *itN=graph->getInNodes(n);
while(itN->hasNext()) {
cout << itN->next().id;
if (itN->hasNext()) cout << ",";
} delete itN; //!!!Warning : do not forget to delete iterators (memory leak)
//===========================
//iterate all successors of a node
cout << " successors: {";
itN = graph->getOutNodes(n);
while (itN->hasNext()) {
cout << itN->next().id;
if (itN->hasNext()) cout << ",";
} delete itN; //!!!Warning : do not forget to delete iterators (memory leak)
15
Tulip
Library
//===========================
//iterate the neighborhood of a node
cout << " neighborhood: {";
itN = graph->getInOutNodes(n);
while(itN->hasNext()) {
cout << itN->next().id;
if (itN->hasNext()) cout << ",";
} delete itN; //!!!Warning : do not forget to delete iterators (memory leak)
//===========================
//iterate the incoming edges
cout << " incoming edges: {";
Iterator<edge> *itE=graph->getInEdges(n);
while(itE->hasNext()) {
cout << itE->next().id;
if (itE->hasNext()) cout << ",";
} delete itE; //!!!Warning : do not forget to delete iterators (memory leak)
//===========================
//iterate the outcomming edges
itE = graph->getOutEdges(n);
while(itE->hasNext()) {
cout << itE->next().id;
if (itE->hasNext()) cout << ",";
} delete itE; //!!!Warning : do not forget to delete iterators (memory leak)
16
Tulip
Li-
brary
//===========================
//iterate the adjacent edges
cout << " adjacent edges: {";
itE = graph->getInOutEdges(n);
while(itE->hasNext()) {
cout << itE->next().id;
if (itE->hasNext()) cout << ",";
} delete itE; //!!!Warning : do not forget to delete iterators (memory leak)
//===========================
//Iterate all edges
Iterator<edge> *itEdges=graph->getEdges();
while(itEdges->hasNext()) {
edge e = itEdges->next();
cout << "edge: " << e.id;
cout << " source: " << graph->source(e).id;
cout << " target: " << graph->target(e).id;
cout << endl;
} delete itEdges; //!!!Warning : do not forget to delete iterators (memory leak)
• A variable :
• An Iterator for the same type as the variable, for example : Variable of type node,
Graph::getNodes().
17
Tulip
Library
Warning
#include <tulip/ForEach.h>
//...
//main
//load Graph
//...
node n = graph->getOneNode();
cout << "In Edges :" << endl;
edge e;
forEach(e, graph->getInEdges(n))
{
cout << e.id << ",";
}
//...
/**
* Tutorial 002
*
* Create a graph
* display all the structure using iterators
*
*/
18
Tulip
Library
int main() {
//create an empty graph
Graph *graph=tlp::newGraph();
//===========================
//Iterate all nodes and display the structure
Iterator<node> *itNodes = graph->getNodes();
while(itNodes->hasNext()) {
node n = itNodes->next();
cout << "node: " << n.id << endl;
cout << " degree: " << graph->deg(n) << endl;
cout << " in-degree: " << graph->indeg(n) << endl;
cout << " out-degree: " << graph->outdeg(n) << endl;
//===========================
//iterate all ancestors of a node
cout << " ancestors: {";
Iterator<node> *itN=graph->getInNodes(n);
while(itN->hasNext()) {
cout << itN->next().id;
if (itN->hasNext()) cout << ",";
} delete itN; //!!!Warning : do not forget to delete iterators (memory leak)
//===========================
//iterate all successors of a node
cout << " successors: {";
itN = graph->getOutNodes(n);
while (itN->hasNext()) {
cout << itN->next().id;
if (itN->hasNext()) cout << ",";
} delete itN; //!!!Warning : do not forget to delete iterators (memory leak)
//===========================
//iterate the neighborhood of a node
cout << " neighborhood: {";
itN = graph->getInOutNodes(n);
while(itN->hasNext()) {
cout << itN->next().id;
if (itN->hasNext()) cout << ",";
} delete itN; //!!!Warning : do not forget to delete iterators (memory leak)
//===========================
//iterate the incoming edges
cout << " incoming edges: {";
Iterator<edge> *itE=graph->getInEdges(n);
while(itE->hasNext()) {
cout << itE->next().id;
if (itE->hasNext()) cout << ",";
19
Tulip
Li-
brary
//===========================
//iterate the outcomming edges
itE = graph->getOutEdges(n);
while(itE->hasNext()) {
cout << itE->next().id;
if (itE->hasNext()) cout << ",";
} delete itE; //!!!Warning : do not forget to delete iterators (memory leak)
//===========================
//iterate the adjacent edges
cout << " adjacent edges: {";
itE = graph->getInOutEdges(n);
while(itE->hasNext()) {
cout << itE->next().id;
if (itE->hasNext()) cout << ",";
} delete itE; //!!!Warning : do not forget to delete iterators (memory leak)
//===========================
//Iterate all edges
Iterator<edge> *itEdges=graph->getEdges();
while(itEdges->hasNext()) {
edge e = itEdges->next();
cout << "edge: " << e.id;
cout << " source: " << graph->source(e).id;
cout << " target: " << graph->target(e).id;
cout << endl;
} delete itEdges; //!!!Warning : do not forget to delete iterators (memory leak)
20
Tulip
Library
Following is an example :
21
Tulip
Library
metric->setAllNodeValue(0.0);
metric->setAllEdgeValue(0.0);
select->setAllNodeValue(false);
select->setAllEdgeValue(false);
layout->setAllNodeValue(Coord(0,0,0)); //coordinates
layout->setAllEdgeValue(vector<Coord>());//Vector of bends
integer->setAllNodeValue(0);
integer->setAllEdgeValue(0);
sizes->setAllNodeValue(Size(0,0,0)); //width, height, depth
sizes->setAllEdgeValue(Size(0,0,0)); //start_size, end_size, arrow_size
Following is the display (in the tulip GUI) of the list of a node associated values for the properties
previously created :
Following is an example :
cout << "List of the properties present in the graph:" << endl;
Iterator<string> *it=graph->getLocalProperties();
while (it->hasNext()) {
cout << it->next() << endl;
} delete it;
22
Tulip
Library
#include <tulip/ColorProperty.h>
#include <tulip/DoubleProperty.h>
#include <tulip/GraphProperty.h>
#include <tulip/IntegerProperty.h>
#include <tulip/LayoutProperty.h>
#include <tulip/SizeProperty.h>
#include <tulip/StringProperty.h>
/**
* Tutorial 003
*
* Create a graph and a properties of each type
* And display properties present in the graph
*/
int main() {
//create an empty graph
Graph *graph=tlp::newGraph();
//build the graph
buildGraph(graph);
BooleanProperty *select=graph->getLocalProperty<BooleanProperty>("firstSelectio
LayoutProperty *layout=graph->getLocalProperty<LayoutProperty>("firstLayout");
IntegerProperty *integer=graph->getLocalProperty<IntegerProperty>("firstInteger
ColorProperty *colors=graph->getLocalProperty<ColorProperty>("firstColors");
SizeProperty *sizes=graph->getLocalProperty<SizeProperty>("firstSizes");
GraphProperty *meta=graph->getLocalProperty<GraphProperty>("firstMeta");
StringProperty *strings=graph->getLocalProperty<StringProperty>("firstString");
23
Tulip
Library
layout->setAllNodeValue(Coord(0,0,0)); //coordinates
layout->setAllEdgeValue(vector<Coord>());//Vector of bends
integer->setAllNodeValue(0);
integer->setAllEdgeValue(0);
sizes->setAllNodeValue(Size(0,0,0)); //width, height, depth
sizes->setAllEdgeValue(Size(0,0,0)); //start_size, end_size, arrow_size
Before anything consider the following function that creates 3 nodes and 3 edges (same as in tutorial
001 ):
The creation of a subgraph is quite simple. You just have to use the function Graph*
addSubGraph (BooleanProperty* selection = 0) . It will create and return a
new SubGraph of the graph. The elements of the new subgraph are those selected in the selec-
tion(selection associated value equals true); if there is no selection an empty subgraph is returned.
24
Tulip
Library
Graph *subgraph0=graph->addSubGraph();
Graph *subgraph1=graph->addSubGraph();
Graph *subgraph2=subgraph1->addSubGraph();
We can check that by iterating on our graph’s subgraphs using the function Iterator< Graph *
>* Graph::getSubGraphs() :
/**
* Tutorial 004
*
* Create a graph and three subgraphs,
* display all the structure using iterators
*/
25
Tulip
Library
int main() {
//create an empty graph
Graph *graph=tlp::newGraph();
delete graph;
return EXIT_SUCCESS;
}
3.11.1. 1. Introduction
We will first begin with the creation of the graph and its properties :
int main() {
//create an empty graph
Graph *graph=tlp::newGraph();
26
Tulip
Library
graph->getLocalProperty<ColorProperty>("firstColors");
graph->getLocalProperty<DoubleProperty>("firstMetric");
Note
The function void buildGraph(Graph *g), is the one implemented in Tutorial 004.
In the sample of code above, we create a graph with 3 properties : firstSelection (select), fisrtColors
and firstMetric. We then set all nodes and edges "firstSelection" associated value to true which means
that all nodes and edges are selected.
We, then, create two subgraphs out of our selection (the entire graph) :
And, to finish this section, we add some new properties to those two subgraphs :
subgraph1->getLocalProperty<DoubleProperty>("firstMetric");
The property "firstMetric" will be redefined but not the two other ones.
Following is a sample and its output that enables the iteration over local properties :
cout << "List of the local properties present in the subgraph1:" << endl;
Iterator<string> *it=subgraph1->getLocalProperties();
while (it->hasNext()) {
27
Tulip
Li-
brary
_________________________________________________________________________
As you can see the only local properties that has subgraph1 are "firstMetric" and "secondMetric".
Indeed, "firstMetric" has been redefined, and, "thirdMetric" has been created with subgraph2.
Following is a sample and its output that enables the iteration over inherited properties :
cout << "List of the inherited properties present in the subgraph1:" << endl;
it=subgraph1->getInheritedProperties();
while (it->hasNext()) {
cout << it->next() << endl;
} delete it;
_________________________________________________________________________
As you can see, subgraph1 just has two inherited properties since "firstMetric" has been redefined.
Following is a sample of code that lists all the properties of a graph, the inherited properties and local
properties :
_________________________________________________________________________
28
Tulip
Library
Following is a sample and its output that enables the iteration over local properties :
cout << "List of the local properties present in the subgraph2:" << endl;
it=subgraph2->getLocalProperties();
while (it->hasNext()) {
cout << it->next() << endl;
} delete it;
_________________________________________________________________________
Following is a sample and its output that enables the iteration over inherited properties :
cout << "List of the inherited properties present in the subgraph2:" << endl;
it=subgraph2->getInheritedProperties();
while (it->hasNext()) {
cout << it->next() << endl;
} delete it;
_________________________________________________________________________
As you can see, subgraph2 has a lot of inherited properties since he is the subgraph of subgraph1
which is the subgraph of the root graph.
/**
29
Tulip
Library
* Tutorial 005
*
* Create a graph hierarchy with several properties
* Display the inherited and local properties in each graph
*/
int main() {
//create an empty graph
Graph *graph=tlp::newGraph();
graph->getLocalProperty<ColorProperty>("firstColors");
graph->getLocalProperty<DoubleProperty>("firstMetric");
subgraph1->getLocalProperty<DoubleProperty>("firstMetric");
cout << "List of the local properties present in the subgraph1:" << endl;
Iterator<string> *it=subgraph1->getLocalProperties();
while (it->hasNext()) {
cout << it->next() << endl;
} delete it;
30
Tulip
Li-
brary
cout << "List of inherited properties present in the subgraph1:" << endl;
it=subgraph1->getInheritedProperties();
while (it->hasNext()) {
cout << it->next() << endl;
} delete it;
cout << "List of the local properties present in the subgraph2:" << endl;
it=subgraph2->getLocalProperties();
while (it->hasNext()) {
cout << it->next() << endl;
} delete it;
cout << "List of inherited properties present in the subgraph2:" << endl;
it=subgraph2->getInheritedProperties();
while (it->hasNext()) {
cout << it->next() << endl;
} delete it;
delete graph;
return EXIT_SUCCESS;
}
5 http://en.wikipedia.org/wiki/Acyclic_Graph#Adjacency_and_degree
31
Tulip
Library
int main() {
//create an empty graph
Graph *graph=tlp::newGraph();
As you can see, node 0 has three edges : edge 1,edge 2 and edge 3. And if we display its edges
adjacency list (see last section for function void displayAdjacency(node n, Graph
*graph) ) we obtain the following output :
1 2 3
32
Tulip
Library
//swap e1 and e3
graph->swapEdgeOrder(n0, e1, e3);
3 2 1
vector<edge> tmp(2);
tmp[0]=e1;
tmp[1]=e3;
graph->setEdgeOrder(n0,tmp);
1 2 3
/**
* Tutorial 006
*
* Create a graph
* Order the edges around the nodes
*/
33
Tulip
Li-
brary
Iterator<edge>*ite=graph->getInOutEdges(n);
while(ite->hasNext())
cout << ite->next().id << " ";
delete ite;
cout << endl;
}
int main() {
//create an empty graph
Graph *graph=tlp::newGraph();
tlp::saveGraph(graph, "adj1.tlp");
//swap e1 and e3
graph->swapEdgeOrder(n0,e1,e3);
vector<edge> tmp(2);
tmp[0]=e1;
tmp[1]=e3;
graph->setEdgeOrder(n0,tmp);
//display the new order of edge around n1
displayAdjacency(n0,graph);
delete graph;
return EXIT_SUCCESS;
}
The direct access in this container is forbidden, but it exist a getter and a setter :
34
Tulip
Li-
brary
Each class of graph has its own header file. Following is a list of those header files and an example of
their use :
• tulip/AcyclicTest.h AcyclicTest::isAcyclic(graph);
• tulip/BiconnectedTest.h BiconnectedTest::isBiconnected(graph);
• tulip/ConnectedTest.h ConnectedTest::isConnected(graph);
• tulip/OuterPlanarTest.h PlanarityTest::isOuterPlanar(graph);
• tulip/PlanarityTest.h PlanarityTest::isPlanar(graph);
• tulip/SimpleTest.h SimpleTest::isSimple(graph);
35
Tulip
Library
• tulip/TreeTest.h TreeTest::isTree(graph);
• tulip/TriconnectedTest.h TriconnectedTest::isTriconnected(graph);
First, we will create a class that inherits from ObservableGraph, and then use it and see what this new
class is able to "do".
To continue this tutorial, we need to include the following files, and namespaces.
#include <iostream>
#include <set>
//- - - - - - - - - - - - -
#include <tulip/TlpTools.h>
#include <tulip/Graph.h>
#include <tulip/ObservableGraph.h>
//- - - - - - - - - - - - -
As said before, we will create a new class that inherits from ObservableGraph. This class will have
several functions to be notified when a node or an edge is deleted or added or reversed (edge).
private:
void addEdge(Graph * g,const edge e) {
cout << "edge :" << e.id << " has been added" << endl;
}
void delEdge(Graph *,const edge e) {
cout << "edge :" << e.id << " is about to be deleted" << endl;
}
void reverseEdge(Graph *,const edge e) {
cout << "edge :" << e.id << " is about to be reversed" << endl;
}
void addNode(Graph * g,const node n) {
cout << "node :" << n.id << " has been added" << endl;
}
36
Tulip
Li-
brary
}
};
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
GraphObserverTest graphObserverTest;
graph->addObserver(&graphObserverTest);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
We add the instance of our class GraphObserverTest with the function Graph::addObserver .
node n1 = graph->addNode();
node n0 = graph->addNode();
edge e0 = graph->addEdge(n0, n1);
graph->reverse(e0);
graph->delNode(n0);
delete graph;
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
return EXIT_SUCCESS;
}
37
Chapter 4. Tulip Open GL Library
4.1. Introduction
Tulip-ogl is a library for OpenGL allowing the developper to add augmented displays on the graph
4.2.2. GlSimpleEntity
GlSimpleEntity is the mother-class of every 2D/3D shape. It provides one important virtual functions
: draw, and one important data field : boundingBox. By generalizing this class, you can have classes
making calls to OpenGL functions within the draw function. The other classes of the library are :
GlLine, GlPolygon, GlBox, GlCircle, GlGrid, GlMultiPolygon, GlQuad, GlRect, GlRectTextured,
GlSphere.
• GlLine : Describes a line according to a start position, a start color, an end position and an end
color.
• GlQuad : Describes a quad according to a position and a size, or according to four points.
• GlRect : Describes a rectangle according to a position and a size, or according to two points.
• GlGrid : Displays a 3D or a 2D projection of a grid. This augmented display is built with GlLine.
• GlComplexPolygon : Describe a convex or concav polygon with color texture and hole
38
Tulip
Open
GL
Library
4.2.4. Scene and layers
The core of a view is the scene. A scene contain all opengl information and hierarchy of GlEntity to
display graph and augmented displays
In NodeLinkDiagramComponent you have three layers : background (2D layer), Main (graph layer)
and Foreground (2D layer).
In following example you construct GlEntity and add it in the Main layer. To get this main layer you
just need to call scene->getLayer("Main")
In the given screenshots, the scene is composed of two nodes placed at positions (-1, -1, -1) and (1, 1,
1). Their sizes are (1, 1, 1)
// We create the line, the last parameter is the thickness of the line
(note : you can’t exceed 10)
1 http://tulip.labri.fr/samples/plugintemplates.tar.gz
39
Tulip
Open
GL
Li-
brary
GlLine* line = new GlLine(startPos, endPos, startCol, endCol, 1);
40
Tulip
Open
GL
Li-
brary
//We firstly add a new GlLayer (with name "2D layer") in the scene and set layer to 2
Here is the screenshot of the result (the screenshot has been shrinked so the radius is not of 256 pixels)
:
41
Tulip
Open
GL
Library
The circle will be positionned at the center of the screen. It will have a radius of 256 pixels and will
be of a medium grey (128, 128, 128, 255).
The four squares will be positionned every 90° on the circle. They will also be in medium gray, and
only wired
//We firstly add a new GlLayer (with name "2D layer") in the scene and set layer to 2
// This is the medium grey color that will be applied to every Gl shape :
42
Tulip
Open
GL
Li-
brary
for(int i=0; i < 4; i++)
{
// We calculate the position of the center of each square
center[0] = cos((double)i * 3.14/2.0) * 256;
center[1] = sin((double)i * 3.14/2.0) * 256;
center[2] = 0;
center = center + circleCenter;
// Then we find the position of the topLeft and the bottomRight corner
This is very simple but you can do more simply : a GlLayer is composed with a GlComposite, so you
can add rectangles and circle directly to the layer2D, like this :
43
Chapter 5. Tulip QT Library
5.1. Introduction
In Tulip the plugin system is extended to interactors, views and controllers
• Interactors is a mini controller system who manage attached view and model
44
Tulip
QT
Li-
brary
5.2. Interactors
An interactor is construct to interact with a view
In node link diagram view we have many interactors, for example : node builder interactor, selection
interactor ... All these interactors have icons and this icons are visible in the toolbar
In interactor Tulip system we have two main classes : InteractorComponent and Interactor itself
Extract archive, go in the directory, modify your PATH environment varialbe, run make and make
install
PATH environment variable must contain the directory where you install you tulip. Here you have an
example to modify this variable : export PATH=/home/user/install/tulip/bin:$PATH
To construct an interactor component you have to build a class that inherits InteractorComponent class
• compute : This function is call before the rendering of the scene. It can be used to add GlEntities
in the scene
1 http://tulip.labri.fr/samples/interactorpluginexample.tar.gz
45
Tulip
QT
Li-
brary
• draw : This function is call just after the graph rendering. It can be used to add some OpenGL
object directly on the OpenGL viewFor example : selection interactor use this function to draw the selection
rectangle
• clone : This function must be implemented to return a copy of the interactor component
• eventFilter : More important function ! This function is call by Qt to treat the event. You must
reimplement this function and treat the event if you can
46
Tulip
QT
Li-
brary
47
Tulip
QT
Li-
brary
You have a list of InteractorComponent. When Qt have an event, this event is passed to first element
of this list, if InteractorComponent don’t treat this event (function eventFilter return false) the event is
passed to second element of the list ...
• In you constructor :
• Call InteractorChainOfResponsibility constructor with two string. First is the path to interactor icon,
second is the interactor tooltip text.
• Call setPriority(int) function to set the priority of the interactor in the toolbar : if priority is high ( >5 for
example) interactor icon is placed at left side of the toolbar
5.3. Views
A view is used to display graph data
In Tulip base you have two different views : Node link diagram view and Spreadsheet view
48
Tulip
QT
Li-
brary
If you want, you can download an view example here2
Extract archive, go in the directory, modify your PATH environment variable, run make and make
install
PATH environment variable must contain the directory where you install you tulip. Here you have an
example to modify this variable : export PATH=/home/user/install/tulip/bin:$PATH
2 http://tulip.labri.fr/samples/viewpluginexample.tar.gz
49
Tulip
QT
Li-
brary
• Display part : void draw();
// Call when the graph is modified or by interactors
void redraw();
// Mainly call by Qt when a menu is open in front of the view
// Data is not modified so the view is unchanged
void init();
// Call when the graph is modified and when the view need to be completely←-
init and draw
// For example this function is call when a layout algorithm is running, in←-
NodeLinkDiagramComponent this function call centerView() and draw()
void createPicture(const std::string &pictureName,int width=0, int←-
height=0);
// Create a picture of this view and store it in file with pictureName
50
Tulip
QT
Li-
brary
5.3.3.1. AbstractView class
AbstractView class provide a basic implementation of iteractor system, so if you want to use it you
don’t have to implement functions : setInteractors(...), getInteractors(...), setActiveInteractor(...) and
getActiveInteractor(...)
In addition, AbstractView provide a system to create a context menu (the menu that appears when you
click right mouse button in the view)
• buildContextMenu function : here you construct your menu, to do that you add QMenu in
contextMenu parameters, for example :
contextMenu->addMenu(new QMenu("viewMenu"));
• computeContextMenu function : this function is call when the user click on a menu in context
menu. In this function you have to threat this action
• Finaly you have specificEventFilter function : this function is call before all others function if the
user move/click the mouse. You have to implement (if you want) your specific mouse mechanism on this
function
At default this OpenGl view display the Graph, but you can modify this default system. GlMainView
use GlMainWidget system to display graph (see GlMainWidget section for more informations
In addition, this class add an hide overview button in contextMenu, but you can add your own menus
in context menu (as you do with AbstractView)
51
Tulip
QT
Library
• First method is ok if you want to create a view who display the graph with node/link system, this
system use setData and getData of GlMainWidget
• If you want you own OpenGl visualisation, you must rebuild view in setData and store data in
getData
As we said above, the GlMainView use a GlMainWidget to display Graph (and other things if you
want), so in getData you have to store GlMainWidget data and, if you want, you can store your own
data
Is very simple
This function is call by the controler to load (previously stored) data on your view
//We check if glMainWidgetData exist because getData can be call with empty data s
if(data.exist("glMainWidgetData")
data.get("glMainWidgetData",glMainWidgetData);
if(data.exist("owndata")
data.get("owndata",stringData);
mainWidget->setData(graph,glMainWidgetData);
}
52
Tulip
QT
Li-
brary
So you have to manually load the data in GlMainWidget
For example if you want a view that show a simple sphere, you can create a code like this :
//Create a layer with name "Main" is very important, because GlMainWidget use it
GlSphere *sphere;
if(data.exist("spherePosition"){
Coord position=data.get("spherePosition",position);
sphere=new GlSphere(position,10.);
}else{
sphere=new GlSphere(Coord(0,0,0),10.);
}
mainLayer->addGlEntity("Sphere",sphere);
}
And if you want to store data of your view, you can do this :
In the overview, you can display only one element (but this element can be a GlComposite) and this
element must be store in entity parameter
So if you have you view which inherits of GlMainView class and you want to display the graph on
the overview (graph is display at default in GlMainView), you have to enter a line like this in your
setData(...) function
overviewWidget->setObservedView(mainWidget,mainWidget->getScene()->getGlGraphCom
5.4. Controllers
As the majority of features in eclipse, the main window’s layout is controlled by plugins. The base
layout is set-up by the MainController class which inherits from the Controller abstract object.
53
Tulip
QT
Library
Whenever a graph is loaded into Tulip, a new controller is chosen to display it (which means that there
is as many controller objects as graphs loaded into Tulip). By default, only MainController is present
and is always chosen to display new graphs. However, if several controllers are available, the user will
be able to chose between them when a new graph will be loaded.
First, we will create a very basic controller which do practically nothing. We’ll then use it as a strat to
develop a ControllerPluginExample (whose features are described below).
We are going to write a controller that does practically nothing (we’ll call it VoidController) and use
it as a base to develop our BasicExampleController.
The process is pretty similar to other plugins. First, we’ll make a class that inherits from the Controller
interface, overriding some methods, then we’ll declare our new class as a controller plugin using the
CONTROLLERPLUGIN
5.4.1.1. VoidController.h
#ifndef VOIDCONTROLLER_H_
#define VOIDCONTROLLER_H_
#include <tulip/Controller.h>
#include <tulip/DataSet.h>
private:
tlp::Graph *graph;
};
#endif /* VOIDCONTROLLER_H_ */
5.4.1.2. VoidController.cpp
#include "VoidController.h"
54
Tulip
QT
Li-
brary
VoidController::VoidController() {
}
VoidController::~VoidController() {
}
Controller::attachMainWindow(facade);
}
Graph *VoidController::getGraph() {
return this->graph;
}
5.4.1.3. Description
The code itself is pretty self-explanatory but we’ll review some of its elements.
First, we can recognize familiar methods: setData, getData and getGraph aim at the same thing as
their counterparts in other plugins. Each controller is assosiated to one graph (passed via setData) and
can store some restoration infos via getData and getGraph methods.
The attachMainWindow is used to build the controller’s GUI. A basic main window layout is given
(the facade parameter). It contains the “File”, “Windows” and “Help” menus and the “Open”, “Save”
and “Print” toolbar buttons. You can tune-up this GUI by adding whatever elements in this tulip
window.
Controllers are tabbed elements: because you have one controller per graph, if multiple controllers
are simultaneously loaded into Tulip, the user we’ll be able to choose between them to see every new
opened graph.
Extract archive, go in the directory, modify your PATH environment varialbe, run make and make
install
PATH environment variable must contain the directory where you install you tulip. Here you have an
example to modify this variable : export PATH=/home/user/install/tulip/bin:$PATH
5.4.3. ControllerPluginExample
3 http://tulip.labri.fr/samples/controllerpluginexample.tar.gz
55
Tulip
QT
Li-
brary
Now we will create a very basic controller. This controller will be create a Node Link Driagram View
in full window mode, and you will have interactors to modify the graph
5.4.3.1. ControllerPluginExample.h
#ifndef CONTROLLERPLUGINEXAMPLE_H
#define CONTROLLERPLUGINEXAMPLE_H
#include <tulip/ControllerViewsManager.h>
#include <tulip/DataSet.h>
#include <tulip/Graph.h>
#include <tulip/AbstractProperty.h>
#include <tulip/Observable.h>
// For this example we construct an simple controller who display a simple node link
public:
virtual ~ControllerPluginExample();
// This function is call when tulip want to attach data on this controller
// So this function is call when the graph is modified or when a property is modif
private:
tlp::Graph *graph;
tlp::View *nodeLinkView;
};
#endif
56
Tulip
QT
Library
5.4.3.2. ControllerPluginExample.cpp
#include "ControllerPluginExample.h"
#include <tulip/View.h>
ControllerPluginExample::~ControllerPluginExample() {
// when we delete this controller, we remove it of observer
if(graph){
Iterator<PropertyInterface*> *it = graph->getObjectProperties();
while (it->hasNext()) {
PropertyInterface* tmp = it->next();
tmp->removeObserver(this);
} delete it;
graph->removeObserver(this);
}
}
this->graph = graph;
graph->addObserver(this);
}
*graph = this->graph;
}
57
Tulip
QT
Li-
brary
Graph *ControllerPluginExample::getGraph() {
return this->graph;
}
5.4.3.3. Description
In this example, we have two important things
• First we have the ControllerViewsManager classThis class is a tools class to create and manage
views. In this example, we just use it to simplify creation of the view and activation of this view (and interactor
activation). If we had directly created the view, without ControllerViewsManager, the interactor tool bar was
empty
• The second important things is the observer systemIn Tulip graph and properties can be observed,
to do this you just have to create a class that inherits of Observer and you have to connect observables
(graph and properties) to this observer with addObserver(...) functionBut you can inherit of two others
class : GraphObserver and PropertyObserver. GraphObserver is use when you want to know when a node
is add/delete for example (see ObservableGraph class for more information). And PropertyObserver is use if
you want to know when a property is modified (see ObservableProperty class for more information)
58
Tulip
QT
Li-
brary
• installInteractors(...) to install interactors of a view in tool bar
To use it, you have to create a view that inherit of this class and call ControllerViewsMan-
ager::attachMainWindow(...) in your class attachMainWindow function
• getCurrentGraph() and getCurrentView() : to get current active view and graph associated with this view
• Tool funstions :
• installInteractors(...) : to install interactors for a view (normaly you don’t have to call manualy this
function, she is atoucall when view is activated)
59
Chapter 6. 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 Section 6.1, “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 Section 6.2,
“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 Section 6.3, “Import plug-ins”.
• Export algorithms : Plug-ins to save a graph to a specific type of file. See Section 6.4,
“Export plug-ins”.
60
Plug-
ins
de-
vel-
op-
ment
Each one of the 8 classes presented above has a public member, TypeNameProperty* type-
NameResult, 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 Section 6.1.3, “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.
61
Plug-
ins
development
• 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.
• Graph* graph :This graph is the one given in parameters, the one on which the algorithm
will be applied.
• 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
Section 6.1.4, “Example of a plugin skeleton”.
6.1.2. 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.
• inHelp : This parameter can be used to add a documentation to the parameter (See example below).
62
Plug-
ins
development
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 :
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 :" \
HTML_HELP_CLOSE(),
};
}
Then, we can add the parameters in the constructor by writing the following lines:
63
Plug-
ins
development
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)");
• bool exist (const std::string& name) const :Returns true if name exists else
false.
64
Plug-
ins
development
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);
}
• 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
65
Plug-
ins
development
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 ha
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.
#include <tulip/TulipPlugin.h>
#include <string>
66
Plug-
ins
de-
vel-
op-
ment // 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) {
// This line is very important because it’s the only way to register your algorithm
// It automatically builds the plugin object that will embed the algorithm.
// 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.
67
Plug-
ins
de-
vel-
op-
ment • 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>("Quotien
Clustering", "1.0");
• 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).
• Graph* graph :This graph is the one given in parameters, the one on which the algorithm
will be applied.
• 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.
• 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.
68
Plug-
ins
development
The methods below, will be redefined in our plugin (See section plug-in skeleton).
• Graph* graph :This graph is the one given in parameters, the one on which the algorithm
will be applied.
• 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.
// This line is very important because it’s the only way to register your import mod
69
Plug-
ins
development
// It automatically builds the plugin object that will embed the algorithm.
// 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.
• 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).
• Graph* graph :This graph is the one given in parameters, the one on which the algorithm
will be applied.
• 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.
70
Plug-
ins
de-
vel-
op-
ment
6.4.3. Skeleton of an ExportModule derived class
#include <tulip/TulipPlugin.h>
#include <string>
#include <iostream>
// This line is very important because it’s the only way to register your export mod
// It automatically builds the plugin object that will embed the algorithm.
// 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.
71
Plug-
ins
de-
vel-
op-
ment
6.5. Compilation ( Makefiles )
You can download plugins skeletons here1 .
# 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)
TARGET= libmyalgorithm-$(TULIP_VERSION).$(LIB_EXTENSION)
CXX=g++
CXXFLAGS = -O3 -Wall -DNDEBUG ‘${TULIP_CONFIG} --cxxflags --plugincxxflags‘
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)
1 http://tulip.labri.fr/samples/plugintemplates.tar.gz
72
Plug-
ins
de-
vel-
op-
ment Procedure 6.1. Compile and install your plugin
1.
[user@localhost ]$ make
2.
Type make install in a terminal. Be careful that you may need root privileges to do this.
3.
’make clean’, will remove all generated files (libraries, *.o , ...)
73
Chapter 7. Tulip graph format
7.1. Nodes
The nodes are stored with a list of indices. The indices must be non negative integers.
Syntax
Sample :
(nodes 0 1 2 3 4 5 )
7.2. Edges
An edge is defined by providing three non negative integers. The first is the id of the edge, the second
is the id of source node of the edge and the third is the id of target node of the edge.
Syntax
Sample
(edge 2 2 1)
It defines one edge with the node that has the id 2 as source and the node that has the id 1 as target.
7.3. Clusters
A cluster is defined by an integer which represent the cluster id, one string which is the name of the
cluster(Two clusters can have the same name). Then it is define with a list of nodes and a list of edges.
To define a subcluster we use the same method. One important point is that the id zero is reserved for
the root graph (thus it cannot be used).
Syntax
(cluster id name
(nodes id_node1 id_node2 ...)
(edges id_edge1 id_edge2 ...)
(cluster id name
(nodes id_node1 id_node2 ...)
(edges id_edge1 id_edge2 ...)
)
)
Sample
(cluster 3 "cluster"
(nodes 1 2 3 )
(edges 2 8 )
(cluster 4 "Sub Cluster"
(nodes 1 2 )
74
Tulip
graph
format
(edges 2 )
)
)
Syntax
Sample
• layout : This type enables to store nodes position in 3D. The position of nodes is defined by a set of
3 doubles (x_coord,y_coord,z_coord). The position of edges is a list of 3D points. These points are
the bends of edges. ((x_coord1,y_coord1,z_coord1)(x_coord2,y_coord2,z_coord2))
• size : This type enables to store the size of elements. The size is defined with a sequence of three
double. (width,heigth,depth)
• color : This type enables to store the color of elements. The color is defined with a sequence of
four integer from 0 to 255. (red,green,blue,alpha)
75
Tulip
graph
format
viewSelection
type : bool, this property is the one used for selected elements in Tulip.
viewLayout
type : layout, this property is the one used for displaying graph in Tulip.
viewColor
type : color, this property is the one used for coloring graphs in Tulip.
viewLabel
type : string, this property is the one used for labeling the graphs in Tulip(in label mode).
76
Tulip
graph
format
viewSize
type : size, this property is the one used for the size of elements displayed.
viewShape
type : int, this property is used for defining the shape of elements.
viewTexture
viewMetaGraph
viewRotation
7.6. GlScene
Scene structure are stored with a xml structure.
First, scene’s data (viewport and background color) are store in data element
Syntax
<data>
<viewport>(x,y,width,height)</viewport>
<background>(red,green,blue,alpha)</background>
</data>
<scene>
<data>
...
</data>
<children>
77
Tulip
graph
for-
mat
<LayerName1 type="GlLayer">
<data>
...
</data>
<children>
...
</children>
</LayerName>
<LayerName2 type="GlLayer">
<data>
...
</data>
<children>
<EntityName type="EntityType">
<data>
...
</data>
</EntityName3>
</children>
</LayerName2>
</children>
</scene>
78
Chapter 8. Programming Guidelines
8.1. Generalities
The presentation of a program indicates the quality of programming. This section relates to the
common recommendations for the Tulip project. Each new programmer has to follow the expressed
rules.
In the header files, the programmer should write a headline containing : his name with personal
email adress (for students), the date of the last modifications, a reminder of the licence GPL1 and
the references of the code (for example, an algorithm). Header files must include a construction that
prevents multiple inclusions. The convention is an all uppercase construction of the file name, the h
suffix and prefixed by “Tulip”, separated by an underscore.
#ifndef Tulip_MYTYPE_H
#define Tulip_MYTYPE_H
...
#endif // Tulip_MYTYPE_H
The organisation of files must be comprehensible. New module leads to a new set of files : a *.cpp
and a *.h named with the name of the type. If the structure implicates that all methods are inline,
the creation of a .cxx file is better than a .cpp file. The cxx should be included at the bottom of
the header file. None implementation is in the header file. In the Tulip hiearchy, the cxx files are in a
directory “cxx” in the header location.
The indentation is an important part for a easy reading in a file and a best understanding. Code must be
properly indented to show the syntactic structure of the program. It is useless to space out excessively
the code. A conventional indentation is just necessary. None useless TAB or spaces. The { caracter
for the opening of a method or a function must be at the end of the line, not in following line. Each
new fitted block of program implies a new shift for the indentation.
Each new module inserted in the Tulip library must be included in the namespace tlp. It is necessary
in order to prevent eventually incompatibilities.
namespace tlp{
/* code inserted */
Tulip is dependent of the STL2 . It provides a set of performing objects that you should use : vector,
map, string, ... It exists two ways to use it. In the .h or .cxx files, you should preface them with the
std namespace (e.g. std::string s;). You will refer them with the fullname : namespace and
class name. For the .cpp files, you can use the short name if you insert the line at the top of your
document using namespace std;.
79
Pro-
gram-
ming
Guide-
lines
class MyClasse{
public:
Myclasse();
~MyClasse(){}
void draw();
private:
std::string mystring;
};
MyClasse::MyClasse(){
mystring = "Hello world";
}
void MyClasse::draw(){
cout<<mystring<<endl;
}
List of Rules
• Types (struct, class, ...) : Names must be in mixed case starting with upper case. Each word
should have first letter in upper case. Don’t use underscore to separate words. (e.g. SortedVector,
OrientedList, RedBird, ...)
• Functions and Methods : Names must be in mixed case like for Types, but starting with lowercase.
After the first one, each important word has first letter in upper case. Don’t use underscore to separate words.
(e.g drawString(), computeFormulas(), ...)
• Macro and Enumeration constants : Names must be defined in upper case with an underscore
between words. (e.g. LAYOUTPLUGIN(C, N, A, D, I, V, R), ...)
80
Programming
Guidelines
The setter and getter must begin with the keyword set or get. All of the methods or functions
should begin with a verb for understanding its goal. The prefix of a boolean variables or methods
should be is, can, has, should : bool isValid(const edge e) const, function specified if
the edge is valid.
Before a declaration of a class, you should write a little description to explain it. The role, the
pre-requisites, the post-requisites, the return values and the parameters should be written before the
declaration of the function or method. It is the minimum for an easy comprehension of your work. In
the code, it is useless to comment each line because the comments are often a paraphrase of the code.
It just is essential to write a comment for strong parts that you have thought.
Autoconf is a tool of GNU producing shell scripts that automtically configure software packages to
adapt to many kinds of UNIX systems. It is not the unique tool, it runs with others to solve all problems
to making portable software. It generates configurations files : specially the configure script
from a configure.in or configure.ac file. Running this script, you produce the customized
Makefiles, and other files. It checks for the presence of each feature that the software need. Autoconf
requires GNU M4 in order to generate the scripts.
To this end, GNU has developed a set of integrated utilities to finish the job of Autoconf. Automake
is the next in run. It is a tool for generating Makefile.in from files called Makefile.am. Each
Makefile.am is basically a series of make variable definitions, with the GNU Makefile standards.
Automake requires Autoconf in order to be used properly.
The last is Libtool. It makes it possible to compile position independent code and build shared libraries
in a portable manner. It does not require either Autoconf, or Automake and can be used independently.
Automake however supports libtool and operates with it in a seamless manner.
81
Programming
Guidelines
To create a configure script with autoconf, you need so to write an autoconf input file
configure.ac (or configure.in, use in previous versions of Autoconf). In this example, it
is created a configure.ac file but Tulip contains configure.in. The both files are correct.
‘hello.c‘
#include <stdio.h>
main(){
printf("Hello world!\n");
}
‘Makefile.am‘
bin_PROGRAMS = hello ¶
hello_SOURCES = hello.c ·
‘configure.ac‘
AC_INIT(hello, 1.0) ¸
AC_CONFIG_SRCDIR(hello.c) ¹
AM_INIT_AUTOMAKE() º
AC_PROG_CC »
AC_OUTPUT(Makefile) ¼
$ aclocal
$ autoconf
The aclocal command installs a file called ‘aclocal.m4’. It contains the knowned Autoconf macros
to be in use in configure.ac, like AC_PROG_CC. If you want to include your macros, you can
create an acinclude.m4 file. An other cache directory is created to store the traces of the runs of
m4. It is called autom4te.cache.
$ automake -a
It displays :
82
Pro-
gram-
ming
Guide-
lines
Makefile.am: installing ‘./INSTALL’
Makefile.am: required file ‘./NEWS’ not found
Makefile.am: required file ‘./README’ not found
Makefile.am: required file ‘./AUTHORS’ not found
Makefile.am: required file ‘./ChangeLog’ not found
Makefile.am: installing ‘./COPYING’
Makefile.am: installing ‘./depcomp’
This creates copies of install-sh, missing, COPYING, depcomp. These files are required
to be present by the GNU coding standards. But NEWS, README, AUTHORS, ChangeLog are not
generated. You have to create them. If you have not them and you attempt to do make distcheck,
then it will deliberately fail. To create it :
Then, you have to run automake -a a second time. This one has created a Makefile.in file
from Makefile.am. In this file, we have specify what are building and the used sources. For a
library, you should define the lib_LIBRARIES variable.
Now the package is exactly in the state that the end-user will find it when person unpacks it from a
source code distribution. To test you program, you can write :
$ ./configure
$ make
$ ./hello
and ...
$ make install
$ make uninstall
$ make dist
...
So, you have to modify two files in the directory of your library to indicate the new files.
include/Makefile.am is the first. You have to complete a variable containing all .h and .cxx
files with your header files named nobase_include_HEADERS. This name is a choice for the
processing of the GNU build system. The second one is src/Makefile.am and so, you complete
the variable containing all .cpp files with your source files : libtulip_ogl_la_SOURCES,
libtulip_la_SOURCES or libtulip_qt_la_SOURCES depending of the librairie you com-
plete. You have modified the both Makefile.am but the Makefile not. To update it, you have to
recreate the configure file at the root directory and run it again. To do it, run ./gen-conf and
83
Pro-
gram-
ming
Guide-
lines
./configure. To avoid this procedure at each modification of the Makefile.am, you can specify
an option when you use configure script : --enable-maintainer-mode. See Section 2.1,
“Options”, for more details about the options. Now, the next compilation includes your work.
Makefile.am can use the same syntax as with ordinary makefiles. General variable can be defined,
available for all your building objects.
srcdir
The relative path to the directory that contains the source code for that Makefile.
abs_srcdir
Absolute path of srcdir.
top_srcdir
The relative path to the top-level of the current build tree. In the top-level directory, this is the
same as srcdir.
abs_top_srcdir
Absolute path of top_srcdir.
builddir
Rigorously equal to “./”. Added for the symmetry only.
abs_builddir
Absolute path of builddir.
top_builddir
The relative path to the top-level of the current build tree. In the top-level directory, this is the
same as builddir.
abs_top_builddir
Absolute path of top_builddir.
The following targets are used for a special directory or for special buildings:
84
Pro-
gram-
ming
Guide-
lines
bin_PROGRAMS = prog1 prog2 ...
Lists the executable files that will be compiled with make and installed with make install
under prefix/bin, where prefix is usually /usr/local but you can specify to an other
value.
In the same way, you can specify variable for a specialy library or shared library by prefixing the
variable by the name of the library.
Occasionally it is useful to know which Makefile variables that Automake uses for compilations.
For instance you might need to do your own compilation in some special cases. Some variables
are inherited from Autoconf; these are CC, CFLAGS, CPPFLAGS, DEFS, LDFLAGS, LIBS, CXX,
CXXFLAGS, ... There are some additional variables which Automake defines itself:
AM_CPPFLAGS
The contents of this variable are passed to every compilation which invokes the C preprocessor;
it is a list of arguments to the preprocessor. For instance, -I and -D options should be listed
here. Automake already provides some -I options automatically. AM_CPPFLAGS is ignored in
preference to a per-executable (or per-library) _CPPFLAGS variable if it is defined.
INCLUDES
This does the same job as AM_CPPFLAGS. It is an older name for the same functionality. This
variable is deprecated; we suggest using AM_CPPFLAGS instead.
85
Pro-
gram-
ming
Guide-
lines
AM_CFLAGS
This is the variable which the Makefile.am author can use to pass in additional C compiler flags.
It is more fully documented elsewhere. In some situations, this is not used, in preference to the
per-executable (or per-library) _CFLAGS.
COMPILE
This is the command used to actually compile a C source file. The filename is appended to form
the complete command line.
AM_LDFLAGS
This is the variable which the Makefile.am author can use to pass in additional linker flags. In
some situations, this is not used, in preference to the per-executable (or per-library) _LDFLAGS.
LINK
This is the command used to actually link a C program. It already includes -o $@ and the usual
variable references (for instance, CFLAGS); it takes as “arguments” the names of the object files
and libraries to link in.
noinst_
denotes data which do not need to be installed.
dist_ /nodist_
denotes files or data that will be included to the distribution (or not with nodist_).
8.4.5. References
Developing software with GNU : the GNU build system - http://www.amath.washington.edu/~lf/tutorials/autoconf/toolsm
86
Chapter 9. Documentation Guidelines
9.1. Definitions
1. Docbook is a collection of standards and tools for technical publishing. A Docbook file is
composed of SGML(3) tags and is also dependant of a Document Type Definition(2). Docbook has defined
standard DTD that you can find in the docbook tools.
2. DTD : Document Type Definition. The DTD defines the vocabulary of content elements that an
author can use and how they relate to each other. For example, a book element can contain a title element,
any number of para elements for paragraphs, and any number of chapter elements.
4. XSL (Extensible Stylesheet Language) is a language of description used for the transformation
of the sgml file into formatted ouput: XSL processors like xsltproc, saxon or xalan, ... do that.
5. Catalog : In XML, it provides a mapping from generic addresses to specific local directories on
a given machine. A catalog can be used to locate the DocBook DTD, system entity files, and stylesheet files
during processing.
To write a manual using Docbook and the XSL stylesheets, we need four tools :
• Docbook DTD
• XSL processor
1 http://www.sagehill.net/docbookxsl/ToolsSetup.html
87
Doc-
u-
men-
ta-
tion
Guide-
lines There are RPM (docbook-dtds, docbook-style-xsl), Debian (docbook-xml, docbook-xsl) packages for
Linux systems, Fink packages for Mac systems, and Cygwin and other packages for Windows systems.
The installation of Docbook and the XSL stylesheet create a file named /etc/xml/catalog. It
contains the informations about all others catalogs to resolve the path of the DTDs and the stylsheets
from the URI.
If you need another solution or you have problems for the compilation, you can download the source
package on oasis web site2 for Docbook and on the SourceForge page3 of XSL stylesheets. The
Docbook sources are in a zip file. Unzip your package in a directory in the place you prefer.
The Docbook XML DTD consists of a main file docbookx.dtd, several module files and a
catalog file, named catalog.xml. To update the changes of location of your DTD, edit the file
CatalogManager.properties in $TULIPDIR/docs/common/. Add the catalog file with
its asbolute path to the catalogs variable.
CatalogManager.properties :
catalogs=/etc/xml/catalog;/home/bardet/docbook-4.4/catalog.xml
relative-catalogs=false
static-catalog=yes
catalog-class-name=org.apache.xml.resolver.Resolver
verbosity=1
Concerning the XSL stylesheet package, you just have to do the same thing. You can execute the
script of intallation. You have to add the reference of the catalog too. Edit the file catalog.xml
and complete the catalogs variable with the reference of the catalog of your XSL stylesheet. This
catalog resolution make sure that the path, the differences could be find in all Operation Systems.
Saxon is a free processor written in Java, so it can be run on any operating system with a modern
Java interpreter. To install it, you have to download on sourceforge the last release 6.5.4. for debian,
it exists a deb package. This is the full version that implements the XSLT 1.0 standard. It runs on
Java system and provides opportunities for extensions. For Windows, it exists the Instant Saxon a
precompiled version that runs only on Microsoft Windows. Saxon is distributed as a zip package. You
have to unzip it into a suitable location. It gives three .jar files ; saxon.jar contains the XSLT
processor. In according to the location, you have to update your CLASSPATH. You need to include
the full path to the necessary .jar files in the CLASSPATH environment variable. To update it :
CLASSPATH=$CLASSPATH:/usr/saxon/saxon.jar:\
2 http://www.oasis-open.org/docbook/xml/
3 http://sourceforge.net/projects/docbook/
88
Doc-
u-
men-
ta-
tion
Guide-
lines /usr/docbook-xsl/extensions/saxon653.jar
export CLASSPATH
It should be erased in all catalog files which blocks the offline compilation (/etc/xml/catalog,
/usr/shar/sgml/docbook/xmlcatalog, ...).
9.2.2. Doxygen
It can already be in your distribution. For distributions like Debian or Fedora Core, you can used :
yum [install doxygen]
apt-get [install doxygen]
For another solution, you can find source files and CVS repository in the web site of Doxygen
(http://www.stack.nl/~dimitri/doxygen).
Docbook is a DTD (Document Type Definition) for XML or SGML document that define elements. It
is a kind of grammar of the source document. This is in relation with stylesheets (DSSSL [1] or XSL)
which allow you to publish on the Web ( in HTML, XHTML) on a printable documentation (PS, PDF,
RTF...) with your Docbook documents. The main advantages of the docbook format is the possibility
to seperate the contents of the forms. The tools which can transform the source documents are generic
and can pratically run on all Operation Systems. Docbook is the successor of LinuxDoc.
89
Documentation
Guidelines
For Tulip documentation, the source documents are in XML, because XML leads to take the place
of SGML to alleviate compatibility problems with browser software. It’s a new, easier version of the
standard rules that govern the markup itself. To find all of the xml elements to composed your own
document, you can see : http://www.docbook.org/tdg5/en/html/pt02.html
For each document, a set of XML files should be created. To help the editing of the handbook, it
is possible to use general editors like kate, emacs, quanta. See Docbook Editors4 . To configure
Kate, select Configure Kate -> Settings -> Configure Kate. Select the plugin item from
the application tree and check the Kate XML Completion, and the Kate XML Validation
boxes.
To compile the handbooks, you just have to type make html. If you want to test the validation of
the sources of the handbooks, type make check. The last command is make pdf, it produces the
printable output.
1. DSSSL: Document Style Semantics and Specification Language. For more informations, you
can visit the web site: http://www.jclark.com/dsssl/
<?xml version=’1.0’?> ¶
<!-- My first Docbook file --> ·
<!DOCTYPE book PUBLIC "-//OASIS//DTD Docbook XML V4.4//EN" ¸
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
The identification of the DTD is used by the document to know which root element is. The
declaration could have a different aspect if you use the system identifier : <!DOCTYPE book
SYSTEM "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
Here, “OASIS” is the owner, the declaration is “DTD Docbook XML V4.4” and the language is
English “EN”. The keyword “book” specifies that the root element is book. An example of the
structure of a Docbook file is like followed.
<author><firstname>Jean-Pierre</firstname><surname>DUPONT
</surname></author>
<copyright><year>2005</year>
<holder>Jean-Pierre DUPONT</holder>
</copyright>
</bookinfo>
<preface> ... </preface>
<chapter> ... </chapter>
<sect1> <title>..</title>
<para> ...</para>
4 http://i18n.kde.org/doc/doc-primer/docbook-editors.html
90
Documentation
Guidelines
</sect1>
<chapter> ... </chapter>
<chapter> ... </chapter>
<appendix> ... </appendix>
<appendix> ... </appendix>
<index> ... </index>
</book>
9.3.1.1. Validation
The validity of a document is very difficult to detect, so we use a program to do that. A validating
parser is a program that can read the DTD and determine whether the exact order of elements in the
document is valid according to the DTD.
To determinate if the XML code is valid, the program xmllint can be used with the option --valid. This
program is a parser dependent of the library libxml2.
xmllint [--valid --noout myfile.docbook]
When there are errors in the document, xmllint detects the number line and displays the form that it
should be.
It exists several attempts to produce an print or web publishing. Recently, the XML workgroup has
made a standard Extensible Style Language (XSL). It provides a set of stylesheet able to transform the
Docbook documents. DSSSL is an other possibility, but we use the XSL stylesheet for the Tulip
project. This stylesheet is an argument for the compilation with an XSL processor for the XSL
transformations.
91
Doc-
u-
men-
ta-
tion
Guide-
lines 9.3.2.1. how to separate the work in several files ?
The first solution to write a part of a handbook is to complete the main document. To avoid that
several persons work on the same file, it exists a solution to cut the docbook file. You can write a section or
a chapter and you just have to include your part in the main file. To create a valid file for the compiler, you
shoud modify the head of a docbook file and specify the kind of document you do. For a chapter, your file
is like followed :
The identification gives the kind of file you write. For including your work, you just have to complete the
declaration of the main file and insert a special tag located at the place that you want the inclusion. Don’t
forget to erase the declaration of your work. The file must begin with the markup “chapter”.
the element uses for the insert of a figure is “<figure>”. It enables the numerotation of the
figures. Warning, the width of the figures should not exceed a certain value to avoid that it is truncated in
the pdf transform. You can specify a title and other parameter in the limits of the DTD.
To do that, you use the set of tags programlisting, co, calloutlist, callout.
<programlisting>
class MyClasse{ <co id="myid" linkends="mylink"/>
};
</programlisting>
<calloutlist>
<callout arearefs="myid" id="mylink">
<para>... comments ...</para>
</callout>
</calloutlist>
5 http://www.sagehill.net/docbookxsl/AnnotateListing.html#Callouts
92
Documentation
Guidelines
The programlisting contains the program that you want to display. It is a verbatim mode. Warning,
special caracters could be not allow : <, for example. The code element represents the callout you want
to place. The location of the insertion is important because it is the location on display. Two attributes are
essential : id for the identification and linkends for indicate which comments is linked with the callout.
After the programlisting element, we use a calloutlist element to define a list of comments.
each comment is contained in a callout element. It has attributes whose arearefs to make a reference
to callouts and id for the identification.
It exists an other solution but it is more difficult. You have to specify coordinates of place where you want
a callout. This solution is an easy and quick way to comment your program listing.
class MyClasse{ ¶
};
To create your first Doxygen documentation, you need a config file .cfg or .doxygen. To generate it :
doxygen [-g myfile.doxygen]
The file contains the options you can choose for the documentation generation. Comments indicates
how to use this variables. The INPUT variable contains the files or directories to find the source
files. When you have set all tags with good values, you can generate the documentation. Doxygen
checks the source files to extract the informations in special comments and tags. See this page for the
informations about the variables : http://www.stack.nl/~dimitri/doxygen/config.html. To create it :
doxygen [myfile.doxygen]
By default, it creates directories : html, latex, and/or man, ...
For the Tulip project, It exists two documentations. One is destinated for the Developer team and
this other one is for the user of the librairies. The Configuration files are generated by the Makefile
processing.
So the blocks of documentation in the sources files are the C++ comment blocks. For each item of
code, there are two types of descriptions, which together form the documentation : a brief description
and detailed description. A detailed description is used to explain generously the existence of an item.
/**
* detailed description
93
Doc-
u-
men-
ta-
tion
Guide-
lines
*/
or
/*!
* detailed description
*/
or
/*!
detailed description
*/
or others ....
To make a brief description, you can use the command \brief. This command ends at the end of a
paragraph, so the detailed description follows after an empty line. An other option is to use a special
C++ style comment which does not span more than one line.
or
or
or others ....
For more details, the web site of Doxygen6 explains it. In general, the comments must be before the
declaration or definition of a type, a function or a member. If you want to putting the documention
after, you have to add a marker <. Note that you can place your comment at other places using some
tags like \class, \union, \fn, \var, ... or @class, @union, @fn, @var, ...
It exists several tags to help you for commenting and writing a description : all of it begin with a
backslash \ or an at-sign @.
6 http://www.doxygen.org/docblocks.html
94
Doc-
u-
men-
ta-
tion
Guide-
lines • @return, to indicate the exit of a function
• @remark
7 http://www.stack.nl/~dimitri/doxygen/commands.html
95
Documentation
Guidelines
//! A destructor.
~MyClass(){}
/** @var i
@brief, you can put the comments where you want
with the special tags */
};
To update the Documentation of Tulip, you just have to use the makefile and so write : make docs.
To illustrate your documentation, you can insert a block of code in a description between \code
and \endcode. This code is written in the documentation with highlighting syntax.
96
Doc-
u-
men-
ta-
tion
Guide-
lines Use the tag \n.
It exists two ways to resolve this questions. The first one is to use the tags \cond and
\endcond to skip the internal code. The second way is to use the preprocessor of Doxygen. In the
configuration file, you specify the macros and you verify if the value of PREPROCESSING is to yes. Then,
you set MACROS_NAME to PREDEFINED.
#ifndef MACROS_NAME
#endif /* MACROS_NAME */
• DOXYGEN_NOTFOR_DEVEL : use to skip the code for Developer and User documentations.
Doxygen allows you to put Latex formulas in the ouput (just for HTML and latex format). Three ways are
avaible. If you want to include formulas in-text, you have to put formulas between a pair of “\f$”
The second way is for a centered display on a seperate line. These formulas should be put between \f[ and
\f] commands.
The third way is to used formulas or other latex elements that are not in a math environment. It can
be specified using \f{environment}, where environment is the latex environment, the corresponding end
commands is \f}
9.5. References
Docbook XSL : the complete Guide http://www.sagehill.net/docbookxsl/index.html
8 http://www.stack.nl/~dimitri/doxygen/formulas.html
9 http://www.oreilly.com/catalog/docbook/chapter/book/docbook.html
10 http://www.docbook.org/tdg/en/html/part2.html
97