A view is used to display graph data
In Tulip base you have two different views : Node link diagram view and Spreadsheet view
If you want, you can download an view example here
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
All the code of this view is commented inside
If you want to create a new view, you have two things to do :
First you have to implement View interface
This interface can be separated into three parts :
Data part :
QWidget *construct(QWidget *parent); // This function is call by the controller when it want to load this view // This function must return a QWidget where we have the view void setData(Graph *,DataSet); // This function is called when we load a new graph or when we create a new one // In the DataSet you can have nothing when you create a new graph or you can have old data when you load a tlp file void getData(Graph **, DataSet *); // This function is called when you save your graph // You must store the graph and the view data voif setGraph(graph *); // This function is called when you change the visualized graph in hierarchical view (for example) Graph *getGraph();
Interactors part :
void setInteractors(const std::list<Interactor *> &interactors); // This function is call by the controller to give interactors to view std::list<Interactor *> getInteractors(); // This function must return interactors of this view (previously given interactors) void setActiveInteractor(Interactor *interactor); // This function is call by the controller when an interactor is activate on this view
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
If you doesn't want to implement all View function, you can implement a class who inherits of AbstractView class or GlMainView class
View : is the main interface without implementation
AbstractView : provide a basic implementation of interactor system
GlMainView : provide a OpenGl view with overview
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(...)
But in your construct(..) function implementation, you have to call AbstractView::construct(...). In addition, AbstractView::contruct(...) function create a QWidget for the view, so you just have to write a code like this :
QWidget *YouViewClass::construct(QWidget *parent) { QWidget *widget=GlMainView::construct(parent); Qwidget *yourWidget=new QWidget; ... setCentralWidget(yourWidget); return widget; }
In addition, AbstractView provide a system to create a context menu (the menu that appears when you click right mouse button in the view)
In this part you have 3 different functions :
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
GlMainView class provide a OpenGl view with an overview
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 your view contruct(...) function you have to call GlMainView::construct(..)
This class implement init(...), draw(...), refresh(...) and createPicture(...) functions
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)
To implement your own methodes, you have two solution :
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
For more simple explanation, we focus initially to getData(...) function
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
To do this you must have a code like this
void YourView::getData(Graph **graph,DataSet *dataSet) { dataSet->set<DataSet>("glMainWidgetData",mainWidget->getData()); dataSet->set<string>("owndata","an example of own data"); *graph=mainWidget->getGraph(); }
Is very simple
Now we focus on setData(...) function
This function is call by the controler to load (previously stored) data on your view
Like getData function, you have to load data in GlMainWidget class
You must have a code like this
void YourView::setData(Graph *graph, DataSet data){ DataSet glMainWidgetData; string stringData; //We check if glMainWidgetData exist because getData can be call with empty data set (for example : if you create this view with new graph) if(data.exist("glMainWidgetData") data.get("glMainWidgetData",glMainWidgetData); if(data.exist("owndata") data.get("owndata",stringData); mainWidget->setData(graph,glMainWidgetData); }
At this point you can't use getData and setData os glMainWidget
You have to completely reload you view in setData function
Why ? This is simple, setData of GlMainWidget is made to automaticaly create a node/link visualisation
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 :
void YourView::setData(Graph *graph, DataSet data){ this->graph=graph; //Create a layer with name "Main" is very important, because GlMainWidget use it GlLayer *mainLayer=new GlLayer("Main"); glMainWidget->getScene()->addLayer(mainLayer); 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 :
void YourView::getData(Graph **graph,DataSet *data){ *graph=this->graph; data->set<Coord>("spherePosition",spherePosition); }
At default, if you create your view, the overview will display anything because you have to give some informations to overview
You just have to call setObservedView(GlMainWidget *widget,GlSimpleEntity *entity) function
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()->getGlGraphComposite());