nodeeditor_doxy
src/Impl/nodeconnector.cpp
Go to the documentation of this file.
00001 #include <QGraphicsScene>
00002 #include <QGraphicsSceneMouseEvent>
00003 #include <QPainter>
00004 #include <QStyleOption>
00005 //dw
00006 #include <QPointF>
00007 #include <QSize>
00008 #include <QGraphicsWidget>
00009 
00010 //#include "edge.h"
00011 #include "nodeconnector.h"
00012 //#include "NodeItem.h"
00013 //#include "graphwidget.h"
00014 NodeConnector::~NodeConnector() {
00015         this->deleteConnections();
00016         //dw super class destructor should do this, right?
00017         if (scene() != NULL) {
00018                 this->scene()->removeItem(this);
00019         }
00020 }
00021 
00022 NodeConnector::NodeConnector(NodeItem *parent1, QGraphicsScene *scene1, /*QLabel*/QWidget* widget, NodeConnector::ConnectorType conType1, const ConnectorAlignment connectorAlignment, bool singleConnection, bool disableWidgetOnConnection, int radius, bool selfConnections)
00023                 //dw666 orig:
00024                 : QGraphicsItem(parent1, scene1),
00025                 //: QGraphicsItem(NULL, scene1),
00026         mConnectorType(conType1), parent(parent1), mWidget(widget), mConnectorAlignment(connectorAlignment), mSingleConnection(singleConnection), mDisableWidgetOnConnection(disableWidgetOnConnection), mSelfConnections(selfConnections), mRadius(radius)
00027 {
00028         //orig
00029     //setFlag(ItemIsMovable);
00030         //dw new4: is this a problem? check it
00031     setCacheMode(DeviceCoordinateCache);
00032 
00033     //dw new: setZValue(1);
00034         setZValue(2);
00035 
00036         //dw667: new try
00037         updatePosition();
00038 
00039         //setFlag(QGraphicsItem::ItemIsSelectable, true);
00040 
00041         if (conType1 == ConnectorType::In) {
00042                 darkColor =  QColor(Qt::darkYellow);
00043         }
00044         else if (conType1 == ConnectorType::Out) {
00045                 darkColor =  QColor(Qt::darkRed).light(80);
00046         }
00047         else {
00048                 darkColor =  QColor(Qt::darkGreen);
00049         }
00050         highlight = false;
00051 }
00052 
00053 //dw667 backmerge: was active
00054 /*
00055 void NodeConnector::updatePositionGeometry() {
00056         //prepareGeometryChange();
00057         updatePosition();
00058         foreach (NodeConnection *c, this->arrows) {
00059                 //dw problem: label already deleted but connector tries to enable it?
00060         //c->paint(painter, option, w);
00061                 c->updatePositionGeometry();
00062     }
00063         update();
00064 }
00065 */
00066 
00067 void NodeConnector::updatePosition() {
00068         this->prepareGeometryChange();
00069 
00070         //if we dont have parent, stay where we are
00071         if (parent == NULL || mWidget == NULL) {
00072                 return;
00073         }
00074 
00075         QPointF pPos = parent->pos();
00076         //dw temp quick fix for refactoring
00077         QPointF newPos = pPos;
00078 
00079         //dw FIXME: need to adapt to different partner classes? should ask parent about position?
00080         /*
00081         QSize widgetSize = mWidget->boundingRect();
00082         //dw677:
00083         //QSizeF widgetSize = parent->boundingRect();
00084         //radius = labelSize.height()/2;
00085 
00086         QPointF newPos;
00087         if (connectorAlignment() == NodeConnector::Left) {
00088                 newPos.setX(-mRadius);
00089                 //newPos.setY(mWidget->pos().y() + widgetSize.height()/2.0);
00090                 //dw677:
00091                 //newPos.setY(parent->pos().y() + widgetSize.height()/2.0);
00092                 //newPos.setY(mWidget->pos().y() + mWidget->boundingRect().height()/2.0);
00093                 //newPos.setY(mWidget->pos().y() + mWidget->boundingRect().height()/2.0);
00094                 //newPos.setY(mWidget->pos().y() + mWidget->height()/2.0);
00095                 newPos.setY(parent->subWidgetRect(mWidget).y() + parent->subWidgetRect(mWidget).height()/2.0);
00096         }
00097         else if (connectorAlignment() == NodeConnector::Right) {
00098                 //seems to be to big
00099                 //newPos.setX(parent->boundingsize().width()+mRadius+1);
00100                 //seems to be size of content??? too small
00101                 //newPos.setX(parent->window()->boundingRect().width()+mRadius+1);
00102                 //float rightx = dynamic_cast<NodeItem*>(parent)->widget()->width()
00103                 //      + mRadius + 1;
00104                 //float rightx = dynamic_cast<NodeItem*>(parent)->widget()->geometry().size().width()
00105                 //      + mRadius + 1;
00106                 /*
00107                 float rightx = dynamic_cast<NodeItem*>(parent)->widget()->width()
00108                         + dynamic_cast<NodeItem*>(parent)->widget()->baseSize().width()
00109                         + mRadius + 1;
00110                         */
00111 /*
00112                 //dw FIXME: ugly
00113                 newPos.setX(parent->boundingRect().width() + mRadius);
00114                 //newPos.setY(mWidget->pos().y()+ widgetSize.height()/2.0);
00115                 newPos.setY(parent->subWidgetRect(mWidget).y()+ parent->subWidgetRect(mWidget).height()/2.0);
00116         }
00117         else if (connectorAlignment() == NodeConnector::Bottom) {
00118                 //newPos.setX(mWidget->pos().x() + widgetSize.width()/2.0);
00119                 newPos.setX(parent->subWidgetRect(mWidget).x() + parent->subWidgetRect(mWidget).width()/2.0);
00120 
00121                 //newPos.setY(parent->widget()->boundingRect().height() + mRadius);
00122                 //newPos.setY(parent->boundingsize().height() + mRadius);
00123                 newPos.setY(parent->boundingRect().height() + mRadius);
00124         }
00125         else if (connectorAlignment() == NodeConnector::Top) {
00126                 //newPos.setX(mWidget->pos().x() + widgetSize.width()/2.0);
00127                 newPos.setX(parent->subWidgetRect(mWidget).x() + parent->subWidgetRect(mWidget).width()/2.0);
00128                 newPos.setY(-mRadius);
00129         }
00130         */
00131 
00132         this->setPos(newPos);
00133         //dw seems to always paint -> is already called from update? or will cause updatePos in next frame again?
00134         //update();
00135 
00136         foreach (NodeConnection *c, this->arrows) {
00137                 //dw problem: label already deleted but connector tries to enable it?
00138         //c->paint(painter, option, w);
00139                 c->updatePosition();
00140     }
00141         update();
00142 }
00143 
00144 /*
00145 void NodeConnector::addEdge(Edge *edge)
00146 {
00147     edgeList << edge;
00148     edge->adjust();
00149 }
00150 
00151 QList<Edge *> NodeConnector::edges() const
00152 {
00153     return edgeList;
00154 }
00155 
00156 void NodeConnector::calculateForces()
00157 {
00158     if (!scene() || scene()->mouseGrabberItem() == this) {
00159         newPos = pos();
00160         return;
00161     }
00162     
00163     // Sum up all forces pushing this item away
00164     qreal xvel = 0;
00165     qreal yvel = 0;
00166     foreach (QGraphicsItem *item, scene()->items()) {
00167         NodeConnector *node = qgraphicsitem_cast<NodeConnector *>(item);
00168         if (!node)
00169             continue;
00170 
00171         QLineF line(mapFromItem(node, 0, 0), QPointF(0, 0));
00172         qreal dx = line.dx();
00173         qreal dy = line.dy();
00174         double l = 2.0 * (dx * dx + dy * dy);
00175         if (l > 0) {
00176             xvel += (dx * 150.0) / l;
00177             yvel += (dy * 150.0) / l;
00178         }
00179     }
00180 
00181     // Now subtract all forces pulling items together
00182     double weight = (edgeList.size() + 1) * 10;
00183     foreach (Edge *edge, edgeList) {
00184         QPointF pos;
00185         if (edge->sourceNodeConnector() == this)
00186             pos = mapFromItem(edge->destNodeConnector(), 0, 0);
00187         else
00188             pos = mapFromItem(edge->sourceNodeConnector(), 0, 0);
00189         xvel += pos.x() / weight;
00190         yvel += pos.y() / weight;
00191     }
00192     
00193     if (qAbs(xvel) < 0.1 && qAbs(yvel) < 0.1)
00194         xvel = yvel = 0;
00195 
00196     QRectF sceneRect = scene()->scenesize();
00197     newPos = pos() + QPointF(xvel, yvel);
00198     newPos.setX(qMin(qMax(newPos.x(), sceneRect.left() + 10), sceneRect.right() - 10));
00199     newPos.setY(qMin(qMax(newPos.y(), sceneRect.top() + 10), sceneRect.bottom() - 10));
00200 }
00201 
00202 bool NodeConnector::advance()
00203 {
00204     if (newPos == pos())
00205         return false;
00206 
00207     setPos(newPos);
00208     return true;
00209 }*/
00210 
00211 void NodeConnector::setHighlight(bool highlight) {
00212         prepareGeometryChange();
00213         this->highlight = highlight;
00214         this->updatePosition();
00215         this->update();
00216 }
00217 
00218 
00219 QRectF NodeConnector::boundingRect() const
00220 {
00221     qreal adjust = 1;
00222     return QRectF(-mRadius - adjust, -mRadius - adjust,
00223                   2*(mRadius + adjust), 2*(mRadius + adjust));
00224 
00225         //dw new
00226         //return QGraphicsItem::boundingsize();
00227 }
00228 
00229 
00230 QPainterPath NodeConnector::shape() const
00231 {
00232         
00233     QPainterPath path;
00234     path.addEllipse(-mRadius, -mRadius, 2*mRadius, 2*mRadius);
00235     return path;
00236         
00237         //dw new
00238         //return QGraphicsItem::shape();
00239 
00240         //dw new2
00241         /*
00242         QPainterPath path;
00243         path.addRect(boundingsize());
00244     return path;
00245         */
00246 }
00247 
00248 
00249 void NodeConnector::debugPaint(QPainter *painter) {
00250         //dw debug
00251         static int i = 0, j=0, k=0;
00252         painter->fillRect(boundingRect(), /*Qt::green*/ QColor(i=(i+19)%256 , j=(j+51)%256, k=(k+11)%256)); // to see item.
00253 }
00254 
00255 
00256 void NodeConnector::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget* w)
00257 {
00258         Q_UNUSED(option);
00259     Q_UNUSED(w);
00260 
00261         //dw 699:
00262         painter->setRenderHint(QPainter::Antialiasing);
00263 
00264         if (static_cast<DiagramScene*>(scene())->isDebugDraw()) {
00265                 debugPaint(painter);
00266         }
00267 
00268     painter->setPen(Qt::NoPen);
00269     painter->setBrush(Qt::darkGray);
00270         //painter->drawEllipse(-mRadius*0.8, -mRadius*0.8, mRadius, mRadius);
00271         //painter->drawEllipse(0, 0, 2*mRadius, 2*mRadius);
00272     QRadialGradient gradient(-mRadius/2, -mRadius/2, mRadius);
00273         if (/*option->state & QStyle::State_Sunken*/ highlight) {
00274         gradient.setCenter(mRadius/2, mRadius/2);
00275         gradient.setFocalPoint(mRadius/2, mRadius/2);
00276         //gradient.setColorAt(1, QColor(Qt::yellow).light(120));
00277         //gradient.setColorAt(0, QColor(Qt::darkYellow).light(120));
00278                 gradient.setColorAt(1, darkColor.light(240));
00279                 gradient.setColorAt(0, darkColor.light(120));
00280     } else {
00281         //gradient.setColorAt(0, Qt::yellow);
00282         //gradient.setColorAt(1, Qt::darkYellow);
00283                 gradient.setColorAt(0, darkColor.light(240));
00284         gradient.setColorAt(1, darkColor);
00285     }
00286         painter->setBrush(gradient);
00287     painter->setPen(QPen(Qt::black, 0));
00288     //painter->drawEllipse(-mRadius, -mRadius, mRadius, mRadius);
00289         painter->drawEllipse(-mRadius, -mRadius, 2*mRadius, 2*mRadius);
00290 
00291         //dw new2, is abstract
00292         //QGraphicsItem::paint(painter, option, w);
00293         
00294         /*
00295         //dw hacky, good idea??
00296         NodeConnection* a;
00297         a->p
00298         foreach(NodeConnection* a, arrows) {
00299                 a->paint(painter, option, NULL);
00300         }
00301 */
00302         
00303 /*
00304         painter->drawEllipse(-7, -7, 20, 20);
00305     QRadialGradient gradient(-3, -3, 10);
00306     if (option->state & QStyle::State_Sunken) {
00307         gradient.setCenter(3, 3);
00308         gradient.setFocalPoint(3, 3);
00309         gradient.setColorAt(1, QColor(Qt::yellow).light(120));
00310         gradient.setColorAt(0, QColor(Qt::darkYellow).light(120));
00311     } else {
00312         gradient.setColorAt(0, Qt::yellow);
00313         gradient.setColorAt(1, Qt::darkYellow);
00314     }
00315     painter->setBrush(gradient);
00316     painter->setPen(QPen(Qt::black, 0));
00317     painter->drawEllipse(-10, -10, 20, 20);
00318         */
00319 }
00320 
00321 //QVariant NodeConnector::itemChange(GraphicsItemChange change, const QVariant &value)
00322 //{
00323         /*
00324     switch (change) {
00325     case ItemPositionHasChanged:
00326 //        foreach (Edge *edge, edgeList)
00327 //            edge->adjust();
00328 //        graph->itemMoved();
00329         break;
00330     default:
00331         break;
00332     };
00333         */
00334 
00335 //    return QGraphicsItem::itemChange(change, value);
00336 //}
00337 
00338 void NodeConnector::mousePressEvent(QGraphicsSceneMouseEvent *event)
00339 {
00340         //highlight = true;
00341     update();
00342     QGraphicsItem::mousePressEvent(event);
00343 }
00344 
00345 void NodeConnector::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
00346 {
00347         setHighlight(false);
00348         //highlight = false;
00349     //update();
00350     QGraphicsItem::mouseReleaseEvent(event);
00351 }
00352 
00353 /*
00354 //not called, does the event exist for this class???
00355 void NodeConnector::mouseOverEvent(QGraphicsSceneMouseEvent *event)
00356 {
00357         highlight = true;
00358     update();
00359     //QGraphicsItem::mouseOverEvent(event);
00360 }
00361 */
00362 
00363 void NodeConnector::addConnection(NodeConnection *arrow)
00364 {
00365         if (mSingleConnection && arrows.count() > 0) {
00366                 //delete arrows.first();
00367                 //arrows.clear();
00368                 deleteConnections();
00369         }
00370 
00371         if (mDisableWidgetOnConnection) {
00372                 mWidget->setEnabled(false);
00373         }
00374 
00375     arrows.append(arrow);
00376 }
00377 
00378 void NodeConnector::deleteConnection(NodeConnection *arrow)
00379 {
00380         //TODO: how to handle deletion exactly, when to emit signals
00381         //arrow->startConnector()->arrows.removeOne(arrow);
00382         //arrow->endConnector()->arrows.removeOne(arrow);
00383 
00384         //deleting arrow will also remove it from this connector
00385         //dw new
00386         //arrow->setParentItem(NULL);
00387         delete arrow;
00388         //arrows removed during connection destruction, but attached outside => bad idea
00389 }
00390 
00391 /* removes a connection, but does not delete it*/
00392 void NodeConnector::removeConnection(NodeConnection *connection) {
00393         arrows.removeOne(connection);
00394         if (mDisableWidgetOnConnection && mWidget != NULL && arrows.count() == 0) {
00395                 mWidget->setEnabled(true);
00396         }
00397 }
00398 
00399 void NodeConnector::deleteConnections()
00400 {
00401         foreach(NodeConnection* arrow, arrows) {
00402                 deleteConnection(arrow);
00403         }
00404 }
00405 
00406 void NodeConnector::removeWidget() {
00407         mWidget = NULL;
00408         parent = NULL;
00409 }
00410 
00411 /*
00412 void NodeConnector::enterEvent ( QEvent * event )  {
00413         highlight = true;
00414         //QGraphicsItem::enterEvent(event);
00415 }
00416 */
00417 
00418 //dw new3
00419 void NodeConnector::update(const QRectF & rect) {
00420         
00421         //dw new3: why do ourself
00422         foreach (NodeConnection *c, this->arrows) {
00423                 //dw problem: label already deleted but connector tries to enable it?
00424         //c->paint(painter, option, w);
00425                 c->update(rect);
00426     }
00427         
00428         QGraphicsItem::update(rect);
00429 }