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);
410 double gap = marginConn;
411 if ((orientationFrom == Parameters::North)||(orientationFrom == Parameters::West)) gap = -gap;
414 if ((orientationFrom == Parameters::East)||(orientationFrom == Parameters::West)) {
415 // must draw a complete esse
416 p = QPointF(pointFrom.x()+gap,pointFrom.y());
418 interPoints.append(p);
419 p = QPointF(pointFrom.x()+gap,(pointFrom.y()+pointTo.y())/2.0);
421 interPoints.append(p);
422 p = QPointF(pointTo.x()-gap,(pointFrom.y()+pointTo.y())/2.0);
424 interPoints.append(p);
425 p = QPointF(pointTo.x()-gap,pointTo.y());
427 interPoints.append(p);
428 pathPaint.lineTo(pointTo);
430 else if ((orientationFrom == Parameters::South)||(orientationFrom == Parameters::North)) {
432 // must draw a complete esse
433 p = QPointF(pointFrom.x(),pointFrom.y()+gap);
435 interPoints.append(p);
436 p = QPointF((pointFrom.x()+pointTo.x())/2.0,pointFrom.y()+gap);
438 interPoints.append(p);
439 p = QPointF((pointFrom.x()+pointTo.x())/2.0,pointTo.y()-gap);
441 interPoints.append(p);
442 p = QPointF(pointTo.x(), pointTo.y()-gap);
444 interPoints.append(p);
445 pathPaint.lineTo(pointTo);
449 void ConnectionItem::computeStaircase(int orientationFrom) {
451 pathPaint = QPainterPath(pointFrom);
455 if ((orientationFrom == Parameters::East)||(orientationFrom == Parameters::West)) {
456 if (pointFrom.y() == pointTo.y()) {
457 //cout << "drawing straight line" << endl;
458 pathPaint.lineTo(pointTo);
461 //cout << "drawing a staircase" << endl;
462 // sufficient place to draw a simple staircase
463 p = QPointF((pointFrom.x()+pointTo.x())/2.0,pointFrom.y());
465 interPoints.append(p);
466 p = QPointF((pointFrom.x()+pointTo.x())/2.0,pointTo.y());
468 interPoints.append(p);
469 pathPaint.lineTo(pointTo);
472 else if ((orientationFrom == Parameters::South)||(orientationFrom == Parameters::North)) {
473 if (pointFrom.x() == pointTo.x()) {
474 //cout << "drawing straight line" << endl;
475 pathPaint.lineTo(pointTo);
478 //cout << "drawing a staircase" << endl;
479 // sufficient place to draw a simple staircase
480 p = QPointF(pointFrom.x(),(pointFrom.y()+pointTo.y())/2.0);
482 interPoints.append(p);
483 p = QPointF(pointTo.x(),(pointFrom.y()+pointTo.y())/2.0);
485 interPoints.append(p);
486 pathPaint.lineTo(pointTo);
493 A Corner has the following shape :
498 void ConnectionItem::computeCorner(int orientationFrom) {
500 pathPaint = QPainterPath(pointFrom);
503 //cout << "drawing a corner" << endl;
505 if ((orientationFrom == Parameters::East)||(orientationFrom == Parameters::West)) {
506 p = QPointF(pointTo.x(),pointFrom.y());
508 interPoints.append(p);
509 pathPaint.lineTo(pointTo);
511 else if ((orientationFrom == Parameters::South)||(orientationFrom == Parameters::North)) {
512 p = QPointF(pointFrom.x(),pointTo.y());
514 interPoints.append(p);
515 pathPaint.lineTo(pointTo);
521 A OpenRect has the following shape :
526 void ConnectionItem::computeOpenRect(int orientationFrom, int orientationTo) {
527 pathPaint = QPainterPath(pointFrom);
530 double gap1 = marginConn;
531 double gap2 = marginConn;
532 //cout << "drawing an OpenRect" << endl;
534 if ((orientationFrom == Parameters::East)||(orientationFrom == Parameters::West)) {
535 if (orientationFrom == Parameters::West) {
538 if (orientationTo == Parameters::North) {
541 p = QPointF(pointFrom.x()+gap1,pointFrom.y());
543 interPoints.append(p);
544 p = QPointF(pointFrom.x()+gap1,pointTo.y()+gap2);
546 interPoints.append(p);
547 p = QPointF(pointTo.x(),pointTo.y()+gap2);
549 interPoints.append(p);
550 pathPaint.lineTo(pointTo);
553 else if ((orientationFrom == Parameters::South)||(orientationFrom == Parameters::North)) {
554 if (orientationFrom == Parameters::North) {
557 if (orientationTo == Parameters::West) {
560 p = QPointF(pointFrom.x(),pointFrom.y()+gap1);
562 interPoints.append(p);
563 p = QPointF(pointTo.x()+gap2,pointFrom.y()+gap1);
565 interPoints.append(p);
566 p = QPointF(pointTo.x()+gap2,pointTo.y());
568 interPoints.append(p);
569 pathPaint.lineTo(pointTo);
573 /* drawHookSmallEnd():
575 A Hook has the following shape :
579 Its end has always a size of marginConn
581 void ConnectionItem::computeHookSmallEnd(int orientationFrom, int orientationTo) {
582 pathPaint = QPainterPath(pointFrom);
585 double gap = marginConn;
586 //cout << "drawing a Hook with small end" << endl;
588 if ((orientationFrom == Parameters::East)||(orientationFrom == Parameters::West)) {
590 if (orientationTo == Parameters::North) gap = -gap;
592 p = QPointF((pointFrom.x()+pointTo.x())/2.0,pointFrom.y());
594 interPoints.append(p);
595 p = QPointF((pointFrom.x()+pointTo.x())/2.0,pointTo.y()+gap);
597 interPoints.append(p);
598 p = QPointF(pointTo.x(),pointTo.y()+gap);
600 interPoints.append(p);
601 pathPaint.lineTo(pointTo);
604 else if ((orientationFrom == Parameters::South)||(orientationFrom == Parameters::North)) {
606 if (orientationTo == Parameters::West) gap = -gap;
608 p = QPointF(pointFrom.x(),(pointFrom.y()+pointTo.y())/2.0);
610 interPoints.append(p);
611 p = QPointF(pointTo.x()+gap,(pointFrom.y()+pointTo.y())/2.0);
613 interPoints.append(p);
614 p = QPointF(pointTo.x()+gap,pointTo.y());
616 interPoints.append(p);
617 pathPaint.lineTo(pointTo);
621 /* drawHookSmallStart():
623 A Hook has the following shape :
627 Its start has always a size of marginConn
629 void ConnectionItem::computeHookSmallStart(int orientationFrom, int orientationTo) {
630 pathPaint = QPainterPath(pointFrom);
633 double gap = marginConn;
634 //cout << "drawing a Hook with small start" << endl;
636 if ((orientationFrom == Parameters::East)||(orientationFrom == Parameters::West)) {
638 if (orientationFrom == Parameters::West) gap = -gap;
640 p = QPointF(pointFrom.x()+gap,pointFrom.y());
642 interPoints.append(p);
643 p = QPointF(pointFrom.x()+gap,(pointFrom.y()+pointTo.y())/2.0);
645 interPoints.append(p);
646 p = QPointF(pointTo.x(),(pointFrom.y()+pointTo.y())/2.0);
648 interPoints.append(p);
649 pathPaint.lineTo(pointTo);
651 else if ((orientationFrom == Parameters::South)||(orientationFrom == Parameters::North)) {
653 if (orientationFrom == Parameters::North) gap = -gap;
655 p = QPointF(pointFrom.x(),pointFrom.y()+gap);
657 interPoints.append(p);
658 p = QPointF((pointFrom.x()+pointTo.x())/2.0,pointFrom.y()+gap);
660 interPoints.append(p);
661 p = QPointF((pointFrom.x()+pointTo.x())/2.0,pointTo.y());
663 interPoints.append(p);
664 pathPaint.lineTo(pointTo);
670 An Elle has the following shape :
675 void ConnectionItem::computeElle(int orientationFrom) {
677 pathPaint = QPainterPath(pointFrom);
682 switch(orientationFrom){
683 case Parameters::North :
684 if(pointFrom.y() < pointTo.y()) {
685 y = pointFrom.y()-marginConn;
688 y = pointTo.y()-marginConn;
690 p = QPointF(pointFrom.x(),y);
692 interPoints.append(p);
693 p = QPointF(pointTo.x(),y);
695 interPoints.append(p);
696 pathPaint.lineTo(pointTo);
698 case Parameters::South :
699 if(pointFrom.y() > pointTo.y()) {
700 y = pointFrom.y()+marginConn;
703 y = pointTo.y()+marginConn;
705 p = QPointF(pointFrom.x(),y);
707 interPoints.append(p);
708 p = QPointF(pointTo.x(),y);
710 interPoints.append(p);
711 pathPaint.lineTo(pointTo);
713 case Parameters::West :
714 if(pointFrom.x() < pointTo.x()) {
715 x = pointFrom.x()-marginConn;
718 x = pointTo.x()-marginConn;
720 p = QPointF(x, pointFrom.y());
722 interPoints.append(p);
723 p = QPointF(x, pointTo.y());
725 interPoints.append(p);
726 pathPaint.lineTo(pointTo);
728 case Parameters::East :
729 if(pointFrom.x() > pointTo.x()) {
730 x = pointFrom.x()+marginConn;
733 x = pointTo.x()+marginConn;
735 p = QPointF(x, pointFrom.y());
737 interPoints.append(p);
738 p = QPointF(x, pointTo.y());
740 interPoints.append(p);
741 pathPaint.lineTo(pointTo);
746 void ConnectionItem::setSelected(bool selected) {
747 this->selected = selected;
755 void ConnectionItem::mousePressEvent(QGraphicsSceneMouseEvent *event) {
756 QGraphicsItem::mousePressEvent(event);
757 setZValue(zValue()+100);
758 setSelected(!selected);
759 update(boundingRect());
762 void ConnectionItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
763 QGraphicsItem::mouseReleaseEvent(event);
764 setZValue(zValue()-100);
767 void ConnectionItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
768 QGraphicsItem::mouseMoveEvent(event);
771 void ConnectionItem::contextMenuEvent(QGraphicsSceneContextMenuEvent * event) {
772 /* have to check if the connection can be removed.
773 If the from or to InterfaceItem is owned by a group item, and this item
774 is both connected to and from, thus it is impossible to remove this connection
776 bool canRemove = true;
777 InterfaceItem* groupIfaceItem = NULL;
778 if (fromInterfaceItem->getOwner()->isGroupItem()) {
779 groupIfaceItem = fromInterfaceItem;
781 else if (toInterfaceItem->getOwner()->isGroupItem()) {
782 groupIfaceItem = toInterfaceItem;
785 if (groupIfaceItem != NULL) {
786 ConnectedInterface* ref = groupIfaceItem->refInter;
787 if ((ref->isConnectedFrom()) && (ref->isConnectedTo())) {
794 QAction* titleAction = menu.addAction("Connection operations");
795 titleAction->setEnabled(false);
797 QAction* removeAction = menu.addAction("Remove");
798 QAction * selectedAction= menu.exec(event->screenPos());
800 if(selectedAction == removeAction){
801 dispatcher->removeConnection(this);
806 void ConnectionItem::prepareChange() {
807 prepareGeometryChange();
810 QDataStream &operator <<(QDataStream &out, ConnectionItem &c) {
811 out.setVersion(QDataStream::Qt_4_8);
814 QDataStream toWrite(&connData, QIODevice::WriteOnly);
817 toWrite << c.getFromInterfaceItem()->getId();
818 toWrite << c.getToInterfaceItem()->getId();
825 QDataStream &operator >>(QDataStream &in, ConnectionItem &c) {
826 in.setVersion(QDataStream::Qt_4_8);