Salome HOME
Revert "Synchronize adm files"
[modules/yacs.git] / src / genericgui / SceneComposedNodeItem.cxx
1 // Copyright (C) 2006-2014  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::reorganizeShrinkExpand() {
395   DEBTRACE("SceneComposedNodeItem::reorganizeShrinkExpand " << _expanded << " " << _label.toStdString());
396   bool isExpanding = isExpanded();
397
398   //update control links
399   std::list<SubjectControlLink*> lscl=dynamic_cast<SubjectNode*>(_subject)->getSubjectControlLinks();
400   for (std::list<SubjectControlLink*>::const_iterator it = lscl.begin(); it != lscl.end(); ++it) {
401     SceneLinkItem* lk = dynamic_cast<SceneLinkItem*>(QtGuiContext::getQtCurrent()->_mapOfSceneItem[*it]);
402
403     bool b1 = true, b2 = true;
404
405     SceneNodeItem* no = lk->getFromNode();
406     if (no) {
407       SceneComposedNodeItem* scni = dynamic_cast<SceneComposedNodeItem*>(no);
408       if (scni) {
409         b1 = scni!=this;
410       };
411     };
412
413     no = lk->getToNode();
414     if (no) {
415       SceneComposedNodeItem* scni = dynamic_cast<SceneComposedNodeItem*>(no);
416       if (scni) {
417         b2 = scni!=this;
418       };
419     };
420
421     if (b1 && b2) {
422       if (isExpanding) {
423         lk->show();
424       } else {
425         lk->hide();
426       };
427     };
428   };
429
430   shrinkExpandRecursive(isExpanding, true);
431   if (Scene::_autoComputeLinks)
432     {
433       SubjectProc* subproc = QtGuiContext::getQtCurrent()->getSubjectProc();
434       SceneItem *item = QtGuiContext::getQtCurrent()->_mapOfSceneItem[subproc];
435       SceneComposedNodeItem *proc = dynamic_cast<SceneComposedNodeItem*>(item);
436       proc->rebuildLinks();
437     }
438 }
439
440 void SceneComposedNodeItem::shrinkExpandRecursive(bool isExpanding, bool fromHere)
441 {
442   DEBTRACE("SceneComposedNodeItem::shrinkExpandRecursive " << isExpanding << " " << fromHere << " " << isExpanded() << " " << _label.toStdString());
443   
444   if (!isExpanding)
445     { // ---collapsing: hide first children , then resize
446       for (list<AbstractSceneItem*>::const_iterator it=_children.begin(); it!=_children.end(); ++it)
447         {
448           SceneItem* item = dynamic_cast<SceneItem*>(*it);
449           item->shrinkExpandRecursive(false, false);
450           item->hide();  
451           DEBTRACE("------------------------------- Hide " << item->getLabel().toStdString());
452           item->shrinkExpandLink(false);  
453         }
454
455       if (_shownState == expandShown)
456         {
457            _expandedWidth = _width;
458            _expandedHeight = _height;
459         }
460
461       if (fromHere)
462         {
463           _shownState = shrinkShown;
464         }
465       else
466         {
467           _ancestorShrinked = true;
468           _shownState = shrinkHidden;
469         }
470
471       _width  = 2*Resource::Corner_Margin + 2*Resource::DataPort_Width + Resource::Space_Margin;
472       if (_shownState == shrinkShown)
473         _height = getHeaderBottom() + Resource::Corner_Margin;
474       else
475         _height = Resource::Header_Height + Resource::Corner_Margin;
476       
477       if (_shownState == shrinkHidden) // shrink of ancestor
478         setPos(0 ,0);
479       else
480         setPos(_expandedPos);
481       adjustHeader();
482       if (_progressItem)
483         _progressItem->adjustGeometry();
484     }
485   else
486     { // --- expanding: resize, then show children
487       _ancestorShrinked = false;
488
489       for (list<AbstractSceneItem*>::const_iterator it=_children.begin(); it!=_children.end(); ++it)
490         {
491           SceneItem* item = dynamic_cast<SceneItem*>(*it);
492           item->shrinkExpandRecursive(isExpanded(), false); 
493           if (isExpanded())
494             {
495               item->show();  
496               DEBTRACE("------------------------------- Show " << item->getLabel().toStdString());
497             }
498           else
499             {
500               item->hide();  
501               DEBTRACE("------------------------------- Hide " << item->getLabel().toStdString());
502             }
503           item->shrinkExpandLink(fromHere);  
504         }
505
506       if (isExpanded())
507         {
508           _width = _expandedWidth;
509           _height = _expandedHeight;
510           _shownState = expandShown;
511         }
512       else
513         {
514           _shownState = shrinkShown;
515           _width  = 2*Resource::Corner_Margin + 2*Resource::DataPort_Width + Resource::Space_Margin;
516           _height = getHeaderBottom() + Resource::Corner_Margin;
517         }
518       setPos(_expandedPos);
519       adjustHeader();
520       if (_progressItem)
521         _progressItem->adjustGeometry();
522     }
523 }
524
525 void SceneComposedNodeItem::shrinkExpandLink(bool se) {
526   DEBTRACE("SceneComposedNodeItem::shrinkExpandLink " << se << " "  << _label.toStdString());
527   se = se && isExpanded();
528   foreach (QGraphicsItem *child, childItems()) {
529     if (SceneItem *sci = dynamic_cast<SceneItem*>(child)) {
530       sci->shrinkExpandLink(se);
531     };
532   };
533 }
534
535 void SceneComposedNodeItem::reorganize()
536 {
537   DEBTRACE("SceneComposedNodeItem::reorganize() " << _label.toStdString());
538   list<AbstractSceneItem*> alreadySet;
539   for (list<AbstractSceneItem*>::const_iterator it=_children.begin(); it!=_children.end(); ++it)
540     {
541       autoPosNewChild(*it, alreadySet);
542       alreadySet.push_back(*it);
543     }
544 }
545
546 void SceneComposedNodeItem::setShownState(shownState ss)
547 {
548   _shownState = ss;
549   if (_shownState == shrinkHidden)
550     {
551       _ancestorShrinked = true;
552       hide();
553     }
554   else
555     {
556       _ancestorShrinked = false;
557       show();
558     }
559   adjustHeader();
560   if (_progressItem)
561     _progressItem->adjustGeometry();
562 }
563
564 void SceneComposedNodeItem::collisionResolv(SceneItem* child, QPointF oldPos)
565 {
566   //DEBTRACE("SceneComposedNodeItem::collisionResolv " << _label.toStdString());
567   for (list<AbstractSceneItem*>::const_iterator it=_children.begin(); it!=_children.end(); ++it)
568     {
569       SceneNodeItem *other = dynamic_cast<SceneNodeItem*>(*it);
570       if (other && (other != child))
571         {
572           if (child->collidesWithItem(other))
573             {
574               //DEBTRACE("collision detected with " << other->getLabel().toStdString());
575               QRectF otherBR = (other->mapToParent(other->boundingRect())).boundingRect();
576               qreal oldX = oldPos.x();
577               qreal oldY = oldPos.y();
578               qreal newX = child->pos().x();
579               qreal newY = child->pos().y();
580               qreal othX = otherBR.left()+0.5;
581               qreal othY = otherBR.top()+0.5;
582               //DEBTRACE("oldX=" << oldX << " oldY=" << oldY << " newX=" << newX << " newY=" << newY);
583               //DEBTRACE("otherLeft=" << otherBR.left() << " otherRight=" << otherBR.right() <<
584               //         " otherTop=" << otherBR.top() << " otherBottom=" << otherBR.bottom());
585               //DEBTRACE("width=" << child->boundingRect().width() <<
586               //         " height=" << child->boundingRect().height());
587               bool fromTop    = (((oldY + child->boundingRect().height()) <= otherBR.top()+1) &&
588                                  ((newY + child->boundingRect().height()) >= otherBR.top()));
589               bool fromBottom = (( oldY >= otherBR.bottom()) &&
590                                  ( newY <= otherBR.bottom()));
591               bool fromRight  = (( oldX >= otherBR.right()) &&
592                                  ( newX <= otherBR.right()));
593               bool fromLeft   = (((oldX+ child->boundingRect().width()) <= otherBR.left()+1) &&
594                                  ((newX+ child->boundingRect().width()) >= otherBR.left()));
595               //DEBTRACE("fromTop=" << fromTop << " fromBottom=" << fromBottom 
596               //         << " fromRight=" << fromRight << " fromLeft=" << fromLeft);
597               bool pushOther =false;
598               bool blocThis = false;
599               if (fromTop)
600                 {
601                   othY = newY + child->boundingRect().height();
602                   pushOther = true;
603                   other->_blocY = false;
604                 }
605               if (fromLeft)
606                 {
607                   othX = newX+ child->boundingRect().width();
608                   pushOther = true;
609                   other->_blocX = false;
610                 }
611               if (fromBottom)
612                 {
613                   if (other->_blocY)
614                     {
615                       newY = otherBR.bottom() + 1;
616                       blocThis = true;
617                       _blocY = true;
618                     }
619                   else
620                     {
621                       othY = newY - otherBR.height();
622                       if ( othY < Resource::Space_Margin + getHeaderBottom() )
623                         {
624                           othY = Resource::Space_Margin + getHeaderBottom();
625                           other->_blocY = true;
626                           newY = otherBR.bottom() + 1;
627                           _blocY = true;
628                           blocThis = true;
629                         }
630                       else
631                         pushOther = true;
632                     }
633                 }
634               if (fromRight)
635                 {
636                   if (other->_blocX)
637                     {
638                       newX = otherBR.right()+ 1;
639                       blocThis = true;
640                       _blocX = true;
641                     }
642                   else
643                     {
644                       othX = newX - otherBR.width();
645                       if (othX < Resource::Space_Margin)
646                         {
647                           othX = Resource::Space_Margin;
648                           other->_blocX = true;
649                           newX = otherBR.right()+ 1;
650                           _blocX = true;
651                           blocThis = true;
652                         }
653                       else
654                         pushOther = true;
655                     }
656                 }
657               //DEBTRACE("newX=" << newX << " newY=" << newY);
658               if (blocThis) child->setTopLeft(QPointF(newX, newY));
659               if (pushOther)
660                 {
661                   other->setTopLeft(QPointF(othX, othY));
662                 }
663             }
664         }
665     } 
666 }
667
668 void SceneComposedNodeItem::rebuildLinks()
669 {
670   DEBTRACE("SceneComposedNodeItem::rebuildLinks " << QtGuiContext::_delayCalc);
671   if (QtGuiContext::_delayCalc)
672     return;
673   CHRONO(1);
674   CHRONO(2);
675   LinkMatrix matrix(this);
676   matrix.compute();
677   CHRONOSTOP(2);
678   CHRONO(3);
679   list<linkdef> alist = matrix.getListOfDataLinkDef();
680   list<linkdef> blist = matrix.getListOfCtrlLinkDef(); // add list operator ?
681   for (list<linkdef>::const_iterator ii = blist.begin(); ii != blist.end(); ++ii)
682     alist.push_back(*ii);
683
684   CHRONOSTOP(3);
685   CHRONO(4);
686   LinkAStar astar(matrix);
687   for (list<linkdef>::const_iterator it = alist.begin(); it != alist.end(); ++it)
688     {
689       linkdef ali = *it;
690       DEBTRACE("from("<<ali.from.first<<","<<ali.from.second
691                <<") to ("<<ali.to.first<<","<<ali.to.second
692                <<") " << ali.item->getLabel().toStdString());
693       if(ali.from.first<0||ali.from.second<0||ali.to.first<0||ali.to.second<0) continue;
694       CHRONO(5);
695       bool isPath = astar.computePath(LNode(ali.from), LNode(ali.to));
696       CHRONOSTOP(5);
697       CHRONO(6);
698       if (! isPath) DEBTRACE("Link Path not found !");
699       if (! isPath) continue;
700       LNodePath ijPath = astar.givePath();
701       if(Scene::_addRowCols)
702         matrix.incrementCost(ijPath);
703       LinkPath apath = matrix.getPath(ijPath);
704 //       DEBTRACE(apath.size());
705       CHRONOSTOP(6);
706       CHRONO(7);
707       ali.item->setPath(apath);
708     }
709 }
710
711 void SceneComposedNodeItem::arrangeNodes(bool isRecursive)
712 {
713   DEBTRACE("SceneComposedItem::arrangeNodes " << isRecursive);
714
715   bool isExtern = !QtGuiContext::_delayCalc;
716   QtGuiContext::_delayCalc = true; // avoid rebuildLinks
717
718   SubjectComposedNode *scnode = dynamic_cast<SubjectComposedNode*>(getSubject());
719   YASSERT(scnode);
720   ComposedNode *cnode = dynamic_cast<ComposedNode*>(scnode->getNode());
721   YASSERT(cnode);
722
723   if (isRecursive)
724     {
725       list<Node*> children = cnode->edGetDirectDescendants();
726       for (list<Node*>::iterator it = children.begin(); it != children.end(); ++it)
727         {
728           DEBTRACE("child " << (*it)->getName());
729           SceneComposedNodeItem *scni = 0;
730           ComposedNode *cchild = dynamic_cast<ComposedNode*>(*it);
731           if (cchild)
732             {
733               SubjectNode* sn = GuiContext::getCurrent()->_mapOfSubjectNode[cchild];
734               SceneItem* sci = QtGuiContext::getQtCurrent()->_mapOfSceneItem[sn];
735               if (sci) scni = dynamic_cast<SceneComposedNodeItem*>(sci);
736             }
737           if (scni && (scni->getShownState() == expandShown))
738             {
739               DEBTRACE("call arrangeNode on child " << (*it)->getName());
740               scni->arrangeNodes(isRecursive);
741             }
742         }
743       arrangeChildNodes();
744     }
745   else
746     arrangeChildNodes();
747
748   if (isExtern)
749     {
750       QtGuiContext::_delayCalc = false; // allow rebuildLinks
751       if (Scene::_autoComputeLinks)
752         rebuildLinks();
753     }
754 }
755
756 void SceneComposedNodeItem::arrangeChildNodes()
757 {
758   reorganize();
759 }
760
761 void SceneComposedNodeItem::dragEnterEvent(QGraphicsSceneDragDropEvent *event)
762 {
763   bool accepted = false;
764   const ItemMimeData *myData = dynamic_cast<const ItemMimeData*>(event->mimeData());
765   if (myData)
766     {
767       if (myData->hasFormat("yacs/cataService") ||
768           myData->hasFormat("yacs/cataNode")    ||
769           myData->hasFormat("yacs/subjectNode"))
770         {
771           event->setAccepted(true);
772           _dragOver = true;
773           QGraphicsItem::update();
774           return;
775         }
776     }
777   event->setAccepted(accepted);
778 }
779
780 void SceneComposedNodeItem::dragLeaveEvent(QGraphicsSceneDragDropEvent *event)
781 {
782     Q_UNUSED(event);
783     _dragOver = false;
784     QGraphicsItem::update();
785 }
786
787 void SceneComposedNodeItem::dropEvent(QGraphicsSceneDragDropEvent *event)
788 {
789   Q_UNUSED(event);
790   _dragOver = false;
791   QGraphicsItem::update();
792
793   const ItemMimeData *myData = dynamic_cast<const ItemMimeData*>(event->mimeData());
794   if (!myData) return;
795   setEventPos(event->scenePos());
796   if (myData->hasFormat("yacs/cataService") || myData->hasFormat("yacs/cataNode"))
797     {
798       SubjectComposedNode *cnode = dynamic_cast<SubjectComposedNode*>(getSubject());
799       bool createNewComponentInstance=Resource::COMPONENT_INSTANCE_NEW;
800       // by default getControl gives false. In this case we use the user preference COMPONENT_INSTANCE_NEW
801       // to create the node. If getControl gives true we invert the user preference
802       if(myData->getControl())
803         createNewComponentInstance=!Resource::COMPONENT_INSTANCE_NEW;
804       QtGuiContext::getQtCurrent()->getGMain()->_guiEditor->CreateNodeFromCatalog(myData, cnode,createNewComponentInstance);
805     }
806   else if(myData->hasFormat("yacs/subjectNode"))
807     {
808       Subject *sub = myData->getSubject();
809       if (!sub) return;
810       SubjectNode *node = dynamic_cast<SubjectNode*>(sub);
811       if (!node) return;
812       if (dynamic_cast<SubjectProc*>(node)) return; // --- do not reparent proc !
813       SubjectComposedNode *cnode = dynamic_cast<SubjectComposedNode*>(getSubject());
814       if (cnode)
815         if (!node->reparent(cnode))
816           Message mess;
817     }
818 }
819
820 QColor SceneComposedNodeItem::getPenColor()
821 {
822   if (_dragOver)
823     return Resource::dragOver;
824   if (isSelected())
825     return _hiPenColor;
826   else 
827     return _penColor;
828 }
829
830 QColor SceneComposedNodeItem::getBrushColor()
831 {
832   if (_dragOver)
833     return _hiBrushColor;
834
835   QColor color;
836   if (isSelected())
837     color = _hiBrushColor;
838   else if (_emphasized)
839     color = Resource::emphasizeBrushColor;
840   else 
841     color = _brushColor;
842
843   if (_hover)
844     color = hoverColor(color);
845   return color;
846 }
847
848 void SceneComposedNodeItem::updateChildItems()
849 {
850   SceneNodeItem::updateChildItems();
851   if(!_header)
852     return;
853   foreach (QGraphicsItem *child, _header->childItems())
854     {
855       if (SceneItem *sci = dynamic_cast<SceneItem*>(child))
856         {
857            sci->updateLinks();
858         }
859     }
860 }
861