]> SALOME platform Git repositories - modules/yacs.git/blob - src/genericgui/SceneBlocItem.cxx
Salome HOME
mergefrom branch BR_V511_PR tag mergeto_trunk_03feb09
[modules/yacs.git] / src / genericgui / SceneBlocItem.cxx
1 //  Copyright (C) 2006-2008  CEA/DEN, EDF R&D
2 //
3 //  This library is free software; you can redistribute it and/or
4 //  modify it under the terms of the GNU Lesser General Public
5 //  License as published by the Free Software Foundation; either
6 //  version 2.1 of the License.
7 //
8 //  This library is distributed in the hope that it will be useful,
9 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
10 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 //  Lesser General Public License for more details.
12 //
13 //  You should have received a copy of the GNU Lesser General Public
14 //  License along with this library; if not, write to the Free Software
15 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 //  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19 #include "SceneBlocItem.hxx"
20 #include "Scene.hxx"
21 #include "Menus.hxx"
22 #include "QtGuiContext.hxx"
23 #include "guiObservers.hxx"
24 #include "ComposedNode.hxx"
25 #include "Proc.hxx"
26 #include "OutputPort.hxx"
27 #include "OutGate.hxx"
28 #include "InputPort.hxx"
29 #include "InGate.hxx"
30
31 #include <sstream>
32
33 // --- for graphviz 2.8
34 #undef HAVE_CONFIG_H
35
36 #ifdef HAVE_DOTNEATO_H
37   #include <dotneato.h>
38 #else
39   #include <gvc.h>
40 #endif
41
42 //#define _DEVDEBUG_
43 #include "YacsTrace.hxx"
44
45 using namespace std;
46 using namespace YACS::ENGINE;
47 using namespace YACS::HMI;
48
49 /*! Definition in dot per inch for graphviz input:
50  *  size of elementary nodes are in pixel in Qt, and given in inches to graphviz
51  */
52 #define DPI 72.
53
54 static GVC_t* aGvc = 0;
55
56
57 SceneBlocItem::SceneBlocItem(QGraphicsScene *scene, SceneItem *parent,
58                              QString label, Subject *subject)
59   : SceneComposedNodeItem(scene, parent, label, subject)
60 {
61   DEBTRACE("SceneBlocItem::SceneBlocItem " <<label.toStdString());
62   _format = "%1"; // --- format to convert a float without locale: ex. 9.81
63 }
64
65 SceneBlocItem::~SceneBlocItem()
66 {
67 }
68
69 //! Auto-arrange nodes inside a schema using Graphviz C API.
70 /*!
71  */
72
73 void SceneBlocItem::arrangeChildNodes()
74 {
75   DEBTRACE("SceneBlocItem::arrangeChildNodes");
76
77   SubjectComposedNode *scnode = dynamic_cast<SubjectComposedNode*>(getSubject());
78   assert(scnode);
79   ComposedNode *cnode = dynamic_cast<ComposedNode*>(scnode->getNode());
80   assert(cnode);
81
82   // ---- Create a graphviz context
83
84   if(!aGvc)
85     {
86       aginit();
87       aGvc = gvContext();
88     }
89
90   // ---- Create a graph
91
92   _graph = agopen((char*)( cnode->getName().c_str()), AGDIGRAPH);
93
94   // ---- Initialize and set attributes for the graph
95   
96   Agsym_t* attr;
97   if ( !(attr = agfindattr(_graph, "compound")))
98     attr = agraphattr(_graph, "compound", "false");
99   agxset(_graph, attr->index, "true");
100
101   if ( !(attr = agfindattr(_graph, "rankdir")))
102     attr = agraphattr(_graph, "rankdir", "TB");
103   agxset(_graph, attr->index, "LR");
104
105 //   if ( !(attr = agfindattr(_graph, "ordering")))
106 //     attr = agraphattr(_graph, "ordering", "" );
107 //   agxset(_graph, attr->index, "in" );
108   
109   if ( !(attr = agfindattr(_graph, "dpi")))
110     attr = agraphattr(_graph, "dpi", "72");
111   agxset(_graph, attr->index, "72"); // --- must be coherent with #define DPI
112
113   // --- label is used to reserve place for bloc banners (adjust size with font !)
114
115   if ( !(attr = agfindattr(_graph, "label")))
116     attr = agraphattr(_graph, "label", "label");
117   agxset(_graph, attr->index, "myLabel");
118
119   if ( !(attr = agfindattr(_graph, "labelloc")))
120     attr = agraphattr(_graph, "labelloc", "top");
121   agxset(_graph, attr->index, "top");
122
123   if ( !(attr = agfindattr(_graph, "fontsize")))
124     attr = agraphattr(_graph, "fontsize", "24");
125   agxset(_graph, attr->index, "24");
126
127   if ( !(attr = agfindattr(_graph, "splines")))
128     attr = agraphattr(_graph, "splines", "");
129   agxset(_graph, attr->index, "");
130
131   // --- Initialize attributes for nodes
132
133   if ( !(attr = agfindattr( _graph->proto->n, "height")))
134     attr = agnodeattr(_graph, "height", "" );
135
136   if ( !(attr = agfindattr( _graph->proto->n, "width")))
137     attr = agnodeattr(_graph, "width", "" );
138
139   if ( !(attr = agfindattr( _graph->proto->n, "shape")))
140     attr = agnodeattr(_graph, "shape", "" );
141
142   if ( !(attr = agfindattr( _graph->proto->n, "fixedsize")))
143     attr = agnodeattr(_graph, "fixedsize", "false" );
144
145   // ---- Bind graph to graphviz context - must be done before layout
146   // ---- Compute a layout
147
148   try
149     {
150       getNodesInfo(cnode);
151       //      createGraphvizNodes(cnode);
152       DEBTRACE("end of graphviz input");
153 #ifdef _DEVDEBUG_
154       agwrite(_graph, stderr);
155 #endif
156 #ifdef HAVE_DOTNEATO_H
157       gvBindContext(aGvc, _graph);
158       dot_layout(_graph);
159 #else
160       //DEBTRACE("external render for test");
161       //gvRenderFilename(aGvc, _mainGraph, "dot", "graph1.dot");
162       DEBTRACE("compute layout");
163       gvLayout(aGvc, _graph, "dot");
164       DEBTRACE("external render for test");
165 #ifdef _DEVDEBUG_
166       gvRenderFilename(aGvc, _graph, "dot", "graph2.dot");
167 #endif
168 #endif
169    }
170   catch (std::exception &e)
171     {
172       DEBTRACE("Exception Graphviz layout: " << e.what());
173       return;
174     }
175   catch (...)
176     {
177       DEBTRACE("Unknown Exception Graphviz layout ");
178       return;
179     }
180   DEBTRACE("start of display");
181   // ---- layout Canvas nodes recursively
182
183   arrangeCanvasNodes(cnode);
184
185   DEBTRACE("clean up graphviz");
186   // ---- Delete layout
187
188 #ifdef HAVE_DOTNEATO_H
189   dot_cleanup(_graph);
190 #else
191   gvFreeLayout(aGvc, _graph);
192 #endif
193
194   // ---- Free graph structures
195
196   agclose(_graph) ;
197
198   // ---- Free context and return number of errors
199
200 #ifndef HAVE_DOTNEATO_H
201   //gvFreeContext( aGvc );
202 #endif
203
204   // --- update scene
205 }
206
207 void  SceneBlocItem::getNodesInfo(YACS::ENGINE::ComposedNode *cnode)
208 {
209   Proc *proc = GuiContext::getCurrent()->getProc();
210
211   // --- Create Nodes = direct descendants in the bloc
212
213   list<Node*> children = cnode->edGetDirectDescendants();
214   for (list<Node*>::iterator it = children.begin(); it != children.end(); ++it)
215     {
216       Agnode_t* aNode = agnode(_graph, (char*)(proc->getChildName(*it).c_str()));
217       DEBTRACE("Add node in graph: " << aNode->name);
218
219       SubjectNode* snode = GuiContext::getCurrent()->_mapOfSubjectNode[(*it)];
220       SceneItem* sci = QtGuiContext::getQtCurrent()->_mapOfSceneItem[snode];
221       double nh = sci->getHeight();
222       double nw = sci->getWidth();
223       double lh = nh/DPI;
224       double lw = nw/DPI;
225
226       QString height, width;
227       height = QString(_format.c_str()).arg(lh, 0, 'g', 3);
228       width  = QString(_format.c_str()).arg(lw, 0, 'g', 3);
229
230       DEBTRACE(aNode->name << " (" << nh << "," << nw << ") = (" << height.toStdString()  << " ; " << width.toStdString() <<")");
231       agxset( aNode, agfindattr(_graph->proto->n,"height")->index, (char*)(height.toAscii().data()));
232       agxset( aNode, agfindattr(_graph->proto->n,"width")->index, (char*)(width.toAscii().data()));
233       agxset( aNode, agfindattr(_graph->proto->n,"shape")->index, "box" );
234       agxset( aNode, agfindattr(_graph->proto->n,"fixedsize")->index, "true" );
235     }
236
237   // --- Create edges (i.e. links)
238
239   Agnode_t* aNode;
240   for (aNode = agfstnode(_graph); aNode; aNode = agnxtnode(_graph, aNode))
241   {
242     string aNodeName = aNode->name;
243     DEBTRACE("--- tail node " << aNode->name);
244     Agnode_t* aTailNode = aNode;
245     Node* outNode = proc->getChildByName(string(aTailNode->name));
246     if (outNode->getFather() != cnode)
247       {
248         DEBTRACE(" =========== problem here ! =============================");
249         continue; // Create edges only with outgoing nodes directly in bloc
250       }
251
252     // --- control link from node, keep only link staying inside the bloc
253
254     {
255       OutGate *outGate = outNode->getOutGate();
256       set<InGate*> setOfInGate = outGate->edSetInGate();
257       set<InGate*>::const_iterator itin = setOfInGate.begin();
258       for (; itin != setOfInGate.end(); ++itin)
259         {
260           Node *inNode = (*itin)->getNode();
261           string inName = proc->getChildName(inNode);
262           DEBTRACE("--- control link from tail node: --- "<<inName);
263           // --- isInMyDescendance(this)   return this
264           //     isInMyDescendance(inNode) return direct child if inNode is a direct child or grandchild
265           if (Node *inDCNode = cnode->isInMyDescendance(inNode))
266             {
267               DEBTRACE("--- edge inside the bloc " << inDCNode->getName());
268               string inDCName = proc->getChildName(inDCNode);
269               Agnode_t* aHeadNode = agnode(_graph, (char*)(inDCName.c_str()));
270               Agedge_t* anEdge    = agedge(_graph, aTailNode, aHeadNode);
271               DEBTRACE("--- control link from tail node: --- " << aNode->name << " --> " << inDCName);
272             }
273         }
274     }
275
276     // --- datalink from node, keep only link staying inside the bloc
277
278     {
279       list<OutPort*> outPortList = outNode->getSetOfOutPort();
280       list<OutPort*>::const_iterator itou = outPortList.begin();
281       for (; itou != outPortList.end(); ++itou)
282         {
283           set<InPort*> inPortList = (*itou)->edSetInPort();
284           set<InPort*>::const_iterator itin = inPortList.begin();
285           for (; itin != inPortList.end(); ++itin)
286             {
287               Node *inNode = (*itin)->getNode();
288               string inName = proc->getChildName(inNode);
289               DEBTRACE("------ data link from tail node: ---- ");
290               if (Node *inDCNode = cnode->isInMyDescendance(inNode))
291                 {
292                   DEBTRACE("--- edge inside the bloc " << inDCNode->getName());
293                   string inDCName = proc->getChildName(inDCNode);
294                   Agnode_t* aHeadNode = agnode(_graph, (char*)(inDCName.c_str()));
295                   Agedge_t* anEdge    = agedge(_graph, aTailNode, aHeadNode);
296                   DEBTRACE("------ data link from tail node: ---- " << aNode->name << " --> " << inDCName);
297                 }
298             }
299         }
300     }
301   }
302 }
303
304
305 void SceneBlocItem::arrangeCanvasNodes(YACS::ENGINE::ComposedNode *cnode)
306 {
307   DEBTRACE("SceneBlocItem::arrangeCanvasNodes");
308   Proc *proc = GuiContext::getCurrent()->getProc();
309
310   SubjectNode* subCompo = GuiContext::getCurrent()->_mapOfSubjectNode[cnode];
311   SceneItem* sci = QtGuiContext::getQtCurrent()->_mapOfSceneItem[subCompo];
312   SceneComposedNodeItem *sceneCompo = dynamic_cast<SceneComposedNodeItem*>(sci);
313   assert(sceneCompo);
314   qreal yHead = sceneCompo->getHeaderBottom() + sceneCompo->getMargin() + sceneCompo->getNml();
315   qreal xOffset = sceneCompo->getMargin() + sceneCompo->getNml();
316
317   list<Node*> children = cnode->edGetDirectDescendants();
318   for (list<Node*>::iterator it = children.begin(); it != children.end(); ++it)
319     {
320       Agnode_t* aNode = agnode(_graph, (char*)(proc->getChildName(*it).c_str()));
321       DEBTRACE("Get node in graph: " << aNode->name);
322       SubjectNode* snode = GuiContext::getCurrent()->_mapOfSubjectNode[(*it)];
323       SceneItem* sci = QtGuiContext::getQtCurrent()->_mapOfSceneItem[snode];
324
325       qreal xCenter = ND_coord_i(aNode).x;
326       qreal yCenter = ND_coord_i(aNode).y;
327       qreal halfWidth = sci->boundingRect().width()/2.;
328       qreal halfHeight = sci->boundingRect().height()/2.;
329
330       sci->setPos(xOffset + xCenter -halfWidth, yHead + yCenter -halfHeight);
331     }
332   sceneCompo->checkGeometryChange();
333   if (Scene::_autoComputeLinks)
334     {
335       YACS::HMI::SubjectProc* subproc = QtGuiContext::getQtCurrent()->getSubjectProc();
336       SceneItem *item = QtGuiContext::getQtCurrent()->_mapOfSceneItem[subproc];
337       SceneComposedNodeItem *proc = dynamic_cast<SceneComposedNodeItem*>(item);
338       proc->rebuildLinks();
339     }
340
341 }