Version: 9.15.0
SceneBlocItem.cxx
Go to the documentation of this file.
1 // Copyright (C) 2006-2025 CEA, EDF
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, or (at your option) any later version.
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 
20 #include "SceneBlocItem.hxx"
21 #include "Scene.hxx"
22 #include "Menus.hxx"
23 #include "QtGuiContext.hxx"
24 #include "guiObservers.hxx"
25 #include "ComposedNode.hxx"
26 #include "Proc.hxx"
27 #include "OutputPort.hxx"
28 #include "OutGate.hxx"
29 #include "InputPort.hxx"
30 #include "InGate.hxx"
31 
32 #include <sstream>
33 
34 #include <gvc.h>
35 
36 #include <Qtx.h> // for Localizer
37 
38 #include "Resource.hxx"
39 
40 //#define _DEVDEBUG_
41 #include "YacsTrace.hxx"
42 
43 using namespace std;
44 using namespace YACS::ENGINE;
45 using namespace YACS::HMI;
46 
50 #define DPI 72.
51 
52 SceneBlocItem::SceneBlocItem(QGraphicsScene *scene, SceneItem *parent,
53  QString label, Subject *subject)
54  : SceneComposedNodeItem(scene, parent, label, subject)
55 {
56  DEBTRACE("SceneBlocItem::SceneBlocItem " <<label.toStdString());
57  _format = "%1"; // --- format to convert a float without locale: ex. 9.81
58 }
59 
61 {
62 }
63 
65 
69 {
70 #ifdef _DEVDEBUG_
71  DEBTRACE("SceneBlocItem::arrangeChildNodes");
72  clock_t start_t, end_t;
73  start_t = clock();
74 #endif //_DEVDEBUG_
75 
76 
77  SubjectComposedNode *scnode = dynamic_cast<SubjectComposedNode*>(getSubject());
78  YASSERT(scnode);
79  ComposedNode *cnode = dynamic_cast<ComposedNode*>(scnode->getNode());
80  YASSERT(cnode);
81 
82  // ---- Create a graphviz context
83 
84  // Graphviz is sensitive to locale : set the mimimal one ("C")for numeric
85  Qtx::Localizer loc;
86 
87  //aginit();
88  GVC_t* aGvc = gvContext();
89 
90  // ---- Create a graph
91 
92  _graph = agopen((char*)( cnode->getName().c_str()), Agdirected, NULL);
93 
94  // ---- Initialize and set attributes for the graph
95 
96  agattr(_graph, AGRAPH, const_cast<char*>("compound"), const_cast<char*>("true"));
97  agattr(_graph, AGRAPH, const_cast<char*>("rankdir"), const_cast<char*>("LR"));
98  agattr(_graph, AGRAPH, const_cast<char*>("dpi"), const_cast<char*>("72"));
99  agattr(_graph, AGRAPH, const_cast<char*>("label"), const_cast<char*>("myLabel"));
100  agattr(_graph, AGRAPH, const_cast<char*>("labelloc"), const_cast<char*>("top"));
101  agattr(_graph, AGRAPH, const_cast<char*>("fontsize"), const_cast<char*>("24"));
102  agattr(_graph, AGRAPH, const_cast<char*>("splines"), const_cast<char*>(""));
103 
104  // --- Initialize attributes for nodes
105 
106  agattr(_graph, AGNODE, const_cast<char*>("height"), const_cast<char*>("" ));
107  agattr(_graph, AGNODE, const_cast<char*>("width"), const_cast<char*>("" ));
108  agattr(_graph, AGNODE, const_cast<char*>("shape"), const_cast<char*>("" ));
109  agattr(_graph, AGNODE, const_cast<char*>("fixedsize"), const_cast<char*>("false" ));
110 
111  // ---- Bind graph to graphviz context - must be done before layout
112  // ---- Compute a layout
113 
114  try
115  {
116  getNodesInfo(cnode);
117  // createGraphvizNodes(cnode);
118  DEBTRACE("end of graphviz input");
119 #ifdef _DEVDEBUG_
120  agwrite(_graph, stderr);
121 #endif
122  //DEBTRACE("external render for test");
123  //gvRenderFilename(aGvc, _mainGraph, "dot", "graph1.dot");
124  DEBTRACE("compute layout");
125  gvLayout(aGvc, _graph, "dot");
126  DEBTRACE("external render for test");
127 #ifdef _DEVDEBUG_
128  gvRenderFilename(aGvc, _graph, "dot", "graph2.dot");
129 #endif
130  }
131  catch (std::exception &e)
132  {
133  DEBTRACE("Exception Graphviz layout: " << e.what());
134  return;
135  }
136  catch (...)
137  {
138  DEBTRACE("Unknown Exception Graphviz layout ");
139  return;
140  }
141 #ifdef _DEVDEBUG_
142  {
143  end_t = clock();
144  double passe = (end_t -start_t);
145  passe = passe/CLOCKS_PER_SEC;
146  DEBTRACE("graphviz : " << passe);
147  start_t = end_t;
148  }
149 #endif //_DEVDEBUG_
150  DEBTRACE("start of display");
151  // ---- layout Canvas nodes recursively
152 
153  arrangeCanvasNodes(cnode);
154 
155  DEBTRACE("clean up graphviz");
156  // ---- Delete layout
157 
158  gvFreeLayout(aGvc, _graph);
159 
160  // ---- Free graph structures
161 
162  agclose(_graph) ;
163 
164  // ---- Free context and return number of errors
165 
166  gvFreeContext( aGvc );
167 
168  // --- update scene
169 #ifdef _DEVDEBUG_
170  {
171  end_t = clock();
172  double passe = (end_t -start_t);
173  passe = passe/CLOCKS_PER_SEC;
174  DEBTRACE("display : " << passe);
175  start_t = end_t;
176  }
177 #endif //_DEVDEBUG_
178 }
179 
181 {
182  Proc *proc = GuiContext::getCurrent()->getProc();
183 
184  // --- Create Nodes = direct descendants in the bloc
185 
186  list<Node*> children = cnode->edGetDirectDescendants();
187  for (list<Node*>::iterator it = children.begin(); it != children.end(); ++it)
188  {
189  Agnode_t* aNode = agnode(_graph, (char*)(proc->getChildName(*it).c_str()), 1);
190  DEBTRACE("Add node in graph: " << agnameof(aNode));
191 
194  double nh = sci->getHeight();
195  double nw = sci->getWidth();
196  double lh = nh/DPI;
197  double lw = nw/DPI;
198 
199  QString height, width;
200  height = QString(_format.c_str()).arg(lh, 0, 'g', 3);
201  width = QString(_format.c_str()).arg(lw, 0, 'g', 3);
202 
203  DEBTRACE(agnameof(aNode) << " (" << nh << "," << nw << ") = (" << height.toStdString() << " ; " << width.toStdString() <<")");
204  agset(aNode, const_cast<char*>("height"), height.toLatin1().data());
205  agset(aNode, const_cast<char*>("width"), width.toLatin1().data());
206  agset(aNode, const_cast<char*>("shape"), const_cast<char*>("box") );
207  agset(aNode, const_cast<char*>("fixedsize"), const_cast<char*>("true") );
208  }
209 
210  // --- Create edges (i.e. links)
211 
212  Agnode_t* aNode = NULL;
213  for (aNode = agfstnode(_graph); aNode; aNode = agnxtnode(_graph, aNode))
214  {
215  string aNodeName = agnameof(aNode);
216  DEBTRACE("--- tail node " << aNodeName);
217  Agnode_t* aTailNode = aNode;
218  Node* outNode = proc->getChildByName(string(agnameof(aTailNode)));
219  if (outNode->getFather() != cnode)
220  {
221  DEBTRACE(" =========== problem here ! =============================");
222  continue; // Create edges only with outgoing nodes directly in bloc
223  }
224 
225  // --- control link from node, keep only link staying inside the bloc
226 
227  {
228  OutGate *outGate = outNode->getOutGate();
229  list<InGate*> setOfInGate = outGate->edSetInGate();
230  list<InGate*>::const_iterator itin = setOfInGate.begin();
231  for (; itin != setOfInGate.end(); ++itin)
232  {
233  Node *inNode = (*itin)->getNode();
234  string inName = proc->getChildName(inNode);
235  DEBTRACE("--- control link from tail node: --- "<<inName);
236  // --- isInMyDescendance(this) return this
237  // isInMyDescendance(inNode) return direct child if inNode is a direct child or grandchild
238  if (Node *inDCNode = cnode->isInMyDescendance(inNode))
239  {
240  DEBTRACE("--- edge inside the bloc " << inDCNode->getName());
241  string inDCName = proc->getChildName(inDCNode);
242  Agnode_t* aHeadNode = agnode(_graph, (char*)(inDCName.c_str()), 1);
243  Agedge_t* anEdge = agedge(_graph, aTailNode, aHeadNode, NULL, 1);
244  DEBTRACE("--- control link from tail node: --- " << agnameof(aNode) << " --> " << inDCName);
245  }
246  }
247  }
248 
249  // --- datalink from node, keep only link staying inside the bloc
250 
251  {
252  list<OutPort*> outPortList = outNode->getSetOfOutPort();
253  list<OutPort*>::const_iterator itou = outPortList.begin();
254  for (; itou != outPortList.end(); ++itou)
255  {
256  set<InPort*> inPortList = (*itou)->edSetInPort();
257  set<InPort*>::const_iterator itin = inPortList.begin();
258  for (; itin != inPortList.end(); ++itin)
259  {
260  Node *inNode = (*itin)->getNode();
261  string inName = proc->getChildName(inNode);
262  DEBTRACE("------ data link from tail node: ---- ");
263  if (Node *inDCNode = cnode->isInMyDescendance(inNode))
264  {
265  DEBTRACE("--- edge inside the bloc " << inDCNode->getName());
266  string inDCName = proc->getChildName(inDCNode);
267  Agnode_t* aHeadNode = agnode(_graph, (char*)(inDCName.c_str()), 1);
268  Agedge_t* anEdge = agedge(_graph, aTailNode, aHeadNode, NULL, 1);
269  DEBTRACE("------ data link from tail node: ---- " << agnameof(aNode) << " --> " << inDCName);
270  }
271  }
272  }
273  }
274  }
275 }
276 
277 
279 {
280  DEBTRACE("SceneBlocItem::arrangeCanvasNodes");
281  Proc *proc = GuiContext::getCurrent()->getProc();
282 
285  SceneComposedNodeItem *sceneCompo = dynamic_cast<SceneComposedNodeItem*>(sci);
286  YASSERT(sceneCompo);
287  qreal yHead = sceneCompo->getHeaderBottom() + Resource::Space_Margin;
288  qreal xOffset = Resource::Space_Margin;
289 
290  list<Node*> children = cnode->edGetDirectDescendants();
291  for (list<Node*>::iterator it = children.begin(); it != children.end(); ++it)
292  {
293  Agnode_t* aNode = agnode(_graph, (char*)(proc->getChildName(*it).c_str()), 1);
294  DEBTRACE("Get node in graph: " << agnameof(aNode));
297 
298  qreal xCenter = ND_coord(aNode).x;
299  qreal yCenter = ND_coord(aNode).y;
300  qreal halfWidth = sci->boundingRect().width()/2.;
301  qreal halfHeight = sci->boundingRect().height()/2.;
302 
303  sci->setPos(xOffset + xCenter -halfWidth, yHead + yCenter -halfHeight);
304  SceneNodeItem *scni = dynamic_cast<SceneNodeItem*>(sci);
305  if (scni) scni->setExpandedPos(QPointF(xOffset + xCenter -halfWidth, yHead + yCenter -halfHeight));
306  }
307  sceneCompo->checkGeometryChange();
309  {
312  SceneComposedNodeItem *proc = dynamic_cast<SceneComposedNodeItem*>(item);
313  proc->rebuildLinks();
314  }
315 
316 }
#define DPI
#define YASSERT(val)
YASSERT macro is always defined, used like assert, but throw a YACS::Exception instead of abort.
Definition: YacsTrace.hxx:59
#define DEBTRACE(msg)
Definition: YacsTrace.hxx:31
Base class for all composed nodes.
std::string getChildName(const Node *node) const
Node * getChildByName(const std::string &name) const
virtual std::list< Node * > edGetDirectDescendants() const =0
std::string getName() const
Node * isInMyDescendance(Node *nodeToTest) const
Returns the parent of a node that is the direct child of this node.
Base class for all nodes.
Definition: Node.hxx:70
OutGate * getOutGate()
Definition: Node.hxx:124
ComposedNode * getFather() const
Definition: Node.hxx:127
std::list< OutPort * > getSetOfOutPort() const
Definition: Node.cxx:299
std::list< InGate * > edSetInGate() const
Definition: OutGate.cxx:112
Base class for all schema objects.
Definition: Proc.hxx:44
YACS::HMI::SubjectProc * getSubjectProc()
Definition: guiContext.hxx:52
YACS::ENGINE::Proc * getProc()
Definition: guiContext.hxx:50
std::map< YACS::ENGINE::Node *, YACS::HMI::SubjectNode * > _mapOfSubjectNode
Definition: guiContext.hxx:68
static GuiContext * getCurrent()
Definition: guiContext.hxx:67
static QtGuiContext * getQtCurrent()
std::map< YACS::HMI::Subject *, YACS::HMI::SceneItem * > _mapOfSceneItem
static int Space_Margin
Definition: Resource.hxx:311
virtual void arrangeCanvasNodes(YACS::ENGINE::ComposedNode *cnode)
virtual void arrangeChildNodes()
Auto-arrange nodes inside a schema using Graphviz C API.
virtual void getNodesInfo(YACS::ENGINE::ComposedNode *cnode)
virtual QRectF boundingRect() const
Definition: SceneItem.cxx:215
virtual void checkGeometryChange()
Definition: SceneItem.cxx:248
virtual qreal getHeaderBottom()
void setExpandedPos(QPointF epos)
static bool _autoComputeLinks
Definition: Scene.hxx:37
virtual YACS::ENGINE::Node * getNode()