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