1 // Copyright (C) 2006-2008 CEA/DEN, EDF R&D
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.
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.
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
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 #include "SceneBlocItem.hxx"
22 #include "QtGuiContext.hxx"
23 #include "guiObservers.hxx"
24 #include "ComposedNode.hxx"
26 #include "OutputPort.hxx"
27 #include "OutGate.hxx"
28 #include "InputPort.hxx"
33 // --- for graphviz 2.8
36 #ifdef HAVE_DOTNEATO_H
43 #include "YacsTrace.hxx"
46 using namespace YACS::ENGINE;
47 using namespace YACS::HMI;
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
54 static GVC_t* aGvc = 0;
57 SceneBlocItem::SceneBlocItem(QGraphicsScene *scene, SceneItem *parent,
58 QString label, Subject *subject)
59 : SceneComposedNodeItem(scene, parent, label, subject)
61 DEBTRACE("SceneBlocItem::SceneBlocItem " <<label.toStdString());
62 _format = "%1"; // --- format to convert a float without locale: ex. 9.81
65 SceneBlocItem::~SceneBlocItem()
69 //! Auto-arrange nodes inside a schema using Graphviz C API.
73 void SceneBlocItem::arrangeChildNodes()
75 DEBTRACE("SceneBlocItem::arrangeChildNodes");
77 SubjectComposedNode *scnode = dynamic_cast<SubjectComposedNode*>(getSubject());
79 ComposedNode *cnode = dynamic_cast<ComposedNode*>(scnode->getNode());
82 // ---- Create a graphviz context
90 // ---- Create a graph
92 _graph = agopen((char*)( cnode->getName().c_str()), AGDIGRAPH);
94 // ---- Initialize and set attributes for the graph
97 if ( !(attr = agfindattr(_graph, "compound")))
98 attr = agraphattr(_graph, "compound", "false");
99 agxset(_graph, attr->index, "true");
101 if ( !(attr = agfindattr(_graph, "rankdir")))
102 attr = agraphattr(_graph, "rankdir", "TB");
103 agxset(_graph, attr->index, "LR");
105 // if ( !(attr = agfindattr(_graph, "ordering")))
106 // attr = agraphattr(_graph, "ordering", "" );
107 // agxset(_graph, attr->index, "in" );
109 if ( !(attr = agfindattr(_graph, "dpi")))
110 attr = agraphattr(_graph, "dpi", "72");
111 agxset(_graph, attr->index, "72"); // --- must be coherent with #define DPI
113 // --- label is used to reserve place for bloc banners (adjust size with font !)
115 if ( !(attr = agfindattr(_graph, "label")))
116 attr = agraphattr(_graph, "label", "label");
117 agxset(_graph, attr->index, "myLabel");
119 if ( !(attr = agfindattr(_graph, "labelloc")))
120 attr = agraphattr(_graph, "labelloc", "top");
121 agxset(_graph, attr->index, "top");
123 if ( !(attr = agfindattr(_graph, "fontsize")))
124 attr = agraphattr(_graph, "fontsize", "24");
125 agxset(_graph, attr->index, "24");
127 if ( !(attr = agfindattr(_graph, "splines")))
128 attr = agraphattr(_graph, "splines", "");
129 agxset(_graph, attr->index, "");
131 // --- Initialize attributes for nodes
133 if ( !(attr = agfindattr( _graph->proto->n, "height")))
134 attr = agnodeattr(_graph, "height", "" );
136 if ( !(attr = agfindattr( _graph->proto->n, "width")))
137 attr = agnodeattr(_graph, "width", "" );
139 if ( !(attr = agfindattr( _graph->proto->n, "shape")))
140 attr = agnodeattr(_graph, "shape", "" );
142 if ( !(attr = agfindattr( _graph->proto->n, "fixedsize")))
143 attr = agnodeattr(_graph, "fixedsize", "false" );
145 // ---- Bind graph to graphviz context - must be done before layout
146 // ---- Compute a layout
151 // createGraphvizNodes(cnode);
152 DEBTRACE("end of graphviz input");
154 agwrite(_graph, stderr);
156 #ifdef HAVE_DOTNEATO_H
157 gvBindContext(aGvc, _graph);
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");
166 gvRenderFilename(aGvc, _graph, "dot", "graph2.dot");
170 catch (std::exception &e)
172 DEBTRACE("Exception Graphviz layout: " << e.what());
177 DEBTRACE("Unknown Exception Graphviz layout ");
180 DEBTRACE("start of display");
181 // ---- layout Canvas nodes recursively
183 arrangeCanvasNodes(cnode);
185 DEBTRACE("clean up graphviz");
186 // ---- Delete layout
188 #ifdef HAVE_DOTNEATO_H
191 gvFreeLayout(aGvc, _graph);
194 // ---- Free graph structures
198 // ---- Free context and return number of errors
200 #ifndef HAVE_DOTNEATO_H
201 //gvFreeContext( aGvc );
207 void SceneBlocItem::getNodesInfo(YACS::ENGINE::ComposedNode *cnode)
209 Proc *proc = GuiContext::getCurrent()->getProc();
211 // --- Create Nodes = direct descendants in the bloc
213 list<Node*> children = cnode->edGetDirectDescendants();
214 for (list<Node*>::iterator it = children.begin(); it != children.end(); ++it)
216 Agnode_t* aNode = agnode(_graph, (char*)(proc->getChildName(*it).c_str()));
217 DEBTRACE("Add node in graph: " << aNode->name);
219 SubjectNode* snode = GuiContext::getCurrent()->_mapOfSubjectNode[(*it)];
220 SceneItem* sci = QtGuiContext::getQtCurrent()->_mapOfSceneItem[snode];
221 double nh = sci->getHeight();
222 double nw = sci->getWidth();
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);
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" );
237 // --- Create edges (i.e. links)
240 for (aNode = agfstnode(_graph); aNode; aNode = agnxtnode(_graph, aNode))
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)
248 DEBTRACE(" =========== problem here ! =============================");
249 continue; // Create edges only with outgoing nodes directly in bloc
252 // --- control link from node, keep only link staying inside the bloc
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)
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))
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);
276 // --- datalink from node, keep only link staying inside the bloc
279 list<OutPort*> outPortList = outNode->getSetOfOutPort();
280 list<OutPort*>::const_iterator itou = outPortList.begin();
281 for (; itou != outPortList.end(); ++itou)
283 set<InPort*> inPortList = (*itou)->edSetInPort();
284 set<InPort*>::const_iterator itin = inPortList.begin();
285 for (; itin != inPortList.end(); ++itin)
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))
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);
305 void SceneBlocItem::arrangeCanvasNodes(YACS::ENGINE::ComposedNode *cnode)
307 DEBTRACE("SceneBlocItem::arrangeCanvasNodes");
308 Proc *proc = GuiContext::getCurrent()->getProc();
310 SubjectNode* subCompo = GuiContext::getCurrent()->_mapOfSubjectNode[cnode];
311 SceneItem* sci = QtGuiContext::getQtCurrent()->_mapOfSceneItem[subCompo];
312 SceneComposedNodeItem *sceneCompo = dynamic_cast<SceneComposedNodeItem*>(sci);
314 qreal yHead = sceneCompo->getHeaderBottom() + sceneCompo->getMargin() + sceneCompo->getNml();
315 qreal xOffset = sceneCompo->getMargin() + sceneCompo->getNml();
317 list<Node*> children = cnode->edGetDirectDescendants();
318 for (list<Node*>::iterator it = children.begin(); it != children.end(); ++it)
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];
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.;
330 sci->setPos(xOffset + xCenter -halfWidth, yHead + yCenter -halfHeight);
332 sceneCompo->checkGeometryChange();
333 if (Scene::_autoComputeLinks)
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();