nodeeditor_doxy
src/Impl/nodeconnection.cpp
Go to the documentation of this file.
00001 #include <QtGui>
00002 
00003 #include "nodeconnection.h"
00004 #include "nodeconnector.h"
00005 #include <math.h>
00006 
00007 const qreal Pi = 3.14;
00008 
00009 NodeConnection::~NodeConnection(){
00010         if (this->mStartConnector != NULL) {
00011                 this->mStartConnector->removeConnection(this);
00012                 this->mStartConnector = NULL;
00013         }
00014         if (this->mEndConnector != NULL) {
00015                 this->mEndConnector->removeConnection(this);
00016                 this->mEndConnector = NULL;
00017         }
00018         //dw new
00019         if (scene() != NULL) {
00020                 this->scene()->removeItem(this);
00021         }
00022 }
00023 
00025 NodeConnection::NodeConnection(NodeConnector *startConnector, NodeConnector *endConnector,
00026          QGraphicsItem *parent, QGraphicsScene *scene, bool bidirectional)
00027                  : QGraphicsPathItem(parent, scene)
00028 {
00029         //setCacheMode(DeviceCoordinateCache);
00030 
00031 
00032     mStartConnector = startConnector;
00033     mEndConnector = endConnector;
00034     setFlag(QGraphicsItem::ItemIsSelectable, true);
00035 
00036         setBidirectional(bidirectional);
00037 
00038         //line
00039     mColor = Qt::black;
00040         //path
00041         //mColor = Qt::black;
00042     setPen(QPen(mColor, 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
00043         arrowSize=10;
00044 
00045         setZValue(-1000.0);
00046 
00047          //dw new4 already done here, but why used in other places?
00048          /*/if (scene != NULL){
00049                 scene->addItem(this);
00050          }*/
00051 
00052         //dw new4: is this a problem? check it
00053     //setCacheMode(DeviceCoordinateCache);
00054 
00055         QPointF controlPoint1;
00056         QPointF controlPoint2;
00057         recreatePath(controlPoint1, controlPoint2);
00058 }
00060 
00062 QRectF NodeConnection::boundingRect() const
00063 {
00064     
00065         /*//line
00066         qreal extra = (pen().width() + 20) / 2.0;
00067 
00068     return QRectF(line().p1(), QSizeF(line().p2().x() - line().p1().x(),
00069                                       line().p2().y() - line().p1().y()))
00070         .normalized()
00071         .adjusted(-extra, -extra, extra, extra);*/
00072         
00073 
00074         qreal extra = 3;
00075         return QGraphicsPathItem::boundingRect().normalized().adjusted(-extra, -extra, extra, extra);
00076         
00077 }
00079 
00081 QPainterPath NodeConnection::shape() const
00082 {
00083         /*
00084         //line
00085     QPainterPath path = QGraphicsLineItem::shape();
00086     //path.addPolygon(arrowHead);
00087     return path;
00088         */
00089 
00090         //return QGraphicsPathItem::shape();
00091         QPainterPath path = QGraphicsPathItem::shape();
00092     //path.addPolygon(arrowHead);
00093     return path;
00094 }
00095 
00096 void NodeConnection::updatePosition() {
00097         prepareGeometryChange();
00098         update();
00099 }
00100 
00103 //void NodeConnection::recreatePath(QPointF& controlPoint1, QPointF& controlPoint2)
00104 //{
00105 //      //line
00106 //      //QLineF line(mapFromItem(mStartConnector, 0, 0), mapFromItem(mEndConnector, 0, 0));
00107 //    //setLine(line);
00108 //
00109 //      //cubic spline?
00110 //      //QPointF a(mapFromItem(mStartConnector, 0, 0) - QPointF(mStartConnector->mRadius,0));
00111 //      //QPointF b(mapFromItem(mEndConnector, 0, 0) - QPointF(mStartConnector->mRadius,0));
00112 //      QPointF a(mapFromItem(mStartConnector, 0, 0));
00113 //      QPointF b(mapFromItem(mEndConnector, 0, 0));
00114 //      int dir1 = 1;
00115 //      //we just think about the case where the connector is left, so just multiply dir where needed
00116 //      if (mStartConnector->connectorAlignment() == NodeConnector::Right) { // right) {
00117 //              dir1 = -1;
00118 //              //a.setX(mapFromItem(mStartConnector, 0, 0).x() + mStartConnector->mRadius);
00119 //      }
00120 //      int dir2 = 1;
00121 //      if (mEndConnector->connectorAlignment() == NodeConnector::Right) { // right) {
00122 //              dir2 = -1;
00123 //              //b.setX(mapFromItem(mEndConnector, 0, 0).x() + mStartConnector->mRadius);
00124 //      }
00125 //
00126 //      //define spline "mRadius"
00127 //      qreal spline_mRadius = 100.0;
00128 //      //dw new version
00129 //      QPointF l;
00130 //      QPointF r;
00131 //      NodeConnector *ri;
00132 //      NodeConnector *li;
00133 //      bool aIsLeft = true;
00134 //      qreal dist = QLineF(a, b).length();
00135 //      qreal diffx = abs(a.x() - b.x());
00136 //      qreal diffy = abs(a.y() - b.y());
00137 //      //QPointF newL;
00138 //      //QPointF newR;
00139 //      if (a.x() < b.x()) {
00140 //              l = a;
00141 //              r = b;
00142 //              li = mStartConnector;
00143 //              ri = mEndConnector;
00144 //      }
00145 //      else {
00146 //              l = b;
00147 //              r = a;
00148 //              li = mEndConnector;
00149 //              ri = mStartConnector;
00150 //              aIsLeft = false;
00151 //      }
00152 //      /*
00153 //      if (r.x() - l.x() > 5 * abs(r.y()-l.y()) && !li->right && ri->right) {
00154 //              newL = l - QPointF(dist/2.0, dist/2.0);
00155 //              newR = r + QPointF(dist/2.0, -dist/2.0);
00156 //      }
00157 //      else {
00158 //              newL = l + (li->right ? 1.0 : -1.0) * QPointF(dist/2.0, 0);
00159 //              newR = r + (ri->right ? 1.0 : -1.0) * QPointF(dist/2.0, 0);
00160 //      }
00161 //      */
00162 //      
00163 //
00164 //      //QPointF controlPoint1;
00165 //      //QPointF controlPoint2;
00166 //      if (r.x() - l.x() > 5 * diffy && li->connectorAlignment() == NodeConnector::Left && ri->connectorAlignment() == NodeConnector::Right) {
00167 //              controlPoint1 = l - QPointF(dist/4.0 + spline_mRadius , dist/4.0 + spline_mRadius);
00168 //              controlPoint2 = r + QPointF(dist/4.0 + spline_mRadius, -dist/4.0 + spline_mRadius);
00169 //      }
00170 //      else {
00171 //              controlPoint1 = l + (li->connectorAlignment() == NodeConnector::Right ? 1.0 : -1.0) * QPointF(dist/2 + (diffy > spline_mRadius ? spline_mRadius : 0), 0);
00172 //              controlPoint2 = r + (ri->connectorAlignment() == NodeConnector::Right ? 1.0 : -1.0) * QPointF(dist/2 + (diffy > spline_mRadius ? spline_mRadius : 0), 0);
00173 //      }
00174 //      
00175 //
00176 //      //dw new5
00177 //      //dw667: was active
00178 //      QPainterPath p(a);
00179 //      //QPainterPath p = path();
00180 //      if (aIsLeft) {
00181 //              p.cubicTo(controlPoint1, controlPoint2, b);
00182 //      }
00183 //      else {
00184 //              p.cubicTo(controlPoint2, controlPoint1, b);
00185 //      }
00186 //
00187 //
00188 //      /*
00189 //      //if directions are different and wrong direction, use y also
00190 //      qreal diffy1 = 0;
00191 //      qreal diffy2 = 0;
00192 //      //y goes from top to bottom!!!!
00193 //      if (dir1*dir2<0) {
00194 //              if (a.y() < b.y()) {
00195 //                      diffy1 = spline_mRadius;
00196 //                      diffy2 = -spline_mRadius;
00197 //              }
00198 //              else {
00199 //                      diffy1 = -spline_mRadius;
00200 //                      diffy2 = spline_mRadius;
00201 //              }
00202 //      }
00203 //      QPointF h1(a.x()-spline_mRadius*dir1, a.y() + diffy1);
00204 //      QPointF h2(b.x()-spline_mRadius*dir2, b.y() + diffy1);
00205 //      p.cubicTo(h1, h2, b);
00206 //      */
00207 //
00208 //
00209 //      //////////////////////
00210 //      //arrow head
00211 //
00212 //      /*
00213 //      QPointF headStartP = p.pointAtPercent(p.percentAtLength(p.length() - mEndConnector->mRadius - arrowSize));
00214 //      QPointF headEndP = p.pointAtPercent(p.percentAtLength(p.length() - mEndConnector->mRadius));
00215 //      QLineF arrowMiddleLine(headStartP, headEndP);
00216 //      //QLineF normHead = arrowMiddleLine.normalVector();
00217 //      arrowMiddleLine.unitVector();
00218 //      QPointF normHead(arrowMiddleLine.dy(), -arrowMiddleLine.dx());
00219 //      QPointF arrowP1 = headStartP + normHead * 0.4;
00220 //      QPointF arrowP2 = headStartP - normHead * 0.4;
00221 //
00222 //      arrowHead.clear();
00223 //      //dw668
00224 //      arrowHead << headEndP << arrowP1 << arrowP2 /*<< headEndP*//*;
00225 //      p.addPolygon(arrowHead);
00226 //      */
00227 //
00228 //      //createArrows(p);
00229 //
00230 //      //////////////////
00231 //      //dw667: was active
00232 //      this->setPath(p);
00233 //}
00235 
00236 
00237 //new try:
00238 //dw667: DO ONLY CALL FROM PAINT METHOD!!!
00239 void NodeConnection::recreatePath(QPointF& controlPoint1, QPointF& controlPoint2)
00240 {
00241         QPointF a(mapFromItem(mStartConnector, 0, 0));
00242         QPointF b(mapFromItem(mEndConnector, 0, 0));
00243 
00244         qreal dist = QLineF(a, b).length();
00245         qreal diffx = abs(a.x() - b.x());
00246         qreal diffy = abs(a.y() - b.y());
00247 
00248         QPointF left;
00249         QPointF right;
00250         NodeConnector* leftConn;
00251         NodeConnector* rightConn;
00252         if (a.x() < b.x()) {
00253                 left = a;
00254                 leftConn = mStartConnector;
00255                 right = b;
00256                 rightConn = mEndConnector;
00257         }
00258         else {
00259                 left = b;
00260                 leftConn = mEndConnector;
00261                 right = a;
00262                 rightConn = mStartConnector;
00263         }
00264 
00265         QPointF bottom;
00266         QPointF top;
00267         NodeConnector* bottomConn;
00268         NodeConnector* topConn;
00269         if (a.y() < b.y()) {
00270                 top = a;
00271                 topConn = mStartConnector;
00272                 bottom = b;
00273                 bottomConn = mEndConnector;     
00274         }
00275         else {
00276                 top = b;
00277                 topConn = mEndConnector;
00278                 bottom = a;
00279                 bottomConn = mStartConnector;
00280         }
00281 
00282         
00283         controlPoint1 = a;
00284         controlPoint2 = b;
00285         //how much to move control point from start or end point, default as used for simple case
00286         qreal moveX = 0.45 * diffx;
00287         qreal moveY = 0.45 * diffy;
00288 
00289         QSizeF combinedSize(30,30);
00290         if (leftConn->parentItem() != NULL) {
00291                 combinedSize.setWidth(leftConn->parentItem()->boundingRect().width());
00292                 combinedSize.setHeight(leftConn->parentItem()->boundingRect().height());
00293         }
00294         else {
00295                 combinedSize.setWidth(5 * leftConn->mRadius);
00296                 combinedSize.setWidth(5 * leftConn->mRadius);
00297         }
00298         if (rightConn->parentItem() != NULL) {
00299                 combinedSize.setWidth(combinedSize.width() + rightConn->parentItem()->boundingRect().width());
00300                 combinedSize.setHeight(combinedSize.height() + rightConn->parentItem()->boundingRect().height());
00301         }
00302         else {
00303                 combinedSize.setWidth(combinedSize.width() + 5 * rightConn->mRadius);
00304                 combinedSize.setHeight(combinedSize.height() + 5 * rightConn->mRadius);
00305         }
00306         
00307         
00308 
00309         if (leftConn->connectorAlignment() == rightConn->connectorAlignment() && leftConn->connectorAlignment() == NodeConnector::Left && right.x() - left.x() < combinedSize.width()/2.0) {
00310                 controlPoint1.setX(controlPoint1.x() - moveY/2.0 /*- combinedSize.width()/2.0*/);
00311                 controlPoint2.setX(controlPoint2.x() - moveY/2.0 /*- combinedSize.width()/2.0*/);
00312         }
00313         else if (leftConn->connectorAlignment() == rightConn->connectorAlignment() && leftConn->connectorAlignment() == NodeConnector::Right && right.x() - left.x() < combinedSize.width()/2.0) {
00314                 controlPoint1.setX(controlPoint1.x() + moveY/2.0 /*+ combinedSize.width()/2.0*/);
00315                 controlPoint2.setX(controlPoint2.x() + moveY/2.0 /*+ combinedSize.width()/2.0*/);
00316         }
00317         else if (leftConn->connectorAlignment() == rightConn->connectorAlignment() && leftConn->connectorAlignment() == NodeConnector::Top && bottom.y() - top.y() < combinedSize.height()/2.0) {
00318                 controlPoint1.setY(controlPoint1.y() - moveX/2.0 /*- combinedSize.height()/2.0*/);
00319                 controlPoint2.setY(controlPoint2.y() - moveX/2.0 /*- combinedSize.height()/2.0*/);
00320         }
00321         else if (leftConn->connectorAlignment() == rightConn->connectorAlignment() && leftConn->connectorAlignment() == NodeConnector::Bottom && bottom.y() - top.y() < combinedSize.height()/2.0) {
00322                 controlPoint1.setY(controlPoint1.y() + moveX/2.0 /*+ combinedSize.height()/2.0*/);
00323                 controlPoint2.setY(controlPoint2.y() + moveX/2.0 /*+ combinedSize.height()/2.0*/);
00324         }
00325         else
00326         //the simple case, they face each other the "good" way
00327         if (leftConn->connectorAlignment() != NodeConnector::Left && rightConn->connectorAlignment() != NodeConnector::Right
00328                         && topConn->connectorAlignment() != NodeConnector::Top && bottomConn->connectorAlignment() != NodeConnector::Bottom) {
00329 
00330                 //very simple: straight line
00331                 //controlPoint1 = a + 0.3 * (b-a);
00332                 //controlPoint2 = a + 0.7 * (b-a);
00333 
00334                 controlPoint1 = a;
00335                 controlPoint2 = b;
00336                 //how much to move control point from start or end point
00337                 qreal moveX = 0.45 * diffx;
00338                 qreal moveY = 0.45 * diffy;
00339                 if (dist > 5 * (mStartConnector->mRadius + arrowSize)) {
00340                         /* does mess up good case because moves there too
00341                         if (abs(diffx-diffy) > 0.3 * dist) {
00342                                 moveX += abs(diffx-diffy);
00343                                 moveY += abs(diffx-diffy);
00344                         }
00345                         */
00346                                 
00347                         if (moveX < 3 * (mStartConnector->mRadius + arrowSize)) {
00348                                 moveX = 3 * (mStartConnector->mRadius + arrowSize);
00349                         }
00350                         if (moveY < 3 * (mStartConnector->mRadius + arrowSize)) {
00351                                 moveY = 3 * (mStartConnector->mRadius + arrowSize);
00352                         }
00353                 }
00354 
00355                 if (mStartConnector->connectorAlignment() == NodeConnector::Left) {
00356                         controlPoint1.setX(controlPoint1.x() - moveX);
00357                 }
00358                 else if (mStartConnector->connectorAlignment() == NodeConnector::Right) {
00359                         controlPoint1.setX(controlPoint1.x() + moveX);
00360                 }
00361                 else if (mStartConnector->connectorAlignment() == NodeConnector::Bottom) {
00362                         controlPoint1.setY(controlPoint1.y() + moveY);
00363                 }
00364                 else if (mStartConnector->connectorAlignment() == NodeConnector::Top) {
00365                         controlPoint1.setY(controlPoint1.y() - moveY);
00366                 }
00367 
00368                 if (mEndConnector->connectorAlignment() == NodeConnector::Left) {
00369                         controlPoint2.setX(controlPoint2.x() - moveX);
00370                 }
00371                 else if (mEndConnector->connectorAlignment() == NodeConnector::Right) {
00372                         controlPoint2.setX(controlPoint2.x() + moveX);
00373                 }
00374                 else if (mEndConnector->connectorAlignment() == NodeConnector::Bottom) {
00375                         controlPoint2.setY(controlPoint2.y() + moveY);
00376                 }
00377                 else if (mEndConnector->connectorAlignment() == NodeConnector::Top) {
00378                         controlPoint2.setY(controlPoint2.y() - moveY);
00379                 }
00380         }
00381         //the bad case, method needs cleanup
00382         else {
00383                 controlPoint1 = a;
00384                 controlPoint2 = b;
00385                 qreal maxMove = 0.5 * dist;
00386                 moveX = 0.5 * dist;
00387                 moveY = 0.5 * dist;
00388                 if (mStartConnector->parent != NULL) {
00389                         maxMove = 1 * (mStartConnector->parent->boundingRect().width() + mStartConnector->parent->boundingRect().height());
00390                 }
00391                 else if (mEndConnector->parent != NULL) {
00392                         maxMove = 1 * (mEndConnector->parent->boundingRect().width() + mEndConnector->parent->boundingRect().height());
00393                 }
00394                 if (moveX > maxMove) {
00395                         moveX = maxMove + 0.1 * (moveX-maxMove);
00396                 }
00397                 if (moveY > maxMove) {
00398                         moveY = maxMove + 0.1 * (moveY-maxMove);
00399                 }
00400                 if (mStartConnector->connectorAlignment() == NodeConnector::Left) {
00401                         moveX *= -1;
00402                         if ((mStartConnector == topConn) == (mStartConnector == rightConn)) {
00403                                 moveY *= -1;//relevantHeight;
00404                         }
00405                 }
00406                 else if (mStartConnector->connectorAlignment() == NodeConnector::Right) {
00407                         //moveX *= 1;
00408                         if ((mStartConnector == topConn) == (mStartConnector == leftConn)) {
00409                                 moveY *= -1;//relevantHeight;
00410                         }
00411                 }
00412                 else if (mStartConnector->connectorAlignment() == NodeConnector::Bottom) {
00413                         //moveY *= 1;
00414                         if ((mStartConnector == leftConn) == (mStartConnector == topConn)) {
00415                                 moveX *= -1;
00416                         }
00417                 }
00418                 else if (mStartConnector->connectorAlignment() == NodeConnector::Top) {
00419                         moveY *= -1;
00420                         if ((mStartConnector == leftConn) == (mStartConnector == bottomConn)) {
00421                                 moveX *= -1;
00422                         }
00423                 }
00424 
00425                 /*
00426                 if (mStartConnector->connectorAlignment() == mEndConnector->connectorAlignment()) {
00427                         moveX *= 2;
00428                         moveY *= 2;
00429                 }
00430                 */
00431 
00432                 //ugly shit: handle some cases that don't look nice
00433                 if (mEndConnector == topConn && topConn->connectorAlignment() == NodeConnector::Top && (bottomConn->connectorAlignment() == NodeConnector::Left || bottomConn->connectorAlignment() == NodeConnector::Right)) {
00434                         moveY *= -1;
00435                         //moveY = 0;
00436                 }
00437                 else if (mEndConnector == bottomConn && bottomConn->connectorAlignment() == NodeConnector::Bottom && (topConn->connectorAlignment() == NodeConnector::Left || topConn->connectorAlignment() == NodeConnector::Right)) {
00438                         moveY *= -1;
00439                         //moveY = 0;
00440                 }
00441                 else if (mEndConnector == leftConn && leftConn->connectorAlignment() == NodeConnector::Left && (rightConn->connectorAlignment() == NodeConnector::Top || rightConn->connectorAlignment() == NodeConnector::Bottom)) {
00442                         moveX *= -1;
00443                         //moveX = 0;
00444                 }
00445                 else if (mEndConnector == rightConn && rightConn->connectorAlignment() == NodeConnector::Right && (leftConn->connectorAlignment() == NodeConnector::Top || leftConn->connectorAlignment() == NodeConnector::Bottom)) {
00446                         moveX *= -1;
00447                         //moveX = 0;
00448                 }
00449 
00450                 controlPoint1.setX(controlPoint1.x() + moveX);
00451                 controlPoint1.setY(controlPoint1.y() + moveY);
00452 
00453 
00454                 moveX = 0.5 * dist;
00455                 moveY = 0.5 * dist;
00456                 // if start was null, then it was already set to end.
00457                 if (mStartConnector->parent != NULL && mEndConnector->parent != NULL) {
00458                         maxMove = 1 * (mEndConnector->parent->boundingRect().width() + mEndConnector->parent->boundingRect().height());
00459                 }
00460                 if (moveX > maxMove) {
00461                         moveX = maxMove + 0.1 * (moveX-maxMove);
00462                 }
00463                 if (moveY > maxMove) {
00464                         moveY = maxMove + 0.1 * (moveY-maxMove);
00465                 }
00466                 if (mEndConnector->connectorAlignment() == NodeConnector::Left) {
00467                         moveX *= -1;
00468                         if ((mEndConnector == topConn) == (mEndConnector == rightConn)) {
00469                                 moveY *= -1;//relevantHeight;
00470                         }
00471                 }
00472                 else if (mEndConnector->connectorAlignment() == NodeConnector::Right) {
00473                         //moveX *= 1;
00474                         if ((mEndConnector == topConn) == (mEndConnector == leftConn)) {
00475                                 moveY *= -1;//relevantHeight;
00476                         }
00477                 }
00478                 else if (mEndConnector->connectorAlignment() == NodeConnector::Bottom) {
00479                         //moveY *= 1;
00480                         if ((mStartConnector == leftConn) == (mStartConnector == topConn)) {
00481                                 moveX *= -1;
00482                         }
00483                 }
00484                 else if (mEndConnector->connectorAlignment() == NodeConnector::Top) {
00485                         moveY *= -1;
00486                         if ((mStartConnector == leftConn) == (mStartConnector == bottomConn)) {
00487                                 moveX *= -1;
00488                         }
00489                 }
00490 
00491                 /*
00492                 if (mStartConnector->connectorAlignment() == mEndConnector->connectorAlignment()) {
00493                         moveX *= 2;
00494                         moveY *= 2;
00495                 }*/
00496 
00497 
00498                 //ugly shit: handle some cases that don't look nice
00499                 if (mStartConnector == topConn && topConn->connectorAlignment() == NodeConnector::Top && (bottomConn->connectorAlignment() == NodeConnector::Left || bottomConn->connectorAlignment() == NodeConnector::Right)) {
00500                         moveY *= -1;
00501                         //moveY = 0;
00502                 }
00503                 else if (mStartConnector == bottomConn && bottomConn->connectorAlignment() == NodeConnector::Bottom && (topConn->connectorAlignment() == NodeConnector::Left || topConn->connectorAlignment() == NodeConnector::Right)) {
00504                         moveY *= -1;
00505                         //moveY = 0;
00506                 }
00507                 else if (mStartConnector == leftConn && leftConn->connectorAlignment() == NodeConnector::Left && (rightConn->connectorAlignment() == NodeConnector::Top || rightConn->connectorAlignment() == NodeConnector::Bottom)) {
00508                         moveX *= -1;
00509                         //moveX = 0;
00510                 }
00511                 else if (mStartConnector == rightConn && rightConn->connectorAlignment() == NodeConnector::Right && (leftConn->connectorAlignment() == NodeConnector::Top || leftConn->connectorAlignment() == NodeConnector::Bottom)) {
00512                         moveX *= -1;
00513                         //moveX = 0;
00514                 }
00515 
00516                 controlPoint2.setX(controlPoint2.x() + moveX);
00517                 controlPoint2.setY(controlPoint2.y() + moveY);
00518         }
00519 
00520 
00521         QPainterPath p(a);
00522         p.cubicTo(controlPoint1, controlPoint2, b);
00523         this->setPath(p);
00524 }
00525 
00526 
00527 //FIXME: width and length for arrow
00528 QPolygonF NodeConnection::createArrowPoly(QPainterPath& p, NodeConnector* conn) {
00529         float arrowStartPercentage;
00530         float arrowEndPercentage;
00531         
00532         if (conn == mEndConnector) {
00533                 arrowStartPercentage = p.percentAtLength(p.length() - conn->mRadius - arrowSize);
00534                 arrowEndPercentage = p.percentAtLength(p.length() - conn->mRadius);
00535         }
00536         else {
00537                 //assuming is start connector, should throw exception otherwise?
00538                 arrowStartPercentage = p.percentAtLength(conn->mRadius + arrowSize);
00539                 arrowEndPercentage = p.percentAtLength(conn->mRadius);
00540         }
00541         QPointF headStartP = p.pointAtPercent(arrowStartPercentage);
00542         QPointF headEndP = p.pointAtPercent(arrowEndPercentage);
00543         QLineF arrowMiddleLine(headStartP, headEndP);
00544         //QLineF normHead = arrowMiddleLine.normalVector();
00545         arrowMiddleLine.unitVector();
00546         QPointF normHead(arrowMiddleLine.dy(), -arrowMiddleLine.dx());
00547         QPointF arrowP1 = headStartP + normHead * 0.4;
00548         QPointF arrowP2 = headStartP - normHead * 0.4;
00549 
00550         QPolygonF arrowHeadEnd;
00551         arrowHeadEnd << headEndP << arrowP1 << arrowP2 /*<< headEndP*/;
00552         return arrowHeadEnd;
00553 }
00554 
00555 
00556 bool NodeConnection::setBidirectional(bool bidirectional) {
00557         mBidirectional =  bidirectional && mStartConnector->connectorType() == NodeConnector::InOut && mEndConnector->connectorType() == NodeConnector::InOut;
00558         return mBidirectional;
00559 }
00560 bool NodeConnection::bidirectional() {
00561         return mBidirectional;
00562 }
00563 
00564 
00565 void NodeConnection::debugPaint(QPainter *painter, QPointF& controlPoint1, QPointF& controlPoint2) {
00566 
00567         //dw debug
00568         static int i = 0, j=0, k=0;
00569 
00570         QPen mPen = painter->pen();
00571         QColor ctrlPtCol(i=(i+19)%256 , j=(j+51)%256, k=(k+11)%256);
00572         mPen.setColor(ctrlPtCol);
00573         painter->setPen(mPen);
00574 
00575         //painter->drawPath(shape()); // to see item.
00576         painter->fillRect(boundingRect(), QColor(i=(i+19)%256 , j=(j+51)%256, k=(k+11)%256)); // to see item.
00577 
00578         //painter->setPen(Qt::NoPen);
00579     painter->setBrush(ctrlPtCol);
00580 
00581         //painter->drawPoint(controlPoint1);
00582         //painter->drawPoint(controlPoint2);
00583         painter->drawEllipse(controlPoint1.x()-2, controlPoint1.y()-2, 5, 5);
00584         painter->drawEllipse(controlPoint2.x()-2, controlPoint2.y()-2, 5, 5);
00585 }
00586 
00587 
00589 void NodeConnection::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *w)
00590 {
00591         Q_UNUSED(option);
00592     Q_UNUSED(w);
00593 
00594         //dw 699:
00595         painter->setRenderHint(QPainter::Antialiasing);
00596 
00597         if (mStartConnector == NULL || mEndConnector == NULL || mStartConnector->collidesWithItem(mEndConnector))
00598         return;
00599 
00600         //ugly, only used for debug draw
00601         QPointF controlPoint1;
00602         QPointF controlPoint2;
00603         recreatePath(controlPoint1, controlPoint2);
00604         
00605         // FIXME:causes difference beteen debug draw and normal draw!!!
00606         //updatePosition(controlPoint1, controlPoint2);
00607         if (static_cast<DiagramScene*>(scene())->isDebugDraw()) {
00608                 QPen origPen = painter->pen();
00609                 QBrush origBrush = painter->brush();
00610                 debugPaint(painter, controlPoint1, controlPoint2);
00611                 painter->setPen(origPen);
00612             painter->setBrush(origBrush);
00613         }
00614 
00615     QPen mPen = pen();
00616     mPen.setColor(mColor);
00617     painter->setPen(mPen);
00618         //line
00619     //painter->setBrush(mColor);
00620         painter->setBrush(Qt::NoBrush);
00621 
00622         if (isSelected())
00623                 painter->setPen(QPen(mColor, 1, Qt::DashLine));
00624 
00625 
00626 
00627 
00628         //painter->drawLine(line());
00629 
00630         //cubic spline?
00631         QPainterPath& p = this->path();
00632         painter->drawPath(p);
00633 
00634         //fill
00635         painter->setBrush(mColor);
00636 
00637         //test:
00638         QPolygonF arrowHeadEnd = createArrowPoly(p, mEndConnector);
00639         if (bidirectional()) {
00640                 QPolygonF arrowHeadStart = createArrowPoly(p, mStartConnector);
00641                 p.addPolygon(arrowHeadStart);
00642                 painter->drawPolygon(arrowHeadStart);
00643         }
00644         //do this after creating other arrow, in case it matters in arrow calc on path
00645         p.addPolygon(arrowHeadEnd);
00646         painter->drawPolygon(arrowHeadEnd);
00647         
00648 
00649         /*
00650         //dw new4: what was it for, now commented out
00651         //dw668: activated again. otherwise painting of path had hollow head
00652                 //dw reset brush, check again
00653             mPen = pen();
00654                 mPen.setColor(mColor);
00655                 painter->setPen(mPen);
00656                 painter->setBrush(mColor);
00657         painter->drawPolygon(arrowHead);
00658                 */
00659 }
00660