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