Salome HOME
955d3b89698ce8f31daf577d3e557866e4610c7a
[modules/superv.git] / src / SUPERVGUI / SUPERVGUI_CanvasLink.cxx
1 //  SUPERV SUPERVGUI : GUI for Supervisor component
2 //
3 //  Copyright (C) 2003  OPEN CASCADE
4 //
5 //  File   : SUPERVGUI_GanvasNodePrs.cxx
6 //  Author : Natalia KOPNOVA
7 //  Module : SUPERV
8
9 using namespace std;
10 #include "SUPERVGUI_CanvasLink.h"
11 #include "SUPERVGUI_Canvas.h"
12 #include "SUPERVGUI_CanvasPort.h"
13 #include "SUPERVGUI_Main.h"
14
15 //#define CHECKTIME
16
17 #ifdef CHECKTIME
18 #include <sys/timeb.h>
19 #endif
20
21 #define DRAW_COLOR Qt::black
22 #define SELECT_COLOR Qt::magenta
23 #define SKETCH_COLOR Qt::darkGreen
24 #define STREAM_COLOR Qt::darkRed // QColor(0, 64, 128) // Qt::blue
25
26 #define LINE_WIDTH 1
27
28
29 SUPERVGUI_CanvasLink::SUPERVGUI_CanvasLink(QObject* theParent, SUPERVGUI_Main* theMain, SUPERV::Link_ptr theLink):
30   QObject(theParent),
31   myMain(theMain),
32   myLink(0),
33   myInputPort(0),
34   myOutputPort(0),
35   myHilighted(false),
36   mySelectedItem(0)
37 {
38   if (theLink && !SUPERV_isNull(theLink)) {
39     myLink = SUPERV::Link::_duplicate(theLink);
40
41     SUPERVGUI_Canvas* aCanvas = myMain->getCanvas();
42     setName(aCanvas->getLinkName(theLink));
43
44     myInputPort = aCanvas->getPort(myLink->InPort());
45     if (myInputPort) myInputPort->addLink(this);
46
47     myOutputPort = aCanvas->getPort(myLink->OutPort());
48     if (myOutputPort) myOutputPort->addLink(this);
49
50     if (myInputPort->isStream())
51       myColor = STREAM_COLOR;
52     else
53       myColor = DRAW_COLOR;
54   }
55 }
56
57 SUPERVGUI_CanvasLink::~SUPERVGUI_CanvasLink()
58 {
59   for (QCanvasItemList::Iterator it = myPrs.begin(); it != myPrs.end(); ++it) {
60     (*it)->hide();
61     delete *it;
62   }
63   if (myInputPort) myInputPort->removeLink(this);
64   if (myOutputPort) myOutputPort->removeLink(this);
65 }
66
67 void SUPERVGUI_CanvasLink::createPrs()
68 {
69   if (myLink && !SUPERV_isNull(myLink)) {
70     if (myInputPort) {
71       addPoint(myInputPort->getConnectionPoint());
72     }
73     if (!myMain->getCanvas()->isControlView()) {
74       long x, y;
75       for (int i = 0; i < myLink->CoordsSize(); i++) {
76         myLink->Coords(i+1, x, y);
77         addPoint(QPoint(x, y), i+1);
78       }
79     }
80     if (myOutputPort) {
81       addPoint(myOutputPort->getConnectionPoint());
82     }
83   }
84   setColor(myHilighted ? SELECT_COLOR : myColor);
85 }
86
87 void SUPERVGUI_CanvasLink::addPoint(const QPoint& thePoint, const int& theIndex)
88 {
89   SUPERVGUI_CanvasPointPrs* aPoint;
90   if (myPrs.empty()) {
91     aPoint = new SUPERVGUI_CanvasPointPrs(myMain->getCanvas(), this, theIndex);
92     aPoint->setColor(myColor);
93     aPoint->move(thePoint.x(), thePoint.y());
94   }
95   else {
96     SUPERVGUI_CanvasPointPrs* aPrev = (SUPERVGUI_CanvasPointPrs*) myPrs.last();
97
98     SUPERVGUI_CanvasEdgePrs* anEdge = new SUPERVGUI_CanvasEdgePrs(myMain->getCanvas(), this);
99     anEdge->setColor(myColor);
100     myPrs.append(anEdge);
101
102     aPoint = new SUPERVGUI_CanvasPointPrs(myMain->getCanvas(), this, theIndex);
103     aPoint->setColor(myColor);
104     aPoint->move(thePoint.x(), thePoint.y());
105
106     aPrev->setOutEdge(anEdge);
107     aPoint->setInEdge(anEdge);
108   }
109   myPrs.append(aPoint);
110 }
111
112 void SUPERVGUI_CanvasLink::setSelectedObject(QCanvasItem* theItem, const QPoint& thePoint)
113 {
114   mySelectedItem = theItem;
115   mySelectedPoint = thePoint;
116 }
117
118 QPopupMenu* SUPERVGUI_CanvasLink::getPopupMenu(QWidget* theParent) 
119 {
120   QPopupMenu* popup = new QPopupMenu(theParent);
121   int anItem;
122   anItem = popup->insertItem(tr("MSG_DELLINK"), this, SLOT(remove()));
123   if (myInputPort && 
124       (myInputPort->getEngine()->Kind() != SUPERV::EndSwitchParameter ||
125        myInputPort->getEngine()->Node()->Kind() != SUPERV::EndSwitchNode))
126     if (myInputPort->getEngine()->Kind() == SUPERV::LoopParameter ||
127         myOutputPort && myOutputPort->getEngine()->Kind() == SUPERV::LoopParameter)
128       popup->setItemEnabled(anItem, false);
129
130   popup->insertSeparator();
131   if (mySelectedItem) {
132     anItem = popup->insertItem(tr("MSG_ADD_POINT"), this, SLOT(addPoint()));
133     if (mySelectedItem->rtti() == SUPERVGUI_Canvas::Rtti_LinkPoint)
134       popup->setItemEnabled(anItem, false);
135
136     anItem = popup->insertItem(tr("MSG_DEL_POINT"), this, SLOT(removePoint()));
137     if (mySelectedItem->rtti() == SUPERVGUI_Canvas::Rtti_LinkEdge)
138       popup->setItemEnabled(anItem, false);
139   }
140   return popup;
141 }
142
143 void SUPERVGUI_CanvasLink::show()
144 {
145   if (myPrs.isEmpty()) createPrs();
146
147   for (QCanvasItemList::Iterator it = myPrs.begin(); it != myPrs.end(); ++it) {
148     (*it)->show();
149   }
150 }
151
152 void SUPERVGUI_CanvasLink::merge()
153 {
154   // remove old presentation
155   for (QCanvasItemList::Iterator it = myPrs.begin(); it != myPrs.end(); ++it) {
156     delete *it;
157   }
158   myPrs.clear();
159
160   // display a new one
161   show();
162 }
163
164 void SUPERVGUI_CanvasLink::setHilighted(bool state)
165 {
166   myHilighted = state;
167   setColor(myHilighted ? SELECT_COLOR : myColor);
168   if (!myPrs.isEmpty()) {
169     bool disp = myPrs.first()->isVisible();
170     if (disp) {
171       for (QCanvasItemList::Iterator it = myPrs.begin(); it != myPrs.end(); ++it) {
172         (*it)->hide(); (*it)->show();
173       }
174       myMain->getCanvas()->update();
175     }
176   }
177 }
178
179 void SUPERVGUI_CanvasLink::moveByPort(SUPERVGUI_CanvasPort* thePort, int dx, int dy)
180 {
181   if (myInputPort && myInputPort == thePort) {
182     myPrs.first()->moveBy(dx, dy);
183     return;
184   }
185   if (myOutputPort && myOutputPort == thePort) {
186     myPrs.last()->moveBy(dx, dy);
187     return;
188   }
189 }
190
191 void SUPERVGUI_CanvasLink::moveByPort(SUPERVGUI_CanvasPort* thePort)
192 {
193   QPoint p = thePort->getConnectionPoint();
194   if (myInputPort && myInputPort == thePort) {
195     myPrs.first()->move(p.x(), p.y());
196     return;
197   }
198   if (myOutputPort && myOutputPort == thePort) {
199     myPrs.last()->move(p.x(), p.y());
200     return;
201   }
202 }
203
204 void SUPERVGUI_CanvasLink::setColor(const QColor& theColor)
205 {
206   for (QCanvasItemList::Iterator it = myPrs.begin(); it != myPrs.end(); ++it) {
207     if ((*it)->rtti() == SUPERVGUI_Canvas::Rtti_LinkPoint) {
208       ((SUPERVGUI_CanvasPointPrs*)(*it))->setColor(theColor);
209     }
210     else if ((*it)->rtti() == SUPERVGUI_Canvas::Rtti_LinkEdge) {
211       ((SUPERVGUI_CanvasEdgePrs*)(*it))->setColor(theColor);
212     }
213   }
214 }
215
216 void SUPERVGUI_CanvasLink::remove() {
217   // IPAL9369 : check the dataflow readiness to modify
218   if ( !myMain->ReadyToModify() ) // null dataflow or executing, ..
219     return;
220
221   myMain->Editing(); // PAL6170: GUI->Engine: setting "Editing" flag 
222
223   QString aValue;
224   SUPERVGUI_CanvasPortIn* aPort = 0;
225   SUPERVGUI_Canvas* aCanvas = myMain->getCanvas();
226   if (myLink && !SUPERV_isNull(myLink)) {
227     if (myInputPort) {
228       if (myInputPort->getEngine()->IsParam() || myInputPort->getEngine()->IsInLine()) {
229         aValue = QString(myInputPort->getEngine()->ToString());
230         aPort = (SUPERVGUI_CanvasPortIn*) myInputPort;
231       }
232     }
233     myLink->destroy();
234   }
235   delete this;
236   if (aPort && !aValue.isEmpty() && myMain->getDataflow()->GraphLevel() == 0) {
237     aPort->setValue(aValue);
238   }
239   aCanvas->update();
240 }
241
242 void SUPERVGUI_CanvasLink::addPoint() {
243   if (mySelectedItem && mySelectedItem->rtti() == SUPERVGUI_Canvas::Rtti_LinkEdge) {
244     SUPERVGUI_CanvasEdgePrs* anEdge = (SUPERVGUI_CanvasEdgePrs*) mySelectedItem;
245
246     int anIndex = 1;
247     QCanvasItemList::Iterator it;
248     for (it = myPrs.begin(); it != myPrs.end(); ++it) {
249       if ((*it) == anEdge) break;
250     }
251     if (it != myPrs.begin()) {
252       --it;
253       SUPERVGUI_CanvasPointPrs* aPoint = (SUPERVGUI_CanvasPointPrs*) (*it);
254       anIndex = aPoint->getIndex()+1;
255       if (anIndex < 1) anIndex = 1;
256     }
257     if (myLink && !SUPERV_isNull(myLink)) 
258       myLink->AddCoord(anIndex, mySelectedPoint.x(), mySelectedPoint.y());
259     merge();
260     myMain->getCanvas()->update();
261   }
262 }
263
264 void SUPERVGUI_CanvasLink::removePoint() {
265   if (mySelectedItem && mySelectedItem->rtti() == SUPERVGUI_Canvas::Rtti_LinkPoint) {
266     SUPERVGUI_CanvasPointPrs* aPoint = (SUPERVGUI_CanvasPointPrs*) mySelectedItem;
267     if (myLink && !SUPERV_isNull(myLink)) 
268       myLink->RemoveCoord(aPoint->getIndex());
269     merge();
270     myMain->getCanvas()->update();
271   }
272 }
273
274 /*
275 //===============================================================================
276 //  SUPERVGUI_CanvasStreamLink: new link to be created
277 //===============================================================================
278 SUPERVGUI_CanvasStreamLink::SUPERVGUI_CanvasStreamLink(QObject* theParent, SUPERVGUI_Main* theMain, 
279                                                        SUPERV::StreamLink_ptr theLink):
280   SUPERVGUI_CanvasLink(theParent, theMain, theLink)
281 {
282   if (theLink && !SUPERV_isNull(theLink)) {
283     myStreamLink = SUPERV::StreamLink::_duplicate(theLink);
284   }
285 }
286
287
288 void SUPERVGUI_CanvasStreamLink::remove() {
289   QString aValue;
290   SUPERVGUI_CanvasPortIn* aPort = 0;
291   SUPERVGUI_Canvas* aCanvas = getMain()->getCanvas();
292   if (myStreamLink && !SUPERV_isNull(myStreamLink)) {
293     if (getInputPort()) {
294       if (getInputPort()->getEngine()->IsParam() || getInputPort()->getEngine()->IsInLine()) {
295         aPort = (SUPERVGUI_CanvasPortIn*) getInputPort();
296         aValue = QString(aPort->getEngine()->ToString());
297       }
298     }
299     myStreamLink->destroy();
300   }
301   delete this;
302   if (aPort && !aValue.isEmpty()) {
303     aPort->setValue(aValue);
304   }
305   aCanvas->update();
306 }
307 */
308
309 //===============================================================================
310 //  SUPERVGUI_CanvasLinkBuilder: new link to be created
311 //===============================================================================
312 SUPERVGUI_CanvasLinkBuilder::SUPERVGUI_CanvasLinkBuilder(QObject* theParent, SUPERVGUI_Main* theMain, 
313                                                          SUPERVGUI_CanvasPort* thePort):
314   SUPERVGUI_CanvasLink(theParent, theMain),
315   myPort(thePort),
316   myFloatingEdge(0)
317 {
318   if (myPort) {
319     myPort->addLink(this);
320     addPoint(myPort->getConnectionPoint());
321   }
322   myColor = SKETCH_COLOR;
323 }
324
325 SUPERVGUI_CanvasLinkBuilder::~SUPERVGUI_CanvasLinkBuilder()
326 {
327   if (myFloatingEdge) delete myFloatingEdge;
328   if (myPort) myPort->removeLink(this);
329 }
330
331 bool SUPERVGUI_CanvasLinkBuilder::canCreateEngine(SUPERVGUI_CanvasPort* thePort)
332 {
333   if (thePort && myPort) {
334     SUPERVGUI_CanvasPort* aInPort;
335     SUPERVGUI_CanvasPort* aOutPort;
336
337     // check if ports are couple of input and output
338     if (myPort->getEngine()->IsInput()) {
339       aInPort = myPort;
340       if (thePort->getEngine()->IsInput())
341         return false;
342       aOutPort = thePort;
343     }
344     else {
345       aOutPort = myPort;
346       if (!thePort->getEngine()->IsInput())
347         return false;
348       aInPort = thePort;
349     }
350
351     // control if nodes are different, not the same node
352     QString aInNode(aInPort->getEngine()->Node()->Name());
353     QString aOutNode(aOutPort->getEngine()->Node()->Name());
354     if (aInNode.compare(aOutNode) == 0) // linking outport and inport of the same node
355       return false;
356
357     // control types of ports
358     int aInKind = aInPort->getEngine()->Kind();
359     int aOutKind = aOutPort->getEngine()->Kind();
360
361     // connect stream port with stream port only
362     if ((aInKind == SUPERV::DataStreamParameter && aOutKind != SUPERV::DataStreamParameter) ||
363         (aOutKind == SUPERV::DataStreamParameter && aInKind != SUPERV::DataStreamParameter))
364       return false;
365
366     // asv : 15.12.04 : NOT allow to connect Gate-to-InLine --> it does not make sence!
367     // Out Gate port can be connected only to In Gate port 
368     if ( aOutKind == SUPERV::GateParameter && aInKind != SUPERV::GateParameter )
369       return false;
370
371     // In Gate can be connected to (receive links from) Gate port and InLine ports (important for Switch nodes)
372     if ( aInKind == SUPERV::GateParameter && aOutKind != SUPERV::GateParameter && aOutKind != SUPERV::InLineParameter )
373         return false;
374
375     // asv : 15.12.04 : PAL7374, p.2.2 "Bugs and Improvements": multiple links into Gate port 
376     //                  for InGate it's OK to accept more than 1 link
377     // THESE NEEDS REVISION, ALSO DON'T ALLOW MANY LINKS TO "DEFAULT" PORT OF EndSwitch
378     //if ( aInPort->getEngine()->IsLinked() && aInKind != SUPERV::GateParameter ) 
379     
380     // control if port is already linked except for input inline ports of end switch node (check for EndSwitchParameter)
381     // and "Default" port of Switch node (check for aNode->isEndSwitch()).  "Default" port is linked by default, but we
382     // let it to be "re-linked" to another port. 
383     const bool isEndSwitch = ( aInKind == SUPERV::EndSwitchParameter || aInPort->getEngine()->Node()->IsEndSwitch() );
384     if ( !isEndSwitch && aInPort->getEngine()->IsLinked() ) 
385       return false;
386     
387     return true;
388   }
389   return false;
390 }
391
392 void SUPERVGUI_CanvasLinkBuilder::setCoords(SUPERV::Link_ptr theLink)
393 {
394   if (theLink) {
395     QCanvasItemList::Iterator it;
396     int anIndex = 1;
397     if (myPort->getEngine()->IsInput()) {
398       it = myPrs.begin(); ++it; // ignore the first point
399       for (; it != myPrs.end(); ++it) {
400         if ((*it)->rtti() == SUPERVGUI_Canvas::Rtti_LinkPoint) {
401           theLink->AddCoord(anIndex++, (int)(*it)->x(), (int)(*it)->y());
402         }
403       }
404     }
405     else {
406       it = myPrs.end(); --it;
407       for (; it != myPrs.begin(); --it) {
408         if ((*it)->rtti() == SUPERVGUI_Canvas::Rtti_LinkPoint) {
409           theLink->AddCoord(anIndex++, (int)(*it)->x(), (int)(*it)->y());
410         }
411       }
412     }
413   }
414 }
415
416 void SUPERVGUI_CanvasLinkBuilder::addNextPoint(const QPoint& thePoint, bool theOrtho)
417 {
418   if (myFloatingEdge) myFloatingEdge->hide();
419
420   if (!theOrtho || myPrs.empty()) {
421     addPoint(thePoint);
422   }
423   else {
424     SUPERVGUI_CanvasPointPrs* aPrev = (SUPERVGUI_CanvasPointPrs*) myPrs.last();
425     int x = (int)aPrev->x(); int y = (int)aPrev->y();
426     if (thePoint.x() != x && thePoint.y() != y) {
427       addPoint(QPoint(thePoint.x(), y), -2);
428     }
429     addPoint(thePoint);
430   }
431   show();
432 }
433
434 void SUPERVGUI_CanvasLinkBuilder::setFloatPoint(const QPoint& thePoint)
435 {
436   if (!myFloatingEdge) {
437     myFloatingEdge = new QCanvasLine(getMain()->getCanvas());
438     myFloatingEdge->setPen(QPen(myColor, LINE_WIDTH));
439   }
440   if (!myPrs.empty()) {
441     myFloatingEdge->setPoints((int)myPrs.last()->x(), (int)myPrs.last()->y(), 
442                               thePoint.x(), thePoint.y());
443     myFloatingEdge->show();
444   }
445 }
446
447 void SUPERVGUI_CanvasLinkBuilder::removeLastPoint()
448 {
449   if (myPrs.count() > 1) {
450     QPoint aLast((int)myPrs.last()->x(), (int)myPrs.last()->y());
451     QCanvasItemList::Iterator it = myPrs.end();
452     bool removed = false;
453     --it;
454     for (; it != myPrs.begin(); --it) {
455       if ((*it)->rtti() == SUPERVGUI_Canvas::Rtti_LinkPoint) {
456         SUPERVGUI_CanvasPointPrs* aPoint = (SUPERVGUI_CanvasPointPrs*) (*it);
457         if (aPoint->getIndex() == -1 && removed) break;
458       }
459       QCanvasItem* anItem = (*it);
460       it = myPrs.remove(it);
461       delete anItem;
462       removed = true;
463     }
464     if (removed) {
465       if (myFloatingEdge) {
466         QPoint aPoint = myFloatingEdge->endPoint();
467         myFloatingEdge->setPoints((int)myPrs.last()->x(), (int)myPrs.last()->y(),
468                                   aPoint.x(), aPoint.y());
469       }
470       else
471         setFloatPoint(aLast);
472     }
473   }
474 }
475
476 void SUPERVGUI_CanvasLinkBuilder::moveByPort(SUPERVGUI_CanvasPort* thePort, int dx, int dy)
477 {
478   if (myPort && myPort == thePort) {
479     myPrs.first()->moveBy(dx, dy);
480     return;
481   }
482 }
483
484 void SUPERVGUI_CanvasLinkBuilder::moveByPort(SUPERVGUI_CanvasPort* thePort)
485 {
486   QPoint p = thePort->getConnectionPoint();
487   if (myPort && myPort == thePort) {
488     myPrs.first()->move(p.x(), p.y());
489     return;
490   }
491 }
492
493
494 //===============================================================================
495 //  SUPERVGUI_CanvasPointPrs: link point presentation
496 //===============================================================================
497 SUPERVGUI_CanvasPointPrs::SUPERVGUI_CanvasPointPrs(QCanvas* theCanvas, 
498                                                    SUPERVGUI_CanvasLink* theLink,
499                                                    const int& theIndex):
500   QCanvasEllipse(theCanvas),
501   myLink(theLink), myIndex(theIndex),
502   myInEdge(0), myOutEdge(0), myMoving(false)
503 {
504   setSize(POINT_SIZE, POINT_SIZE);
505   setZ(-1);
506 }
507
508 int SUPERVGUI_CanvasPointPrs::rtti() const
509 {
510   return SUPERVGUI_Canvas::Rtti_LinkPoint;
511 }
512
513 void SUPERVGUI_CanvasPointPrs::setInEdge(SUPERVGUI_CanvasEdgePrs* theEdge)
514 {
515   myInEdge = theEdge;
516   theEdge->setFromPoint(this);
517 }
518
519 void SUPERVGUI_CanvasPointPrs::setOutEdge(SUPERVGUI_CanvasEdgePrs* theEdge)
520 {
521   myOutEdge = theEdge;
522   theEdge->setToPoint(this); 
523 }
524
525 void SUPERVGUI_CanvasPointPrs::moveBy(double dx, double dy)
526 {
527   QCanvasEllipse::moveBy(dx, dy);
528   if (myInEdge) myInEdge->setFromPoint(this);
529   if (myOutEdge) myOutEdge->setToPoint(this);
530   //resize canvas view if mouse is outside
531   int w = (int)(x()+dx) + width() + GRAPH_MARGIN;
532   int h = (int)(y()+dy) + height() + GRAPH_MARGIN;
533   if (canvas()->width() > w) w = canvas()->width();
534   if (canvas()->height() > h) h = canvas()->height();
535   if (canvas()->width() < w || canvas()->height() < h) canvas()->resize(w, h);
536   if (myIndex > 0 && isMoving()) {
537     myLink->getEngine()->ChangeCoord(myIndex, (int)x(), (int)y());
538   }
539 }
540
541 void SUPERVGUI_CanvasPointPrs::setColor(const QColor& theColor)
542 {
543   setBrush(theColor);
544 }
545
546 //===============================================================================
547 //  SUPERVGUI_CanvasEdgePrs: link edge presentation
548 //===============================================================================
549 SUPERVGUI_CanvasEdgePrs::SUPERVGUI_CanvasEdgePrs(QCanvas* theCanvas, 
550                                                  SUPERVGUI_CanvasLink* theLink):
551   QCanvasLine(theCanvas),
552   myLink(theLink)
553 {
554   setZ(-2);
555 }
556
557 int SUPERVGUI_CanvasEdgePrs::rtti() const
558 {
559   return SUPERVGUI_Canvas::Rtti_LinkEdge;
560 }
561
562 void SUPERVGUI_CanvasEdgePrs::setFromPoint(SUPERVGUI_CanvasPointPrs* thePoint)
563 {
564   myStartPoint = thePoint;
565   setPoints((int)(thePoint->x()), (int)(thePoint->y()), endPoint().x(), endPoint().y());
566 }
567
568 void SUPERVGUI_CanvasEdgePrs::setToPoint(SUPERVGUI_CanvasPointPrs* thePoint)
569 {
570   myEndPoint = thePoint;
571   setPoints(startPoint().x(), startPoint().y(), (int)(thePoint->x()), (int)(thePoint->y()));
572 }
573
574 void SUPERVGUI_CanvasEdgePrs::setColor(const QColor& theColor)
575 {
576   setPen(QPen(theColor, LINE_WIDTH));
577 }
578
579 void SUPERVGUI_CanvasEdgePrs::moveBy(double dx, double dy)
580 {
581   //mkr: for moving segment of link
582   if (myStartPoint && myEndPoint) {
583     myStartPoint->setMoving(true);
584     myStartPoint->moveBy(dx, dy);
585     
586     myEndPoint->setMoving(true);
587     myEndPoint->moveBy(dx,dy);
588   }
589 }
590