Salome HOME
mergefrom branch BR_V511_PR tag mergeto_trunk_03feb09
[modules/yacs.git] / src / genericgui / SceneComposedNodeItem.cxx
1 //  Copyright (C) 2006-2008  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 #include "SceneBlocItem.hxx"
20 #include "SceneComposedNodeItem.hxx"
21 #include "SceneElementaryNodeItem.hxx"
22 #include "SceneHeaderItem.hxx"
23 #include "SceneHeaderNodeItem.hxx"
24 #include "SceneInPortItem.hxx"
25 #include "SceneOutPortItem.hxx"
26 #include "SceneLinkItem.hxx"
27 #include "SceneCtrlLinkItem.hxx"
28 #include "LinkMatrix.hxx"
29 #include "LinkAStar.hxx"
30 #include "ItemMimeData.hxx"
31 #include "QtGuiContext.hxx"
32 #include "Menus.hxx"
33 #include "Message.hxx"
34 #include "guiObservers.hxx"
35 #include "GuiEditor.hxx"
36 #include "Scene.hxx"
37 #include "Switch.hxx"
38
39 #include <QPointF>
40 #include <QGraphicsSceneDragDropEvent>
41
42 #include <cassert>
43
44 //#define _DEVDEBUG_
45 #include "YacsTrace.hxx"
46
47 using namespace std;
48 using namespace YACS::ENGINE;
49 using namespace YACS::HMI;
50
51 SceneComposedNodeItem::SceneComposedNodeItem(QGraphicsScene *scene, SceneItem *parent,
52                                              QString label, Subject *subject)
53   : SceneNodeItem(scene, parent, label, subject)
54 {
55   DEBTRACE("SceneComposedNodeItem::SceneComposedNodeItem " <<label.toStdString());
56   _brushColor   = QColor(213,213,213);
57   _hiBrushColor = QColor(225,225,225);
58   _penColor     = QColor(120,120,120);
59   _hiPenColor   = QColor( 60, 60, 60);
60   _dragOver = false;
61   setAcceptDrops(true);
62 }
63
64 SceneComposedNodeItem::~SceneComposedNodeItem()
65 {
66 }
67
68 QRectF SceneComposedNodeItem::childrenBoundingRect() const
69 {
70   QRectF ChildrenBRect =QRectF(x(), y(), 5, 5);
71   if (_header) ChildrenBRect = _header->getMinimalBoundingRect();
72   for (list<AbstractSceneItem*>::const_iterator it=_children.begin(); it!=_children.end(); ++it)
73     ChildrenBRect = ChildrenBRect.united(childBoundingRect(*it));
74   return ChildrenBRect;
75 }
76
77 void SceneComposedNodeItem::paint(QPainter *painter,
78                           const QStyleOptionGraphicsItem *option,
79                           QWidget *widget)
80 {
81   //DEBTRACE("SceneComposedNodeItem::paint " << _label.toStdString());
82   painter->save();
83   painter->setBrush(QBrush(Qt::NoBrush));
84   painter->setPen(QPen(Qt::NoPen));
85   painter->drawRect(QRectF(0, 0, _width, _height));
86   painter->setPen(getPenColor());
87   painter->setBrush(getBrushColor());
88   painter->drawRect(QRectF(_nml, _nml,
89                            _width-2*_nml, _height-2*_nml));
90   painter->restore();
91 }
92
93 void SceneComposedNodeItem::update(GuiEvent event, int type, Subject* son)
94 {
95   DEBTRACE("SceneComposedNodeItem::update "<< eventName(event)<<" "<<type<<" "<<son);
96   SceneNodeItem::update(event, type, son);
97   AbstractSceneItem *item;
98   switch (event)
99     {
100     case YACS::HMI::ADD:
101       switch (type)
102         {
103         case YACS::HMI::BLOC:
104           item =  new SceneBlocItem(_scene,
105                                     this,
106                                     son->getName().c_str(),
107                                     son);
108           item->addHeader();
109           autoPosNewChild(item, _children, true);
110           break;
111         case YACS::HMI::FORLOOP:
112         case YACS::HMI::WHILELOOP:
113         case YACS::HMI::SWITCH:
114         case YACS::HMI::FOREACHLOOP:
115         case YACS::HMI::OPTIMIZERLOOP:
116           item =  new SceneComposedNodeItem(_scene,
117                                             this,
118                                             son->getName().c_str(),
119                                             son);
120           item->addHeader();
121           autoPosNewChild(item, _children, true);
122           break;
123         case YACS::HMI::PYTHONNODE:
124         case YACS::HMI::PYFUNCNODE:
125         case YACS::HMI::CORBANODE:
126         case YACS::HMI::CPPNODE:
127         case YACS::HMI::SALOMENODE:
128         case YACS::HMI::SALOMEPYTHONNODE:
129         case YACS::HMI::XMLNODE:
130         case YACS::HMI::PRESETNODE:
131         case YACS::HMI::OUTNODE:
132         case YACS::HMI::STUDYINNODE:
133         case YACS::HMI::STUDYOUTNODE:
134           item =  new SceneElementaryNodeItem(_scene,
135                                               this,
136                                               son->getName().c_str(),
137                                               son);
138           item->addHeader();
139           autoPosNewChild(item, _children, true);
140           break;
141         case YACS::HMI::INPUTPORT:
142         case YACS::HMI::INPUTDATASTREAMPORT:
143           item =  new SceneInPortItem(_scene,
144                                       _header,
145                                       son->getName().c_str(),
146                                       son);
147           _header->autoPosNewPort(item);
148           _inPorts.push_back(item);
149           break;
150         case YACS::HMI::OUTPUTPORT:
151         case YACS::HMI::OUTPUTDATASTREAMPORT:
152           item =  new SceneOutPortItem(_scene,
153                                        _header,
154                                        son->getName().c_str(),
155                                        son);
156           _header->autoPosNewPort(item);
157           _outPorts.push_back(item);
158           break;
159         default:
160           DEBTRACE("SceneComposedNodeItem::update() ADD, type not handled:" << type);
161         }
162       break;
163     case YACS::HMI::ADDLINK:
164       switch (type)
165         {
166         case YACS::HMI::DATALINK:
167           if (SubjectLink* slink = dynamic_cast<SubjectLink*>(son))
168             {
169               SubjectDataPort* soutp = slink->getSubjectOutPort();
170               SubjectDataPort* sinp  = slink->getSubjectInPort();
171               SceneItem * scout = QtGuiContext::getQtCurrent()->_mapOfSceneItem[soutp];
172               SceneItem * scin  = QtGuiContext::getQtCurrent()->_mapOfSceneItem[sinp];
173               ScenePortItem* from = dynamic_cast<ScenePortItem*>(scout);
174               ScenePortItem* to  = dynamic_cast<ScenePortItem*>(scin);
175               item = new SceneLinkItem(_scene,
176                                        this,
177                                        from, to,
178                                        son->getName().c_str(),
179                                        son);
180             }
181           break;
182         }
183       break;
184     case YACS::HMI::ADDCONTROLLINK:
185       switch (type)
186         {
187         case YACS::HMI::CONTROLLINK:
188           if (SubjectControlLink* slink = dynamic_cast<SubjectControlLink*>(son))
189             {
190               SubjectNode* soutn = slink->getSubjectOutNode();
191               SubjectNode* sinn  = slink->getSubjectInNode();
192               SceneItem * scout = QtGuiContext::getQtCurrent()->_mapOfSceneItem[soutn];
193               SceneItem * scin  = QtGuiContext::getQtCurrent()->_mapOfSceneItem[sinn];
194               SceneNodeItem* nodefrom = dynamic_cast<SceneNodeItem*>(scout);
195               SceneNodeItem* nodeto  = dynamic_cast<SceneNodeItem*>(scin);
196               if (!nodeto || !nodefrom) DEBTRACE("CONTROLLINK problem -----------------");
197               ScenePortItem* from = nodefrom->getCtrlOutPortItem();
198               ScenePortItem* to = nodeto->getCtrlInPortItem();
199               if (!to || !from) DEBTRACE("CONTROLLINK problem -----------------");
200               item = new SceneCtrlLinkItem(_scene,
201                                            this,
202                                            from, to,
203                                            son->getName().c_str(),
204                                            son);
205             }
206           break;
207         }
208       break;
209     case YACS::HMI::REMOVE:
210       //SceneObserverItem::update(event, type, son);
211       reorganize();
212       break;
213     case YACS::HMI::SETCASE:
214       {
215         SubjectSwitch *sSwitch = dynamic_cast<SubjectSwitch*>(_subject);
216         if (sSwitch)
217           {
218             Switch *aSwitch = dynamic_cast<Switch*>(sSwitch->getNode());
219             Node *node = aSwitch->edGetNode(type);
220             if (node)
221               {
222                 if (GuiContext::getCurrent()->_mapOfSubjectNode.count(node))
223                   {
224                     Subject* sub = GuiContext::getCurrent()->_mapOfSubjectNode[node];
225                     if (QtGuiContext::getQtCurrent()->_mapOfSceneItem.count(sub))
226                       {
227                         SceneItem* item = QtGuiContext::getQtCurrent()->_mapOfSceneItem[sub];
228                         SceneNodeItem *scnode = dynamic_cast<SceneNodeItem*>(item);
229                         if (scnode) scnode->updateName();
230                       }
231                   }
232               }
233           }
234       }
235       break;
236     case YACS::HMI::CUT:
237       {
238         SceneItem * sinode  = QtGuiContext::getQtCurrent()->_mapOfSceneItem[son];
239         removeChildFromList(sinode);
240       }
241       break;
242     case YACS::HMI::PASTE:
243       {
244         SceneItem * sinode  = QtGuiContext::getQtCurrent()->_mapOfSceneItem[son];
245         sinode->setParent(this);
246         autoPosNewChild(sinode, _children, true);
247       }
248       break;
249     default:
250        ;
251 //       DEBTRACE("SceneComposedNodeItem::update(), event not handled: "<< eventName(event));
252     }
253 }
254
255 void SceneComposedNodeItem::autoPosNewChild(AbstractSceneItem *item,
256                                             const std::list<AbstractSceneItem*> alreadySet,
257                                             bool isNew)
258 {
259   QRectF childrenBox;
260   qreal xLeft = _margin + _nml;
261   qreal yTop  = getHeaderBottom() + _margin + _nml;
262   for (list<AbstractSceneItem*>::const_iterator it=alreadySet.begin(); it!=alreadySet.end(); ++it)
263     {
264       childrenBox = childrenBox.united(childBoundingRect(*it));
265       DEBTRACE((*it)->getLabel().toStdString());
266       DEBTRACE("childrenBox valid " << childrenBox.right() << " " << childrenBox.bottom());
267     }
268   if (childrenBox.isValid())
269     xLeft += childrenBox.right();
270   DEBTRACE("left, top " << xLeft  << " " << yTop);
271   QPointF topLeft(xLeft, yTop);
272   if (isNew) _children.push_back(item);
273   item->setTopLeft(topLeft);
274 }
275
276 void SceneComposedNodeItem::popupMenu(QWidget *caller, const QPoint &globalPos)
277 {
278   ComposedNodeMenu m;
279   m.popupMenu(caller, globalPos);
280 }
281
282 std::list<AbstractSceneItem*> SceneComposedNodeItem::getChildren()
283 {
284   return _children;
285 }
286
287 void SceneComposedNodeItem::removeChildFromList(AbstractSceneItem* child)
288 {
289   _children.remove(child);
290 }
291
292 void SceneComposedNodeItem::reorganize()
293 {
294   DEBTRACE("SceneComposedNodeItem::reorganize() " << _label.toStdString());
295   list<AbstractSceneItem*> alreadySet;
296   for (list<AbstractSceneItem*>::const_iterator it=_children.begin(); it!=_children.end(); ++it)
297     {
298       autoPosNewChild(*it, alreadySet);
299       alreadySet.push_back(*it);
300     }
301 }
302
303 void SceneComposedNodeItem::collisionResolv(SceneItem* child, QPointF oldPos)
304 {
305   //DEBTRACE("SceneComposedNodeItem::collisionResolv " << _label.toStdString());
306   for (list<AbstractSceneItem*>::const_iterator it=_children.begin(); it!=_children.end(); ++it)
307     {
308       SceneNodeItem *other = dynamic_cast<SceneNodeItem*>(*it);
309       if (other && (other != child))
310         {
311           if (child->collidesWithItem(other))
312             {
313               //DEBTRACE("collision detected with " << other->getLabel().toStdString());
314               QRectF otherBR = (other->mapToParent(other->boundingRect())).boundingRect();
315               //oldPos = mapFromScene(oldPos);
316               qreal oldX = oldPos.x();
317               qreal oldY = oldPos.y();
318               qreal newX = child->pos().x();
319               qreal newY = child->pos().y();
320               qreal othX = otherBR.left()+0.5;
321               qreal othY = otherBR.top()+0.5;
322               //DEBTRACE("oldX=" << oldX << " oldY=" << oldY << " newX=" << newX << " newY=" << newY);
323               //DEBTRACE("otherLeft=" << otherBR.left() << " otherRight=" << otherBR.right() <<
324               //         " otherTop=" << otherBR.top() << " otherBottom=" << otherBR.bottom());
325               //DEBTRACE("width=" << child->boundingRect().width() <<
326               //         " height=" << child->boundingRect().height());
327               bool fromTop    = (((oldY + child->boundingRect().height()) <= otherBR.top()+1) &&
328                                  ((newY + child->boundingRect().height()) >= otherBR.top()));
329               bool fromBottom = (( oldY >= otherBR.bottom()) &&
330                                  ( newY <= otherBR.bottom()));
331               bool fromRight  = (( oldX >= otherBR.right()) &&
332                                  ( newX <= otherBR.right()));
333               bool fromLeft   = (((oldX+ child->boundingRect().width()) <= otherBR.left()+1) &&
334                                  ((newX+ child->boundingRect().width()) >= otherBR.left()));
335               //DEBTRACE("fromTop=" << fromTop << " fromBottom=" << fromBottom 
336               //         << " fromRight=" << fromRight << " fromLeft=" << fromLeft);
337               bool pushOther =false;
338               bool blocThis = false;
339               if (fromTop)
340                 {
341                   //newY = otherBR.top() - child->boundingRect().height() -_margin;
342                   othY = newY + child->boundingRect().height();
343                   pushOther = true;
344                 }
345               if (fromLeft)
346                 {
347                   //newX = otherBR.left() -child->boundingRect().width() - _margin;
348                   othX = newX+ child->boundingRect().width();
349                   pushOther = true;
350                 }
351               if (fromBottom)
352                 {
353                   newY = otherBR.bottom() + 1;
354                   blocThis = true;
355                 }
356               if (fromRight)
357                 {
358                   newX = otherBR.right()+ 1;
359                   blocThis = true;
360                 }
361               //DEBTRACE("newX=" << newX << " newY=" << newY);
362               if (blocThis) child->setTopLeft(QPointF(newX, newY));
363               if (pushOther)
364                 {
365                   other->setTopLeft(QPointF(othX, othY));
366                 }
367             }
368         }
369     } 
370 }
371
372 void SceneComposedNodeItem::rebuildLinks()
373 {
374   LinkMatrix matrix(this);
375   matrix.compute();
376   list<linkdef> alist = matrix.getListOfDataLinkDef();
377   list<linkdef> blist = matrix.getListOfCtrlLinkDef(); // add list operator ?
378   for (list<linkdef>::const_iterator ii = blist.begin(); ii != blist.end(); ++ii)
379     alist.push_back(*ii);
380
381   LinkAStar astar(matrix);
382   for (list<linkdef>::const_iterator it = alist.begin(); it != alist.end(); ++it)
383     {
384       linkdef ali = *it;
385 //       DEBTRACE("from("<<ali.from.first<<","<<ali.from.second
386 //                <<") to ("<<ali.to.first<<","<<ali.to.second
387 //                <<") " << ali.item->getLabel().toStdString());
388       bool isPath = astar.computePath(LNode(ali.from), LNode(ali.to));
389       if (! isPath) DEBTRACE("Link Path not found !");
390       LinkPath apath = matrix.getPath(astar.givePath());
391 //       DEBTRACE(apath.size());
392       ali.item->setPath(apath);
393     }
394
395 }
396
397 void SceneComposedNodeItem::arrangeNodes(bool isRecursive)
398 {
399   DEBTRACE("SceneComposedItem::arrangeNodes " << isRecursive);
400
401   SubjectComposedNode *scnode = dynamic_cast<SubjectComposedNode*>(getSubject());
402   assert(scnode);
403   ComposedNode *cnode = dynamic_cast<ComposedNode*>(scnode->getNode());
404   assert(cnode);
405
406   if (isRecursive)
407     {
408       list<Node*> children = cnode->edGetDirectDescendants();
409       for (list<Node*>::iterator it = children.begin(); it != children.end(); ++it)
410         {
411           DEBTRACE("child " << (*it)->getName());
412           SceneComposedNodeItem *scni = 0;
413           ComposedNode *cchild = dynamic_cast<ComposedNode*>(*it);
414           if (cchild)
415             {
416               SubjectNode* sn = GuiContext::getCurrent()->_mapOfSubjectNode[cchild];
417               SceneItem* sci = QtGuiContext::getQtCurrent()->_mapOfSceneItem[sn];
418               if (sci) scni = dynamic_cast<SceneComposedNodeItem*>(sci);
419             }
420           if (scni)
421             {
422               DEBTRACE("call arrangeNode on child " << (*it)->getName());
423               scni->arrangeNodes(isRecursive);
424             }
425         }
426       arrangeChildNodes();
427     }
428   else
429     arrangeChildNodes();
430 }
431
432 void SceneComposedNodeItem::dragEnterEvent(QGraphicsSceneDragDropEvent *event)
433 {
434   bool accepted = false;
435   const ItemMimeData *myData = dynamic_cast<const ItemMimeData*>(event->mimeData());
436   if (myData)
437     {
438       if (myData->hasFormat("yacs/cataService") ||
439           myData->hasFormat("yacs/cataNode")    ||
440           myData->hasFormat("yacs/subjectNode"))
441         {
442           event->setAccepted(true);
443           _dragOver = true;
444           QGraphicsItem::update();
445           return;
446         }
447     }
448   event->setAccepted(accepted);
449 }
450
451 void SceneComposedNodeItem::dragLeaveEvent(QGraphicsSceneDragDropEvent *event)
452 {
453     Q_UNUSED(event);
454     _dragOver = false;
455     QGraphicsItem::update();
456 }
457
458 void SceneComposedNodeItem::dropEvent(QGraphicsSceneDragDropEvent *event)
459 {
460   Q_UNUSED(event);
461   _dragOver = false;
462   QGraphicsItem::update();
463
464   const ItemMimeData *myData = dynamic_cast<const ItemMimeData*>(event->mimeData());
465   if (!myData) return;
466   if (myData->hasFormat("yacs/cataService") || myData->hasFormat("yacs/cataNode"))
467     {
468       SubjectComposedNode *cnode = dynamic_cast<SubjectComposedNode*>(getSubject());
469       QtGuiContext::getQtCurrent()->getGMain()->_guiEditor->CreateNodeFromCatalog(myData, cnode);
470     }
471   else if(myData->hasFormat("yacs/subjectNode"))
472     {
473       Subject *sub = myData->getSubject();
474       if (!sub) return;
475       SubjectNode *node = dynamic_cast<SubjectNode*>(sub);
476       if (!node) return;
477       SubjectComposedNode *cnode = dynamic_cast<SubjectComposedNode*>(getSubject());
478       if (cnode)
479         if (node->reparent(cnode))
480           Message mess;
481     }
482 }
483
484 QColor SceneComposedNodeItem::getPenColor()
485 {
486   if (_dragOver)
487     return QColor(255,0,0);
488   if (isSelected())
489     return _hiPenColor;
490   else 
491     return _penColor;
492 }
493
494 QColor SceneComposedNodeItem::getBrushColor()
495 {
496   if (_dragOver)
497     return _hiBrushColor;
498
499   QColor color;
500   if (isSelected())
501     color = _hiBrushColor;
502   else 
503     color = _brushColor;
504
505   if (_hover)
506     color = hoverColor(color);
507   return color;
508 }
509