1 #include "ConnectionItem.h"
3 #include "Dispatcher.h"
4 #include "Parameters.h"
5 #include "AbstractBoxItem.h"
6 #include "ConnectedInterface.h"
7 #include "InterfaceItem.h"
8 #include "AbstractBlock.h"
10 //int ConnectionItem::counter = 0;
12 ConnectionItem::ConnectionItem(InterfaceItem* _iface1,
13 InterfaceItem* _iface2,
14 Dispatcher* _dispatcher,
15 Parameters* _params) : QGraphicsItem() {
18 dispatcher = _dispatcher;
21 ConnectedInterface* ref1 = _iface1->refInter;
22 ConnectedInterface* ref2 = _iface2->refInter;
24 case 1 : ref1 is group interface, and ref2 block interface of a block within the group
25 case 2 : the opposite of case 1
26 case 3 : ref1 and ref2 are block interface of blocks that are both within the same parent group.
27 case 4 : ref1 is source interface and ref2 interface of top group
28 case 5 : the opposite of case 4
30 if (ref1->getOwner() == ref2->getOwner()->getParent()) {
32 if (ref1->getDirection() == AbstractInterface::Input) {
33 fromInterfaceItem = _iface1;
34 toInterfaceItem = _iface2;
36 else if (ref1->getDirection() == AbstractInterface::InOut) {
37 fromInterfaceItem = _iface1;
38 toInterfaceItem = _iface2;
40 else if (ref1->getDirection() == AbstractInterface::Output) {
41 toInterfaceItem = _iface1;
42 fromInterfaceItem = _iface2;
45 else if (ref1->getOwner()->getParent() == ref2->getOwner()) {
47 if (ref1->getDirection() == AbstractInterface::Input) {
48 fromInterfaceItem = _iface2;
49 toInterfaceItem = _iface1;
51 else if (ref1->getDirection() == AbstractInterface::InOut) {
52 fromInterfaceItem = _iface2;
53 toInterfaceItem = _iface1;
55 else if (ref1->getDirection() == AbstractInterface::Output) {
56 toInterfaceItem = _iface2;
57 fromInterfaceItem = _iface1;
60 // NB : this case is in fact similar to the previous. Kept here for clarity
61 else if (ref1->getOwner()->getParent() == ref2->getOwner()->getParent()) {
63 if (ref1->getDirection() == AbstractInterface::Input) {
64 fromInterfaceItem = _iface2;
65 toInterfaceItem = _iface1;
67 else if (ref1->getDirection() == AbstractInterface::InOut) {
68 fromInterfaceItem = _iface2;
69 toInterfaceItem = _iface1;
71 else if (ref1->getDirection() == AbstractInterface::Output) {
72 toInterfaceItem = _iface2;
73 fromInterfaceItem = _iface1;
76 else if ((ref1->getOwner()->isSourceBlock()) && (ref2->getOwner()->isTopGroupBlock())) {
77 fromInterfaceItem = _iface1;
78 toInterfaceItem = _iface2;
80 else if ((ref2->getOwner()->isSourceBlock()) && (ref1->getOwner()->isTopGroupBlock())) {
81 fromInterfaceItem = _iface2;
82 toInterfaceItem = _iface1;
84 // adding this to interface items
85 fromInterfaceItem->addConnectionItem(this);
86 toInterfaceItem->addConnectionItem(this);
89 marginConn = params->arrowLineLength+params->arrowWidth;
91 setFlag(ItemIsSelectable);
92 setAcceptHoverEvents(true);
93 setFlag(ItemSendsGeometryChanges);
94 setCursor(Qt::PointingHandCursor);
97 if (fromInterfaceItem->refInter->getPurpose() == AbstractInterface::Data) {
108 ConnectionItem::ConnectionItem(const ConnectionItem ©) {
109 pointFrom = copy.pointFrom;
110 pointTo = copy.pointTo;
111 interPoint1 = copy.interPoint1;
112 interPoint2 = copy.interPoint2;
113 interPoint3 = copy.interPoint3;
114 interPoint4 = copy.interPoint4;
117 ConnectionItem::~ConnectionItem() {
120 ConnectionItem::ConnectionItem() {
123 QPainterPath ConnectionItem::shape() const {
127 QRectF ConnectionItem::boundingRect() const {
131 if(pointFrom.x() < pointTo.x()){
132 start.setX(pointFrom.x()-20);
133 end.setX(pointTo.x()+20);
135 start.setX(pointTo.x()-20);
136 end.setX(pointFrom.x()+20);
138 if(pointFrom.y() < pointTo.y()){
139 start.setY(pointFrom.y()-20);
140 end.setY(pointTo.y()+20);
142 start.setY(pointTo.y()-20);
143 end.setY(pointFrom.y()+20);
145 return QRectF(start, end);
148 void ConnectionItem::paint(QPainter *painter,
149 const QStyleOptionGraphicsItem *option,
152 if (!visible) return;
154 painter->setPen(Qt::blue);
156 painter->setPen(Qt::red);
159 painter->drawPath(pathPaint);
162 void ConnectionItem::addInterPoint(QPointF point) {
166 void ConnectionItem::setPath() {
168 // signals to the scene that this connection is going to change of shape.
169 prepareGeometryChange();
171 bool withinGroup = false;
173 1: from group input iface to box input iface
174 2: from output box iface to group output iface
175 3: from output box iface to input box iface
176 4: from source output iface to input group iface
178 For cases 1 & 2, the position of group iface is given by getStartPosition
179 For all other cases, the iface from and to position is given by getEndPosition
181 if ((fromInterfaceItem->getOwner()->isGroupItem()) && (toInterfaceItem->getOwner()->isBoxItem())) {
182 pointFrom = fromInterfaceItem->getStartPosition();
183 pointTo = toInterfaceItem->getEndPosition();
186 else if ((toInterfaceItem->getOwner()->isGroupItem()) && (fromInterfaceItem->getOwner()->isBoxItem())) {
187 pointFrom = fromInterfaceItem->getEndPosition();
188 pointTo = toInterfaceItem->getStartPosition();
192 pointFrom = fromInterfaceItem->getEndPosition();
193 pointTo = toInterfaceItem->getEndPosition();
197 oriFrom = fromInterfaceItem->getOrientation();
198 oriTo = toInterfaceItem->getOrientation();
200 /* NB: if src or dest is onwed by a GroupItem the orientation
201 must be changed as it is a block.
204 if(fromInterfaceItem->owner->isGroupItem()){
205 switch(fromInterfaceItem->getOrientation()){
206 case Parameters::North :
207 oriFrom = Parameters::South;
209 case Parameters::South :
210 oriFrom = Parameters::North;
212 case Parameters::East :
213 oriFrom = Parameters::West;
215 case Parameters::West :
216 oriFrom = Parameters::East;
220 else if(toInterfaceItem->owner->isGroupItem()){
221 switch(toInterfaceItem->getOrientation()){
222 case Parameters::North :
223 oriTo = Parameters::South;
225 case Parameters::South :
226 oriTo = Parameters::North;
228 case Parameters::East :
229 oriTo = Parameters::West;
231 case Parameters::West :
232 oriTo = Parameters::East;
240 if(oriFrom == Parameters::South) {
242 // FROM SOUTH TO SOUTH
243 if(oriTo == Parameters::South) {
244 computeElle(oriFrom);
246 // FROM SOUTH TO NORTH
247 else if(oriTo == Parameters::North) {
248 gap1 = pointTo.y() - pointFrom.y();
249 if (gap1 > 2*marginConn) {
250 computeStaircase(oriFrom);
253 computeEsse(oriFrom);
256 // FROM SOUTH TO EAST OR WEST
257 else if ((oriTo == Parameters::East) || (oriTo == Parameters::West)){
259 gap1 = pointTo.x() - pointFrom.x();
260 if (oriTo == Parameters::West) gap1 = -gap1;
261 gap2 = pointTo.y() - pointFrom.y();
265 computeHookSmallEnd(oriFrom,oriTo);
268 computeOpenRect(oriFrom,oriTo);
273 computeCorner(oriFrom);
276 computeHookSmallStart(oriFrom,oriTo);
281 else if(oriFrom == Parameters::North) {
283 // FROM NORTH TO SOUTH
284 if(oriTo == Parameters::South) {
285 gap1 = pointFrom.y() - pointTo.y();
286 if (gap1 > 2*marginConn) {
287 computeStaircase(oriFrom);
290 computeEsse(oriFrom);
293 // FROM NORTH TO NORTH
294 else if(oriTo == Parameters::North) {
295 computeElle(oriFrom);
297 // FROM NORTH TO EAST OR WEST
298 else if ((oriTo == Parameters::East) || (oriTo == Parameters::West)){
300 gap1 = pointTo.x() - pointFrom.x();
301 if (oriTo == Parameters::West) gap1 = -gap1;
302 gap2 = pointFrom.y() - pointTo.y();
306 computeHookSmallEnd(oriFrom,oriTo);
309 computeOpenRect(oriFrom,oriTo);
314 computeCorner(oriFrom);
317 computeHookSmallStart(oriFrom,oriTo);
322 else if(oriFrom == Parameters::East) {
323 // FROM EAST TO NORTH OR SOUTH
324 if ((oriTo == Parameters::South) || (oriTo == Parameters::North)){
326 gap1 = pointFrom.x() - pointTo.x();
327 gap2 = pointFrom.y() - pointTo.y();
328 if (oriTo == Parameters::North) gap2 = -gap2;
332 computeHookSmallStart(oriFrom,oriTo);
335 computeOpenRect(oriFrom,oriTo);
340 computeCorner(oriFrom);
343 computeHookSmallEnd(oriFrom,oriTo);
347 else if(oriTo == Parameters::East) {
348 computeElle(oriFrom);
350 else if (oriTo == Parameters::West) {
351 gap1 = pointTo.x() - pointFrom.x();
352 if (gap1 > 2*marginConn) {
353 computeStaircase(oriFrom);
356 computeEsse(oriFrom);
360 else if (oriFrom == Parameters::West) {
362 // FROM WEST TO NORTH OR SOUTH
363 if ((oriTo == Parameters::South) || (oriTo == Parameters::North)){
365 gap1 = pointTo.x() - pointFrom.x();
366 gap2 = pointFrom.y() - pointTo.y();
367 if (oriTo == Parameters::North) gap2 = -gap2;
371 computeHookSmallStart(oriFrom,oriTo);
374 computeOpenRect(oriFrom,oriTo);
379 computeCorner(oriFrom);
382 computeHookSmallEnd(oriFrom,oriTo);
386 else if(oriTo == Parameters::East) {
387 gap1 = pointFrom.x() - pointTo.x();
388 if (gap1 > 2*marginConn) {
389 computeStaircase(oriFrom);
392 computeEsse(oriFrom);
395 else if (oriTo == Parameters::West) {
396 computeElle(oriFrom);
401 //pathShape = pps.createStroke(pathPaint);
405 void ConnectionItem::computeEsse(int orientationFrom) {
407 //cout << "drawing an esse" << endl;
408 pathPaint = QPainterPath(pointFrom);
411 double gap = marginConn;
413 if ((orientationFrom == Parameters::North)||(orientationFrom == Parameters::West)) gap = -gap;
416 if ((orientationFrom == Parameters::East)||(orientationFrom == Parameters::West)) {
418 // must draw a complete esse
419 p = QPointF(pointFrom.x()+gap,pointFrom.y());
422 interPoints.append(p);
423 p = QPointF(pointFrom.x()+gap,(pointFrom.y()+pointTo.y())/2.0);
426 interPoints.append(p);
427 p = QPointF(pointTo.x()-gap,(pointFrom.y()+pointTo.y())/2.0);
430 interPoints.append(p);
431 p = QPointF(pointTo.x()-gap,pointTo.y());
434 interPoints.append(p);
435 pathPaint.lineTo(pointTo);
437 else if ((orientationFrom == Parameters::South)||(orientationFrom == Parameters::North)) {
439 // must draw a complete esse
440 p = QPointF(pointFrom.x(),pointFrom.y()+gap);
443 interPoints.append(p);
444 p = QPointF((pointFrom.x()+pointTo.x())/2.0,pointFrom.y()+gap);
447 interPoints.append(p);
448 p = QPointF((pointFrom.x()+pointTo.x())/2.0,pointTo.y()-gap);
451 interPoints.append(p);
452 p = QPointF(pointTo.x(), pointTo.y()-gap);
455 interPoints.append(p);
456 pathPaint.lineTo(pointTo);
459 pathShape = pps.createStroke(s);
462 void ConnectionItem::computeStaircase(int orientationFrom) {
464 pathPaint = QPainterPath(pointFrom);
466 double gap = marginConn;
470 if ((orientationFrom == Parameters::East)||(orientationFrom == Parameters::West)) {
472 if (orientationFrom == Parameters::West) gap = -gap;
473 p = QPointF(pointFrom.x()+gap,pointFrom.y());
476 if (pointFrom.y() == pointTo.y()) {
477 //cout << "drawing straight line" << endl;
478 pathPaint.lineTo(pointTo);
482 //cout << "drawing a staircase" << endl;
483 // sufficient place to draw a simple staircase
484 p = QPointF((pointFrom.x()+pointTo.x())/2.0,pointFrom.y());
487 interPoints.append(p);
488 p = QPointF((pointFrom.x()+pointTo.x())/2.0,pointTo.y());
491 interPoints.append(p);
492 pathPaint.lineTo(pointTo);
494 p = QPointF(pointTo.x()-gap,pointTo.y());
497 else if ((orientationFrom == Parameters::South)||(orientationFrom == Parameters::North)) {
499 if (orientationFrom == Parameters::North) gap = -gap;
501 p = QPointF(pointFrom.x(),pointFrom.y()+gap);
504 if (pointFrom.x() == pointTo.x()) {
505 //cout << "drawing straight line" << endl;
506 pathPaint.lineTo(pointTo);
509 //cout << "drawing a staircase" << endl;
510 // sufficient place to draw a simple staircase
511 p = QPointF(pointFrom.x(),(pointFrom.y()+pointTo.y())/2.0);
514 interPoints.append(p);
515 p = QPointF(pointTo.x(),(pointFrom.y()+pointTo.y())/2.0);
518 interPoints.append(p);
519 pathPaint.lineTo(pointTo);
521 p = QPointF(pointTo.x(),pointTo.y()-gap);
525 pathShape = pps.createStroke(s);
530 A Corner has the following shape :
535 void ConnectionItem::computeCorner(int orientationFrom) {
537 pathPaint = QPainterPath(pointFrom);
541 double gap = marginConn;
543 //cout << "drawing a corner" << endl;
545 if ((orientationFrom == Parameters::East)||(orientationFrom == Parameters::West)) {
546 if (orientationFrom == Parameters::West) gap = -gap;
547 p = QPointF(pointFrom.x()+gap,pointFrom.y());
549 p = QPointF(pointTo.x(),pointFrom.y());
552 interPoints.append(p);
553 pathPaint.lineTo(pointTo);
554 p = QPointF(pointTo.x(),pointTo.y()-gap);
557 else if ((orientationFrom == Parameters::South)||(orientationFrom == Parameters::North)) {
558 if (orientationFrom == Parameters::North) gap = -gap;
559 p = QPointF(pointFrom.x(),pointFrom.y()+gap);
561 p = QPointF(pointFrom.x(),pointTo.y());
564 interPoints.append(p);
565 pathPaint.lineTo(pointTo);
566 p = QPointF(pointTo.x()-gap,pointTo.y());
570 pathShape = pps.createStroke(s);
575 A OpenRect has the following shape :
580 Its beginning and end have always a size of marginConn
582 void ConnectionItem::computeOpenRect(int orientationFrom, int orientationTo) {
583 pathPaint = QPainterPath(pointFrom);
586 double gap1 = marginConn;
587 double gap2 = marginConn;
589 //cout << "drawing an OpenRect" << endl;
591 if ((orientationFrom == Parameters::East)||(orientationFrom == Parameters::West)) {
592 if (orientationFrom == Parameters::West) {
595 if (orientationTo == Parameters::North) {
598 p = QPointF(pointFrom.x()+gap1,pointFrom.y());
601 interPoints.append(p);
602 p = QPointF(pointFrom.x()+gap1,pointTo.y()+gap2);
605 interPoints.append(p);
606 p = QPointF(pointTo.x(),pointTo.y()+gap2);
609 interPoints.append(p);
610 pathPaint.lineTo(pointTo);
613 else if ((orientationFrom == Parameters::South)||(orientationFrom == Parameters::North)) {
614 if (orientationFrom == Parameters::North) {
617 if (orientationTo == Parameters::West) {
620 p = QPointF(pointFrom.x(),pointFrom.y()+gap1);
623 interPoints.append(p);
624 p = QPointF(pointTo.x()+gap2,pointFrom.y()+gap1);
627 interPoints.append(p);
628 p = QPointF(pointTo.x()+gap2,pointTo.y());
631 interPoints.append(p);
632 pathPaint.lineTo(pointTo);
635 pathShape = pps.createStroke(s);
639 /* drawHookSmallEnd():
641 A Hook has the following shape :
645 Its end has always a size of marginConn
647 void ConnectionItem::computeHookSmallEnd(int orientationFrom, int orientationTo) {
648 pathPaint = QPainterPath(pointFrom);
652 double gap2 = marginConn;
653 double gap1 = marginConn;
654 //cout << "drawing a Hook with small end" << endl;
656 if ((orientationFrom == Parameters::East)||(orientationFrom == Parameters::West)) {
658 if (orientationFrom == Parameters::West) gap1 = -gap1;
659 if (orientationTo == Parameters::North) gap2 = -gap2;
661 p = QPointF(pointFrom.x()+gap1,pointFrom.y());
663 p = QPointF((pointFrom.x()+pointTo.x())/2.0,pointFrom.y());
666 interPoints.append(p);
667 p = QPointF((pointFrom.x()+pointTo.x())/2.0,pointTo.y()+gap2);
670 interPoints.append(p);
671 p = QPointF(pointTo.x(),pointTo.y()+gap2);
674 interPoints.append(p);
675 pathPaint.lineTo(pointTo);
678 else if ((orientationFrom == Parameters::South)||(orientationFrom == Parameters::North)) {
680 if (orientationFrom == Parameters::North) gap1 = -gap1;
681 if (orientationTo == Parameters::West) gap2 = -gap2;
683 p = QPointF(pointFrom.x(),pointFrom.y()+gap1);
685 p = QPointF(pointFrom.x(),(pointFrom.y()+pointTo.y())/2.0);
688 interPoints.append(p);
689 p = QPointF(pointTo.x()+gap2,(pointFrom.y()+pointTo.y())/2.0);
692 interPoints.append(p);
693 p = QPointF(pointTo.x()+gap2,pointTo.y());
696 interPoints.append(p);
697 pathPaint.lineTo(pointTo);
700 pathShape = pps.createStroke(s);
703 /* drawHookSmallStart():
705 A Hook has the following shape :
709 Its start has always a size of marginConn
711 void ConnectionItem::computeHookSmallStart(int orientationFrom, int orientationTo) {
712 pathPaint = QPainterPath(pointFrom);
716 double gap1 = marginConn;
717 double gap2 = marginConn;
718 //cout << "drawing a Hook with small start" << endl;
720 if ((orientationFrom == Parameters::East)||(orientationFrom == Parameters::West)) {
722 if (orientationFrom == Parameters::West) gap1 = -gap1;
723 if (orientationTo == Parameters::North) gap2 = -gap2;
725 p = QPointF(pointFrom.x()+gap1,pointFrom.y());
728 interPoints.append(p);
729 p = QPointF(pointFrom.x()+gap1,(pointFrom.y()+pointTo.y())/2.0);
732 interPoints.append(p);
733 p = QPointF(pointTo.x(),(pointFrom.y()+pointTo.y())/2.0);
736 interPoints.append(p);
737 pathPaint.lineTo(pointTo);
738 p = QPointF(pointTo.x(),pointFrom.y()+gap2);
741 else if ((orientationFrom == Parameters::South)||(orientationFrom == Parameters::North)) {
743 if (orientationFrom == Parameters::North) gap1 = -gap1;
744 if (orientationTo == Parameters::West) gap2 = -gap2;
746 p = QPointF(pointFrom.x(),pointFrom.y()+gap1);
749 interPoints.append(p);
750 p = QPointF((pointFrom.x()+pointTo.x())/2.0,pointFrom.y()+gap1);
753 interPoints.append(p);
754 p = QPointF((pointFrom.x()+pointTo.x())/2.0,pointTo.y());
757 interPoints.append(p);
758 pathPaint.lineTo(pointTo);
759 p = QPointF(pointTo.x()+gap2,pointFrom.y());
763 pathShape = pps.createStroke(s);
768 An Elle has the following shape :
773 void ConnectionItem::computeElle(int orientationFrom) {
775 pathPaint = QPainterPath(pointFrom);
779 double gap = marginConn;
783 if ((orientationFrom == Parameters::North) || (orientationFrom == Parameters::South)) {
784 double diffPos = pointFrom.y() - pointTo.y();
785 if (orientationFrom == Parameters::North) {
789 p = QPointF(pointFrom.x(),pointFrom.y()+gap);
791 if (diffPos >= 0.0) {
793 interPoints.append(p);
794 p = QPointF(pointTo.x(),pointFrom.y()+gap);
797 interPoints.append(p);
798 pathPaint.lineTo(pointTo);
799 p = QPointF(pointTo.x(),pointTo.y()+gap);
803 p = QPointF(pointFrom.x(),pointTo.y()+gap);
806 interPoints.append(p);
807 p = QPointF(pointTo.x(),pointTo.y()+gap);
810 interPoints.append(p);
811 pathPaint.lineTo(pointTo);
814 else if ((orientationFrom == Parameters::West) || (orientationFrom == Parameters::East)) {
815 double diffPos = pointFrom.x() - pointTo.x();
816 if (orientationFrom == Parameters::West) {
820 p = QPointF(pointFrom.x()+gap,pointFrom.y());
822 if (diffPos >= 0.0) {
824 interPoints.append(p);
825 p = QPointF(pointTo.x()+gap,pointFrom.y());
828 interPoints.append(p);
829 pathPaint.lineTo(pointTo);
830 p = QPointF(pointTo.x()+gap,pointTo.y());
834 p = QPointF(pointFrom.x()+gap,pointTo.y());
837 interPoints.append(p);
838 p = QPointF(pointTo.x()+gap,pointTo.y());
841 interPoints.append(p);
842 pathPaint.lineTo(pointTo);
847 pathShape = pps.createStroke(s);
850 void ConnectionItem::setSelected(bool selected) {
851 this->selected = selected;
859 void ConnectionItem::mousePressEvent(QGraphicsSceneMouseEvent *event) {
860 QGraphicsItem::mousePressEvent(event);
861 setZValue(zValue()+100);
862 setSelected(!selected);
863 update(boundingRect());
866 void ConnectionItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
867 QGraphicsItem::mouseReleaseEvent(event);
868 setZValue(zValue()-100);
871 void ConnectionItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
872 QGraphicsItem::mouseMoveEvent(event);
875 void ConnectionItem::contextMenuEvent(QGraphicsSceneContextMenuEvent * event) {
876 /* have to check if the connection can be removed.
877 If the from or to InterfaceItem is owned by a group item, and this item
878 is both connected to and from, thus it is impossible to remove this connection
880 bool canRemove = true;
881 InterfaceItem* groupIfaceItem = NULL;
882 if (fromInterfaceItem->getOwner()->isGroupItem()) {
883 groupIfaceItem = fromInterfaceItem;
885 else if (toInterfaceItem->getOwner()->isGroupItem()) {
886 groupIfaceItem = toInterfaceItem;
889 if (groupIfaceItem != NULL) {
890 ConnectedInterface* ref = groupIfaceItem->refInter;
891 if ((ref->isConnectedFrom()) && (ref->isConnectedTo())) {
898 QAction* titleAction = menu.addAction("Connection operations");
899 titleAction->setEnabled(false);
901 QAction* removeAction = menu.addAction("Remove");
902 QAction * selectedAction= menu.exec(event->screenPos());
904 if(selectedAction == removeAction){
905 dispatcher->removeConnection(this);
910 void ConnectionItem::prepareChange() {
911 prepareGeometryChange();
914 QDataStream &operator <<(QDataStream &out, ConnectionItem &c) {
915 out.setVersion(QDataStream::Qt_4_8);
918 QDataStream toWrite(&connData, QIODevice::WriteOnly);
921 toWrite << c.getFromInterfaceItem()->getId();
922 toWrite << c.getToInterfaceItem()->getId();
929 QDataStream &operator >>(QDataStream &in, ConnectionItem &c) {
930 in.setVersion(QDataStream::Qt_4_8);