Salome HOME
Copyright update: 2016
[modules/yacs.git] / src / genericgui / SceneComposedNodeItem.cxx
1 // Copyright (C) 2006-2016  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, 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 #define CHRONODEF
21 #include "chrono.hxx"
22
23 #include "SceneBlocItem.hxx"
24 #include "SceneComposedNodeItem.hxx"
25 #include "SceneElementaryNodeItem.hxx"
26 #include "SceneHeaderItem.hxx"
27 #include "SceneHeaderNodeItem.hxx"
28 #include "SceneInPortItem.hxx"
29 #include "SceneOutPortItem.hxx"
30 #include "SceneLinkItem.hxx"
31 #include "SceneDSLinkItem.hxx"
32 #include "SceneCtrlLinkItem.hxx"
33 #include "SceneProgressItem.hxx"
34 #include "LinkMatrix.hxx"
35 #include "LinkAStar.hxx"
36 #include "ItemMimeData.hxx"
37 #include "QtGuiContext.hxx"
38 #include "Menus.hxx"
39 #include "Message.hxx"
40 #include "guiObservers.hxx"
41 #include "GuiEditor.hxx"
42 #include "Scene.hxx"
43 #include "Switch.hxx"
44
45 #include <QPointF>
46 #include <QGraphicsSceneDragDropEvent>
47
48 #include <cassert>
49
50 #include "Resource.hxx"
51
52 //#define _DEVDEBUG_
53 #include "YacsTrace.hxx"
54
55 using namespace std;
56 using namespace YACS::ENGINE;
57 using namespace YACS::HMI;
58
59 SceneComposedNodeItem::SceneComposedNodeItem(QGraphicsScene *scene, SceneItem *parent,
60                                              QString label, Subject *subject)
61   : SceneNodeItem(scene, parent, label, subject)
62 {
63   DEBTRACE("SceneComposedNodeItem::SceneComposedNodeItem " <<label.toStdString());
64
65   _width  = 2*Resource::Corner_Margin + 2*Resource::DataPort_Width + Resource::Space_Margin;
66   _height = Resource::Header_Height + Resource::DataPort_Height + Resource::Corner_Margin;
67
68   _hiBrushColor = Resource::ComposedNode_hiBrush;
69   _penColor     = Resource::ComposedNode_pen;
70   _hiPenColor   = Resource::ComposedNode_hiPen;
71   adjustColors();
72   _dragOver = false;
73   setAcceptDrops(true);
74 }
75
76 SceneComposedNodeItem::~SceneComposedNodeItem()
77 {
78 }
79
80 void SceneComposedNodeItem::adjustColors()
81 {
82   _brushColor = Resource::ComposedNode_brush.darker(100 +5*_level);
83   for (list<AbstractSceneItem*>::const_iterator it=_children.begin(); it!=_children.end(); ++it)
84     {
85       if (SceneComposedNodeItem *scnode = dynamic_cast<SceneComposedNodeItem*>(*it))
86         scnode->adjustColors();
87     }
88  }
89
90 QRectF SceneComposedNodeItem::childrenBoundingRect() const
91 {
92   QRectF ChildrenBRect =QRectF(x(), y(), 5, 5);
93   if (_header) ChildrenBRect = _header->getMinimalBoundingRect();
94   for (list<AbstractSceneItem*>::const_iterator it=_children.begin(); it!=_children.end(); ++it)
95     ChildrenBRect = ChildrenBRect.united(childBoundingRect(*it));
96   ChildrenBRect.setWidth (ChildrenBRect.width()  + Resource::Border_Margin);
97   ChildrenBRect.setHeight(ChildrenBRect.height() + Resource::Border_Margin);
98   return ChildrenBRect;
99 }
100
101 void SceneComposedNodeItem::paint(QPainter *painter,
102                           const QStyleOptionGraphicsItem *option,
103                           QWidget *widget)
104 {
105   //DEBTRACE("SceneComposedNodeItem::paint " << _label.toStdString());
106   // IMN (14/11/2013) below block commented
107   // prevent bad resizing of scene in shrink mode
108   /*  if (!isExpanded()) {
109     _width  = 2*Resource::Corner_Margin + 2*Resource::DataPort_Width + Resource::Space_Margin;
110     _height = getHeaderBottom() + Resource::Corner_Margin;
111   };*/
112
113   painter->save();
114   painter->setPen(getPenColor());
115   painter->setBrush(getBrushColor());
116   painter->drawRect(QRectF(Resource::Border_Margin, Resource::Border_Margin, _width - 2*Resource::Border_Margin, _height - 2*Resource::Border_Margin));
117   painter->restore();
118 }
119
120 void SceneComposedNodeItem::update(GuiEvent event, int type, Subject* son)
121 {
122   DEBTRACE("SceneComposedNodeItem::update "<< eventName(event)<<" "<<type<<" "<<son);
123   SceneNodeItem::update(event, type, son);
124   AbstractSceneItem *item;
125   switch (event)
126     {
127     case YACS::HMI::ADD:
128       switch (type)
129         {
130         case YACS::HMI::BLOC:
131           item =  new SceneBlocItem(_scene,
132                                     this,
133                                     son->getName().c_str(),
134                                     son);
135           item->addHeader();
136           autoPosNewChild(item, _children, true);
137           break;
138         case YACS::HMI::FORLOOP:
139         case YACS::HMI::WHILELOOP:
140         case YACS::HMI::SWITCH:
141         case YACS::HMI::FOREACHLOOP:
142         case YACS::HMI::OPTIMIZERLOOP:
143           item =  new SceneComposedNodeItem(_scene,
144                                             this,
145                                             son->getName().c_str(),
146                                             son);
147           item->addHeader();
148           if ( !QtGuiContext::getQtCurrent()->isEdition()
149             && (type == YACS::HMI::FORLOOP || type == YACS::HMI::FOREACHLOOP) )
150             {
151               item->addProgressItem();
152             }
153           autoPosNewChild(item, _children, true);
154           break;
155         case YACS::HMI::PYTHONNODE:
156         case YACS::HMI::PYFUNCNODE:
157         case YACS::HMI::CORBANODE:
158         case YACS::HMI::CPPNODE:
159         case YACS::HMI::SALOMENODE:
160         case YACS::HMI::SALOMEPYTHONNODE:
161         case YACS::HMI::XMLNODE:
162         case YACS::HMI::PRESETNODE:
163         case YACS::HMI::OUTNODE:
164         case YACS::HMI::STUDYINNODE:
165         case YACS::HMI::STUDYOUTNODE:
166           item =  new SceneElementaryNodeItem(_scene,
167                                               this,
168                                               son->getName().c_str(),
169                                               son);
170           item->addHeader();
171           autoPosNewChild(item, _children, true);
172           break;
173         case YACS::HMI::INPUTPORT:
174         case YACS::HMI::INPUTDATASTREAMPORT:
175           item =  new SceneInPortItem(_scene,
176                                       _header,
177                                       son->getName().c_str(),
178                                       son);
179           _header->autoPosNewPort(item);
180           _inPorts.push_back(item);
181           if (Scene::_autoComputeLinks && !QtGuiContext::getQtCurrent()->isLoading())
182             {
183               YACS::HMI::SubjectProc* subproc = QtGuiContext::getQtCurrent()->getSubjectProc();
184               SceneItem *item = QtGuiContext::getQtCurrent()->_mapOfSceneItem[subproc];
185               SceneComposedNodeItem *proc = dynamic_cast<SceneComposedNodeItem*>(item);
186               proc->rebuildLinks();
187             }
188           break;
189         case YACS::HMI::OUTPUTPORT:
190         case YACS::HMI::OUTPUTDATASTREAMPORT:
191           item =  new SceneOutPortItem(_scene,
192                                        _header,
193                                        son->getName().c_str(),
194                                        son);
195           _header->autoPosNewPort(item);
196           _outPorts.push_back(item);
197           if (Scene::_autoComputeLinks && !QtGuiContext::getQtCurrent()->isLoading())
198             {
199               YACS::HMI::SubjectProc* subproc = QtGuiContext::getQtCurrent()->getSubjectProc();
200               SceneItem *item = QtGuiContext::getQtCurrent()->_mapOfSceneItem[subproc];
201               SceneComposedNodeItem *proc = dynamic_cast<SceneComposedNodeItem*>(item);
202               proc->rebuildLinks();
203             }
204           break;
205         default:
206           DEBTRACE("SceneComposedNodeItem::update() ADD, type not handled:" << type);
207         }
208       break;
209     case YACS::HMI::ADDLINK:
210       switch (type)
211         {
212         case YACS::HMI::DATALINK:
213           if (SubjectLink* slink = dynamic_cast<SubjectLink*>(son))
214             {
215               SubjectDataPort* soutp = slink->getSubjectOutPort();
216               SubjectDataPort* sinp  = slink->getSubjectInPort();
217               SceneItem * scout = QtGuiContext::getQtCurrent()->_mapOfSceneItem[soutp];
218               SceneItem * scin  = QtGuiContext::getQtCurrent()->_mapOfSceneItem[sinp];
219               ScenePortItem* from = dynamic_cast<ScenePortItem*>(scout);
220               ScenePortItem* to  = dynamic_cast<ScenePortItem*>(scin);
221               if (dynamic_cast<SubjectInputDataStreamPort*>(sinp))
222                 {
223                   SceneDSLinkItem* item = new SceneDSLinkItem(_scene,
224                                              this,
225                                              from, to,
226                                              son->getName().c_str(),
227                                              son);
228                   item->updateShape();
229                 }
230               else
231                 {
232                   SceneLinkItem* item = new SceneLinkItem(_scene,
233                                            this,
234                                            from, to,
235                                            son->getName().c_str(),
236                                            son);
237                   item->updateShape();
238                 }
239               if (Scene::_autoComputeLinks && !QtGuiContext::getQtCurrent()->isLoading())
240                 {
241                   YACS::HMI::SubjectProc* subproc = QtGuiContext::getQtCurrent()->getSubjectProc();
242                   SceneItem *item = QtGuiContext::getQtCurrent()->_mapOfSceneItem[subproc];
243                   SceneComposedNodeItem *proc = dynamic_cast<SceneComposedNodeItem*>(item);
244                   proc->rebuildLinks();
245                 }
246             }
247           break;
248         }
249       break;
250     case YACS::HMI::ADDCONTROLLINK:
251       switch (type)
252         {
253         case YACS::HMI::CONTROLLINK:
254           if (SubjectControlLink* slink = dynamic_cast<SubjectControlLink*>(son))
255             {
256               SubjectNode* soutn = slink->getSubjectOutNode();
257               SubjectNode* sinn  = slink->getSubjectInNode();
258               SceneItem * scout = QtGuiContext::getQtCurrent()->_mapOfSceneItem[soutn];
259               SceneItem * scin  = QtGuiContext::getQtCurrent()->_mapOfSceneItem[sinn];
260               SceneNodeItem* nodefrom = dynamic_cast<SceneNodeItem*>(scout);
261               SceneNodeItem* nodeto  = dynamic_cast<SceneNodeItem*>(scin);
262               if (!nodeto || !nodefrom) DEBTRACE("CONTROLLINK problem -----------------");
263               ScenePortItem* from = nodefrom->getCtrlOutPortItem();
264               ScenePortItem* to = nodeto->getCtrlInPortItem();
265               if (!to || !from) DEBTRACE("CONTROLLINK problem -----------------");
266               SceneCtrlLinkItem* item = new SceneCtrlLinkItem(_scene,
267                                            this,
268                                            from, to,
269                                            son->getName().c_str(),
270                                            son);
271               item->updateShape();
272               if (Scene::_autoComputeLinks && !QtGuiContext::getQtCurrent()->isLoading())
273                 {
274                   YACS::HMI::SubjectProc* subproc = QtGuiContext::getQtCurrent()->getSubjectProc();
275                   SceneItem *item = QtGuiContext::getQtCurrent()->_mapOfSceneItem[subproc];
276                   SceneComposedNodeItem *proc = dynamic_cast<SceneComposedNodeItem*>(item);
277                   proc->rebuildLinks();
278                 }
279             }
280           break;
281         }
282       break;
283     case YACS::HMI::REMOVE:
284       //SceneObserverItem::update(event, type, son);
285       break;
286     case YACS::HMI::SETCASE:
287       {
288         SubjectSwitch *sSwitch = dynamic_cast<SubjectSwitch*>(_subject);
289         if (sSwitch)
290           {
291             Switch *aSwitch = dynamic_cast<Switch*>(sSwitch->getNode());
292             Node *node = aSwitch->edGetNode(type);
293             if (node)
294               {
295                 if (GuiContext::getCurrent()->_mapOfSubjectNode.count(node))
296                   {
297                     Subject* sub = GuiContext::getCurrent()->_mapOfSubjectNode[node];
298                     if (QtGuiContext::getQtCurrent()->_mapOfSceneItem.count(sub))
299                       {
300                         SceneItem* item = QtGuiContext::getQtCurrent()->_mapOfSceneItem[sub];
301                         SceneNodeItem *scnode = dynamic_cast<SceneNodeItem*>(item);
302                         if (scnode) scnode->updateName();
303                       }
304                   }
305               }
306           }
307       }
308       break;
309     case YACS::HMI::CUT:
310       {
311         SceneItem * sinode  = QtGuiContext::getQtCurrent()->_mapOfSceneItem[son];
312         removeChildFromList(sinode);
313       }
314       break;
315     case YACS::HMI::PASTE:
316       {
317         SceneItem * sinode  = QtGuiContext::getQtCurrent()->_mapOfSceneItem[son];
318         sinode->setParent(this);
319         sinode->setLevel();
320         if (SceneComposedNodeItem *scnode = dynamic_cast<SceneComposedNodeItem*>(sinode))
321           scnode->adjustColors();
322         autoPosNewChild(sinode, _children, true);
323       }
324       break;
325     case PROGRESS:
326       {
327         if (dynamic_cast<SubjectForLoop*>(son) || dynamic_cast<SubjectForEachLoop*>(son))
328         {
329           if (SceneProgressItem* spitem = getProgressItem())
330             spitem->setProgress(son->getProgress().c_str());
331         }
332       }
333       break;
334     default:
335        ;
336 //       DEBTRACE("SceneComposedNodeItem::update(), event not handled: "<< eventName(event));
337     }
338 }
339
340 void SceneComposedNodeItem::autoPosNewChild(AbstractSceneItem *item,
341                                             const std::list<AbstractSceneItem*> alreadySet,
342                                             bool isNew)
343 {
344   SceneItem *it = dynamic_cast<SceneItem*>(item);
345   YASSERT(it);
346
347   QRectF childrenBox;
348   qreal xLeft = Resource::Corner_Margin;
349   qreal yTop  = getHeaderBottom() + Resource::Space_Margin;
350   for (list<AbstractSceneItem*>::const_iterator it=alreadySet.begin(); it!=alreadySet.end(); ++it)
351     {
352       childrenBox = childrenBox.united(childBoundingRect(*it));
353       DEBTRACE((*it)->getLabel().toStdString());
354       DEBTRACE("childrenBox valid " << childrenBox.right() << " " << childrenBox.bottom());
355     }
356   if (childrenBox.isValid())
357     yTop = childrenBox.bottom() + 1.; // +1. to avoid collision with bottom (penwidth)
358   //xLeft += childrenBox.right();
359   DEBTRACE("left, top " << xLeft  << " " << yTop);
360   QPointF topLeft(xLeft, yTop);
361   if (isNew) _children.push_back(item);
362   if (_eventPos.isNull())
363     {
364       //DEBTRACE("_eventPos.isNull");
365       item->setTopLeft(topLeft);
366     }
367   else
368     {
369       //DEBTRACE("_eventPos " << _eventPos.x() << " " << _eventPos.y());
370       item->setTopLeft(_eventPos);
371     }
372   collisionResolv(it, -it->boundingRect().bottomRight()); // as if the new item was coming from top left (previous position outside)
373   if (Scene::_autoComputeLinks && !QtGuiContext::getQtCurrent()->isLoading()) rebuildLinks();
374   _eventPos.setX(0);
375   _eventPos.setY(0);
376 }
377
378 void SceneComposedNodeItem::popupMenu(QWidget *caller, const QPoint &globalPos)
379 {
380   ComposedNodeMenu m;
381   m.popupMenu(caller, globalPos);
382 }
383
384 std::list<AbstractSceneItem*> SceneComposedNodeItem::getChildren()
385 {
386   return _children;
387 }
388
389 void SceneComposedNodeItem::removeChildFromList(AbstractSceneItem* child)
390 {
391   _children.remove(child);
392 }
393
394 void SceneComposedNodeItem::updateControlLinks(bool toExpand)
395 {
396   //update control links
397   std::list<SubjectControlLink*> lscl=dynamic_cast<SubjectNode*>(getSubject())->getSubjectControlLinks();
398   for (std::list<SubjectControlLink*>::const_iterator it = lscl.begin(); it != lscl.end(); ++it) {
399     SceneLinkItem* lk = dynamic_cast<SceneLinkItem*>(QtGuiContext::getQtCurrent()->_mapOfSceneItem[*it]);
400
401     bool b1 = true, b2 = true;
402
403     SceneNodeItem* no = lk->getFromNode();
404     if (no) {
405       SceneComposedNodeItem* scni = dynamic_cast<SceneComposedNodeItem*>(no);
406       if (scni) {
407         b1 = scni!=this;
408       };
409     };
410
411     no = lk->getToNode();
412     if (no) {
413       SceneComposedNodeItem* scni = dynamic_cast<SceneComposedNodeItem*>(no);
414       if (scni) {
415         b2 = scni!=this;
416       };
417     };
418
419     if (b1 && b2) {
420       if (toExpand) {
421         lk->show();
422       } else {
423         lk->hide();
424       };
425     };
426   };
427 }
428
429 void SceneComposedNodeItem::reorganizeShrinkExpand(ShrinkMode theShrinkMode) {
430   DEBTRACE("SceneComposedNodeItem::reorganizeShrinkExpand " << _expanded << " " << _label.toStdString());
431
432   bool toExpand = true;
433   if (theShrinkMode == CurrentNode) {
434     // shrink/expand current node only
435     toExpand = !isExpanded();
436
437     updateControlLinks(toExpand);
438     shrinkExpandRecursive(toExpand, true, theShrinkMode);
439
440   } else {
441     if (!isExpanded())
442       return;
443     // shrink/expand child nodes
444     toExpand = !hasExpandedChildren(theShrinkMode == ElementaryNodes);
445     for (list<AbstractSceneItem*>::const_iterator it=_children.begin(); it!=_children.end(); ++it) {
446       SceneItem* item = dynamic_cast<SceneItem*>(*it);
447       SceneNodeItem *sni = dynamic_cast<SceneNodeItem*>(item);
448       item->shrinkExpandRecursive(toExpand, true, theShrinkMode);
449     }
450     _ancestorShrinked = !toExpand;
451     _width = _expandedWidth;
452     _height = _expandedHeight;
453     _shownState = expandShown;
454     adjustHeader();
455     rebuildLinks();
456   }
457
458   if (Scene::_autoComputeLinks)
459     {
460       SubjectProc* subproc = QtGuiContext::getQtCurrent()->getSubjectProc();
461       SceneItem *item = QtGuiContext::getQtCurrent()->_mapOfSceneItem[subproc];
462       SceneComposedNodeItem *proc = dynamic_cast<SceneComposedNodeItem*>(item);
463       proc->rebuildLinks();
464     }
465 }
466
467 bool SceneComposedNodeItem::hasExpandedChildren(bool recursively)
468 {
469   bool res = false;
470   for (list<AbstractSceneItem*>::const_iterator it=_children.begin(); it!=_children.end() && !res; ++it) {
471     SceneItem* item = dynamic_cast<SceneItem*>(*it);
472     SceneNodeItem *sni = dynamic_cast<SceneNodeItem*>(item);
473     if (sni->isExpanded()) {
474       res = true;
475       if (recursively)
476         if (SceneComposedNodeItem *scni = dynamic_cast<SceneComposedNodeItem*>(sni))
477           res = scni->hasExpandedChildren(recursively);
478     }
479   }
480   return res;
481 }
482
483 void SceneComposedNodeItem::shrinkExpandRecursive(bool toExpand, bool fromHere, ShrinkMode theShrinkMode)
484 {
485   DEBTRACE("SceneComposedNodeItem::shrinkExpandRecursive " << isExpanding << " " << fromHere << " " << isExpanded() << " " << _label.toStdString());
486   
487   bool toChangeShrinkState = false;
488   switch (theShrinkMode) {
489   case CurrentNode:
490     if (fromHere)
491       toChangeShrinkState = true;
492     break;
493   case ChildrenNodes:
494     if (fromHere)
495       toChangeShrinkState = true;
496     break;
497   case ElementaryNodes:
498     toChangeShrinkState = false;
499     break;
500   }
501   if (toChangeShrinkState) {
502     if (toExpand != isExpanded())
503       setExpanded(toExpand);
504   } else if (!isExpanded() && theShrinkMode == ElementaryNodes) {
505     return;
506   }
507
508   updateControlLinks(toExpand);
509
510   if (!toExpand)
511     { // ---collapsing: hide first children , then resize
512       for (list<AbstractSceneItem*>::const_iterator it=_children.begin(); it!=_children.end(); ++it)
513         {
514           SceneItem* item = dynamic_cast<SceneItem*>(*it);
515           item->shrinkExpandRecursive(toExpand, false, theShrinkMode);
516           if (theShrinkMode != ElementaryNodes) {
517             item->hide();  
518             DEBTRACE("------------------------------- Hide " << item->getLabel().toStdString());
519             item->shrinkExpandLink(false);  
520           }
521         }
522
523       if (toChangeShrinkState || theShrinkMode != ElementaryNodes) {
524         if (_shownState == expandShown)
525           {
526              _expandedWidth = _width;
527              _expandedHeight = _height;
528           }
529
530         if (fromHere)
531           {
532             _shownState = shrinkShown;
533           }
534         else
535           {
536             _ancestorShrinked = true;
537             _shownState = shrinkHidden;
538           }
539
540         _width  = 2*Resource::Corner_Margin + 2*Resource::DataPort_Width + Resource::Space_Margin;
541         if (_shownState == shrinkShown)
542           _height = getHeaderBottom() + Resource::Corner_Margin;
543         else
544           _height = Resource::Header_Height + Resource::Corner_Margin;
545       
546         if (_shownState == shrinkHidden) // shrink of ancestor
547           setPos(0 ,0);
548         else
549           setPos(_expandedPos);
550         adjustHeader();
551         if (_progressItem)
552           _progressItem->adjustGeometry();
553       }
554     }
555   else
556     { // --- expanding: resize, then show children
557       if (toChangeShrinkState)
558         _ancestorShrinked = false;
559
560       for (list<AbstractSceneItem*>::const_iterator it=_children.begin(); it!=_children.end(); ++it)
561         {
562           SceneItem* item = dynamic_cast<SceneItem*>(*it);
563           item->shrinkExpandRecursive(isExpanded(), false, theShrinkMode); 
564           if (theShrinkMode != ElementaryNodes) {
565             if (isExpanded())
566               {
567                 item->show();  
568                 DEBTRACE("------------------------------- Show " << item->getLabel().toStdString());
569               }
570             else
571               {
572                 item->hide();  
573                 DEBTRACE("------------------------------- Hide " << item->getLabel().toStdString());
574               }
575             item->shrinkExpandLink(fromHere);  
576           }
577         }
578
579       if (isExpanded())
580         {
581           _width = _expandedWidth;
582           _height = _expandedHeight;
583           _shownState = expandShown;
584         }
585       else
586         {
587           _shownState = shrinkShown;
588           _width  = 2*Resource::Corner_Margin + 2*Resource::DataPort_Width + Resource::Space_Margin;
589           _height = getHeaderBottom() + Resource::Corner_Margin;
590         }
591       setPos(_expandedPos);
592       adjustHeader();
593       if (_progressItem)
594         _progressItem->adjustGeometry();
595     }
596 }
597
598 void SceneComposedNodeItem::shrinkExpandLink(bool se) {
599   DEBTRACE("SceneComposedNodeItem::shrinkExpandLink " << se << " "  << _label.toStdString());
600   se = se && isExpanded();
601   foreach (QGraphicsItem *child, childItems()) {
602     if (SceneItem *sci = dynamic_cast<SceneItem*>(child)) {
603       sci->shrinkExpandLink(se);
604     };
605   };
606 }
607
608 void SceneComposedNodeItem::reorganize()
609 {
610   DEBTRACE("SceneComposedNodeItem::reorganize() " << _label.toStdString());
611   list<AbstractSceneItem*> alreadySet;
612   for (list<AbstractSceneItem*>::const_iterator it=_children.begin(); it!=_children.end(); ++it)
613     {
614       autoPosNewChild(*it, alreadySet);
615       alreadySet.push_back(*it);
616     }
617 }
618
619 void SceneComposedNodeItem::setShownState(shownState ss)
620 {
621   _shownState = ss;
622   if (_shownState == shrinkHidden)
623     {
624       _ancestorShrinked = true;
625       hide();
626     }
627   else
628     {
629       _ancestorShrinked = false;
630       show();
631     }
632   adjustHeader();
633   if (_progressItem)
634     _progressItem->adjustGeometry();
635 }
636
637 void SceneComposedNodeItem::collisionResolv(SceneItem* child, QPointF oldPos)
638 {
639   //DEBTRACE("SceneComposedNodeItem::collisionResolv " << _label.toStdString());
640   for (list<AbstractSceneItem*>::const_iterator it=_children.begin(); it!=_children.end(); ++it)
641     {
642       SceneNodeItem *other = dynamic_cast<SceneNodeItem*>(*it);
643       if (other && (other != child))
644         {
645           if (child->collidesWithItem(other))
646             {
647               //DEBTRACE("collision detected with " << other->getLabel().toStdString());
648               QRectF otherBR = (other->mapToParent(other->boundingRect())).boundingRect();
649               qreal oldX = oldPos.x();
650               qreal oldY = oldPos.y();
651               qreal newX = child->pos().x();
652               qreal newY = child->pos().y();
653               qreal othX = otherBR.left()+0.5;
654               qreal othY = otherBR.top()+0.5;
655               //DEBTRACE("oldX=" << oldX << " oldY=" << oldY << " newX=" << newX << " newY=" << newY);
656               //DEBTRACE("otherLeft=" << otherBR.left() << " otherRight=" << otherBR.right() <<
657               //         " otherTop=" << otherBR.top() << " otherBottom=" << otherBR.bottom());
658               //DEBTRACE("width=" << child->boundingRect().width() <<
659               //         " height=" << child->boundingRect().height());
660               bool fromTop    = (((oldY + child->boundingRect().height()) <= otherBR.top()+1) &&
661                                  ((newY + child->boundingRect().height()) >= otherBR.top()));
662               bool fromBottom = (( oldY >= otherBR.bottom()) &&
663                                  ( newY <= otherBR.bottom()));
664               bool fromRight  = (( oldX >= otherBR.right()) &&
665                                  ( newX <= otherBR.right()));
666               bool fromLeft   = (((oldX+ child->boundingRect().width()) <= otherBR.left()+1) &&
667                                  ((newX+ child->boundingRect().width()) >= otherBR.left()));
668               //DEBTRACE("fromTop=" << fromTop << " fromBottom=" << fromBottom 
669               //         << " fromRight=" << fromRight << " fromLeft=" << fromLeft);
670               bool pushOther =false;
671               bool blocThis = false;
672               if (fromTop)
673                 {
674                   othY = newY + child->boundingRect().height();
675                   pushOther = true;
676                   other->_blocY = false;
677                 }
678               if (fromLeft)
679                 {
680                   othX = newX+ child->boundingRect().width();
681                   pushOther = true;
682                   other->_blocX = false;
683                 }
684               if (fromBottom)
685                 {
686                   if (other->_blocY)
687                     {
688                       newY = otherBR.bottom() + 1;
689                       blocThis = true;
690                       _blocY = true;
691                     }
692                   else
693                     {
694                       othY = newY - otherBR.height();
695                       if ( othY < Resource::Space_Margin + getHeaderBottom() )
696                         {
697                           othY = Resource::Space_Margin + getHeaderBottom();
698                           other->_blocY = true;
699                           newY = otherBR.bottom() + 1;
700                           _blocY = true;
701                           blocThis = true;
702                         }
703                       else
704                         pushOther = true;
705                     }
706                 }
707               if (fromRight)
708                 {
709                   if (other->_blocX)
710                     {
711                       newX = otherBR.right()+ 1;
712                       blocThis = true;
713                       _blocX = true;
714                     }
715                   else
716                     {
717                       othX = newX - otherBR.width();
718                       if (othX < Resource::Space_Margin)
719                         {
720                           othX = Resource::Space_Margin;
721                           other->_blocX = true;
722                           newX = otherBR.right()+ 1;
723                           _blocX = true;
724                           blocThis = true;
725                         }
726                       else
727                         pushOther = true;
728                     }
729                 }
730               //DEBTRACE("newX=" << newX << " newY=" << newY);
731               if (blocThis) child->setTopLeft(QPointF(newX, newY));
732               if (pushOther)
733                 {
734                   other->setTopLeft(QPointF(othX, othY));
735                 }
736             }
737         }
738     } 
739 }
740
741 void SceneComposedNodeItem::rebuildLinks()
742 {
743   DEBTRACE("SceneComposedNodeItem::rebuildLinks " << QtGuiContext::_delayCalc);
744   if (QtGuiContext::_delayCalc)
745     return;
746   CHRONO(1);
747   CHRONO(2);
748   LinkMatrix matrix(this);
749   matrix.compute();
750   CHRONOSTOP(2);
751   CHRONO(3);
752   list<linkdef> alist = matrix.getListOfDataLinkDef();
753   list<linkdef> blist = matrix.getListOfCtrlLinkDef(); // add list operator ?
754   for (list<linkdef>::const_iterator ii = blist.begin(); ii != blist.end(); ++ii)
755     alist.push_back(*ii);
756
757   CHRONOSTOP(3);
758   CHRONO(4);
759   LinkAStar astar(matrix);
760   for (list<linkdef>::const_iterator it = alist.begin(); it != alist.end(); ++it)
761     {
762       linkdef ali = *it;
763       DEBTRACE("from("<<ali.from.first<<","<<ali.from.second
764                <<") to ("<<ali.to.first<<","<<ali.to.second
765                <<") " << ali.item->getLabel().toStdString());
766       if(ali.from.first<0||ali.from.second<0||ali.to.first<0||ali.to.second<0) continue;
767       CHRONO(5);
768       bool isPath = astar.computePath(LNode(ali.from), LNode(ali.to));
769       CHRONOSTOP(5);
770       CHRONO(6);
771       if (! isPath) DEBTRACE("Link Path not found !");
772       if (! isPath) continue;
773       LNodePath ijPath = astar.givePath();
774       if(Scene::_addRowCols)
775         matrix.incrementCost(ijPath);
776       LinkPath apath = matrix.getPath(ijPath);
777 //       DEBTRACE(apath.size());
778       CHRONOSTOP(6);
779       CHRONO(7);
780       ali.item->setPath(apath);
781     }
782 }
783
784 void SceneComposedNodeItem::arrangeNodes(bool isRecursive)
785 {
786   DEBTRACE("SceneComposedItem::arrangeNodes " << isRecursive);
787
788   bool isExtern = !QtGuiContext::_delayCalc;
789   QtGuiContext::_delayCalc = true; // avoid rebuildLinks
790
791   SubjectComposedNode *scnode = dynamic_cast<SubjectComposedNode*>(getSubject());
792   YASSERT(scnode);
793   ComposedNode *cnode = dynamic_cast<ComposedNode*>(scnode->getNode());
794   YASSERT(cnode);
795
796   if (isRecursive)
797     {
798       list<Node*> children = cnode->edGetDirectDescendants();
799       for (list<Node*>::iterator it = children.begin(); it != children.end(); ++it)
800         {
801           DEBTRACE("child " << (*it)->getName());
802           SceneComposedNodeItem *scni = 0;
803           ComposedNode *cchild = dynamic_cast<ComposedNode*>(*it);
804           if (cchild)
805             {
806               SubjectNode* sn = GuiContext::getCurrent()->_mapOfSubjectNode[cchild];
807               SceneItem* sci = QtGuiContext::getQtCurrent()->_mapOfSceneItem[sn];
808               if (sci) scni = dynamic_cast<SceneComposedNodeItem*>(sci);
809             }
810           if (scni && (scni->getShownState() == expandShown))
811             {
812               DEBTRACE("call arrangeNode on child " << (*it)->getName());
813               scni->arrangeNodes(isRecursive);
814             }
815         }
816       arrangeChildNodes();
817     }
818   else
819     arrangeChildNodes();
820
821   if (isExtern)
822     {
823       QtGuiContext::_delayCalc = false; // allow rebuildLinks
824       if (Scene::_autoComputeLinks)
825         rebuildLinks();
826     }
827 }
828
829 void SceneComposedNodeItem::arrangeChildNodes()
830 {
831   reorganize();
832 }
833
834 void SceneComposedNodeItem::dragEnterEvent(QGraphicsSceneDragDropEvent *event)
835 {
836   bool accepted = false;
837   const ItemMimeData *myData = dynamic_cast<const ItemMimeData*>(event->mimeData());
838   if (myData)
839     {
840       if (myData->hasFormat("yacs/cataService") ||
841           myData->hasFormat("yacs/cataNode")    ||
842           myData->hasFormat("yacs/subjectNode"))
843         {
844           event->setAccepted(true);
845           _dragOver = true;
846           QGraphicsItem::update();
847           return;
848         }
849     }
850   event->setAccepted(accepted);
851 }
852
853 void SceneComposedNodeItem::dragLeaveEvent(QGraphicsSceneDragDropEvent *event)
854 {
855     Q_UNUSED(event);
856     _dragOver = false;
857     QGraphicsItem::update();
858 }
859
860 void SceneComposedNodeItem::dropEvent(QGraphicsSceneDragDropEvent *event)
861 {
862   Q_UNUSED(event);
863   _dragOver = false;
864   QGraphicsItem::update();
865
866   const ItemMimeData *myData = dynamic_cast<const ItemMimeData*>(event->mimeData());
867   if (!myData) return;
868   setEventPos(event->scenePos());
869   if (myData->hasFormat("yacs/cataService") || myData->hasFormat("yacs/cataNode"))
870     {
871       SubjectComposedNode *cnode = dynamic_cast<SubjectComposedNode*>(getSubject());
872       bool createNewComponentInstance=Resource::COMPONENT_INSTANCE_NEW;
873       // by default getControl gives false. In this case we use the user preference COMPONENT_INSTANCE_NEW
874       // to create the node. If getControl gives true we invert the user preference
875       if(myData->getControl())
876         createNewComponentInstance=!Resource::COMPONENT_INSTANCE_NEW;
877       QtGuiContext::getQtCurrent()->getGMain()->_guiEditor->CreateNodeFromCatalog(myData, cnode,createNewComponentInstance);
878     }
879   else if(myData->hasFormat("yacs/subjectNode"))
880     {
881       Subject *sub = myData->getSubject();
882       if (!sub) return;
883       SubjectNode *node = dynamic_cast<SubjectNode*>(sub);
884       if (!node) return;
885       if (dynamic_cast<SubjectProc*>(node)) return; // --- do not reparent proc !
886       SubjectComposedNode *cnode = dynamic_cast<SubjectComposedNode*>(getSubject());
887       if (cnode)
888         if (!node->reparent(cnode))
889           Message mess;
890     }
891 }
892
893 QColor SceneComposedNodeItem::getPenColor()
894 {
895   if (_dragOver)
896     return Resource::dragOver;
897   if (isSelected())
898     return _hiPenColor;
899   else 
900     return _penColor;
901 }
902
903 QColor SceneComposedNodeItem::getBrushColor()
904 {
905   if (_dragOver)
906     return _hiBrushColor;
907
908   QColor color;
909   if (isSelected())
910     color = _hiBrushColor;
911   else if (_emphasized)
912     color = Resource::emphasizeBrushColor;
913   else 
914     color = _brushColor;
915
916   if (_hover)
917     color = hoverColor(color);
918   return color;
919 }
920
921 void SceneComposedNodeItem::updateChildItems()
922 {
923   SceneNodeItem::updateChildItems();
924   if(!_header)
925     return;
926   foreach (QGraphicsItem *child, _header->childItems())
927     {
928       if (SceneItem *sci = dynamic_cast<SceneItem*>(child))
929         {
930            sci->updateLinks();
931         }
932     }
933 }
934