From c19af27b62d938b7e45148b908bfd839e98c80f5 Mon Sep 17 00:00:00 2001 From: Denes Matetelki Date: Tue, 14 Jun 2011 11:08:09 +0200 Subject: [PATCH] shorter lines to fit in 80, bugfix: multiple edges could be added between 2 nodes --- edge.cpp | 47 ++++++++++++++++++++++------------- graphwidget.cpp | 43 ++++++++++++++++++++++++-------- graphwidget.h | 1 + node.cpp | 66 ++++++++++++++++++++++++++++++++----------------- node.h | 3 ++- 5 files changed, 110 insertions(+), 50 deletions(-) diff --git a/edge.cpp b/edge.cpp index 5e585f0..09b2290 100644 --- a/edge.cpp +++ b/edge.cpp @@ -20,13 +20,12 @@ Edge::Edge(Node *sourceNode, Node *destNode) m_sourceNode->addEdge(this,true); m_destNode->addEdge(this,false); adjust(); -// setZValue(1); } Edge::~Edge() { - m_sourceNode->removeEdge(this); - m_destNode->removeEdge(this); + m_sourceNode->removeEdgeFromList(this); + m_destNode->removeEdgeFromList(this); } Node *Edge::sourceNode() const @@ -42,7 +41,6 @@ Node *Edge::destNode() const /** @note This is brute force. Isn't there a simple fv for this? * The precision is not the best either */ - QPointF firstNotContainedPoint(const QLineF &line, const QRectF &rect, bool reverse = false) @@ -71,12 +69,16 @@ void Edge::adjust() prepareGeometryChange(); - QLineF line(mapFromItem(m_sourceNode, 0, 0) + m_sourceNode->boundingRect().center(), - mapFromItem(m_destNode, 0, 0) + m_destNode->boundingRect().center()); + QLineF line(mapFromItem(m_sourceNode, 0, 0) + + m_sourceNode->boundingRect().center(), + mapFromItem(m_destNode, 0, 0) + + m_destNode->boundingRect().center()); if (line.length() > qreal(20.)) { - m_sourcePoint = firstNotContainedPoint(line,m_sourceNode->sceneBoundingRect()); - m_destPoint = firstNotContainedPoint(line,m_destNode->sceneBoundingRect(),true); + m_sourcePoint = firstNotContainedPoint(line, + m_sourceNode->sceneBoundingRect()); + m_destPoint = firstNotContainedPoint(line, + m_destNode->sceneBoundingRect(),true); } else { m_sourcePoint = m_destPoint = line.p1(); } @@ -92,12 +94,15 @@ QRectF Edge::boundingRect() const return QRectF(m_sourcePoint, QSizeF(m_destPoint.x() - m_sourcePoint.x(), m_destPoint.y() - m_sourcePoint.y())) - .normalized() - .adjusted(-extra, -extra, extra, extra); + .normalized().adjusted(-extra, -extra, extra, extra); } -void Edge::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) +void Edge::paint(QPainter *painter, + const QStyleOptionGraphicsItem *, + QWidget *w) { + Q_UNUSED(w); + if (!m_sourceNode || !m_destNode) return; @@ -111,20 +116,28 @@ void Edge::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) return; // Draw the line itself - painter->setPen(QPen(Qt::black, 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); + painter->setPen(QPen(Qt::black, + 1, + Qt::SolidLine, + Qt::RoundCap, + Qt::RoundJoin)); painter->drawLine(line); if (line.length() < m_arrowSize) return; // Draw the arrows - QPointF destArrowP1 = m_destPoint + QPointF(sin(m_angle - Pi / 3) * m_arrowSize, - cos(m_angle - Pi / 3) * m_arrowSize); - QPointF destArrowP2 = m_destPoint + QPointF(sin(m_angle - Pi + Pi / 3) * m_arrowSize, - cos(m_angle - Pi + Pi / 3) * m_arrowSize); + QPointF destArrowP1 = m_destPoint + + QPointF(sin(m_angle - Pi / 3) * m_arrowSize, + cos(m_angle - Pi / 3) * m_arrowSize); + QPointF destArrowP2 = m_destPoint + + QPointF(sin(m_angle - Pi + Pi / 3) * m_arrowSize, + cos(m_angle - Pi + Pi / 3) * m_arrowSize); painter->setBrush(Qt::black); - painter->drawPolygon(QPolygonF() << line.p2() << destArrowP1 << destArrowP2); + painter->drawPolygon(QPolygonF() << line.p2() + << destArrowP1 + << destArrowP2); } double Edge::getAngle() const diff --git a/graphwidget.cpp b/graphwidget.cpp index d6f9c4e..f734c42 100644 --- a/graphwidget.cpp +++ b/graphwidget.cpp @@ -231,7 +231,6 @@ void GraphWidget::keyPressEvent(QKeyEvent *event) dynamic_cast(m_parent)->getStatusBar()->showMessage( tr("No active node."), 5000); // millisec - } else { @@ -291,7 +290,7 @@ void GraphWidget::keyPressEvent(QKeyEvent *event) if (m_edgeAdding) { - m_scene->addItem(new Edge(m_activeNode, m_hintNode)); + addEdge(m_activeNode, m_hintNode); m_edgeAdding = false; } if (m_edgeDeleting) @@ -341,8 +340,18 @@ void GraphWidget::keyPressEvent(QKeyEvent *event) if (m_showingNodeNumbers) { - m_showingNodeNumbers = false; showingAllNodeNumbers(false); + if (m_hintNumber.isEmpty()) + { + showingAllNodeNumbers(true); + m_nodeList.first()->showNumber(0,true,true); + m_hintNode = m_nodeList.first(); + } + else + { + showingNodeNumbersBeginWithNumber(m_hintNumber.toInt(), + true); + } } } else @@ -352,6 +361,8 @@ void GraphWidget::keyPressEvent(QKeyEvent *event) 5000); // millisec } + break; + // add edge to active node case Qt::Key_A: @@ -378,7 +389,7 @@ void GraphWidget::keyPressEvent(QKeyEvent *event) if (m_activeNode) { dynamic_cast(m_parent)->getStatusBar()->showMessage( - tr("Delete edge: select destination node"), + tr("Delete edge: select other end-node"), 5000); // millisec m_edgeDeleting = true; @@ -442,7 +453,6 @@ void GraphWidget::insertNode() { double angle(m_activeNode->calculateBiggestAngle()); - qreal length(100); QPointF pos(length * cos(angle), length * sin(angle)); @@ -452,11 +462,10 @@ void GraphWidget::insertNode() m_scene->addItem(node); node->setPos(m_activeNode->sceneBoundingRect().center() + pos - - node->boundingRect().center() - ); + node->boundingRect().center()); m_nodeList.append(node); - m_scene->addItem(new Edge(m_activeNode, node)); + addEdge(m_activeNode, node); setActiveNode(node); setActiveNodeEditable(); @@ -497,7 +506,7 @@ void GraphWidget::showingNodeNumbersBeginWithNumber(const int &number, if (m_edgeAdding) { - m_scene->addItem(new Edge(m_activeNode, m_hintNode)); + addEdge(m_activeNode, m_hintNode); m_edgeAdding = false; } if (m_edgeDeleting) @@ -538,7 +547,7 @@ void GraphWidget::nodeSelected(Node *node) { if (m_edgeAdding) { - m_scene->addItem(new Edge(m_activeNode, node)); + addEdge(m_activeNode, node); m_edgeAdding = false; } if (m_edgeDeleting) @@ -551,3 +560,17 @@ void GraphWidget::nodeSelected(Node *node) setActiveNode(node); } } + +void GraphWidget::addEdge(const Node *source, const Node *destination) +{ + if (source->isConnected(destination)) + { + dynamic_cast(m_parent)->getStatusBar()->showMessage( + tr("There is already an edge between these two nodes."), + 5000); // millisec + } + else + { + m_scene->addItem(new Edge(m_activeNode, m_hintNode)); + } +} diff --git a/graphwidget.h b/graphwidget.h index 8271480..da12478 100644 --- a/graphwidget.h +++ b/graphwidget.h @@ -37,6 +37,7 @@ private: const bool &show = true); bool numberStartsWithNumber(const int &number, const int &prefix); qreal calculateBiggestAngle(Node *node); + void addEdge(const Node *source, const Node *destination); QList m_nodeList; QWidget *m_parent; diff --git a/node.cpp b/node.cpp index 9f3d7a2..6c5d581 100644 --- a/node.cpp +++ b/node.cpp @@ -7,6 +7,8 @@ #include static const double Pi = 3.14159265358979323846264338327950288419717; +static double TwoPi = 2.0 * Pi; +static double OneAndHalfPi = 1.5 * Pi; Node::Node(GraphWidget *parent) : m_graph(parent), @@ -20,12 +22,12 @@ Node::Node(GraphWidget *parent) : setCacheMode(DeviceCoordinateCache); - // shall I use system colors? setDefaultTextColor(QColor(0,0,0)); } Node::~Node() { + // dtor of Edge will call removeEdgeFromList on booth nodes. foreach (EdgeElement element, m_edgeList) delete element.edge; } @@ -35,7 +37,7 @@ void Node::addEdge(Edge *edge, bool startsFromThisNode) edge->adjust(); } -void Node::removeEdge(Edge *edge) +void Node::removeEdgeFromList(Edge *edge) { for(QList::iterator it = m_edgeList.begin(); it != m_edgeList.end(); it++) @@ -50,13 +52,13 @@ void Node::removeEdge(Edge *edge) void Node::removeEdge(Node *otherEnd) { - qDebug() << __PRETTY_FUNCTION__; - for(QList::iterator it = m_edgeList.begin(); it != m_edgeList.end(); it++) { - if ((it->edge->sourceNode() == otherEnd && it->edge->destNode() == this) - || (it->edge->sourceNode() == this && it->edge->destNode() == otherEnd)) + if ((it->edge->sourceNode() == otherEnd && + it->edge->destNode() == this) + || (it->edge->sourceNode() == this && + it->edge->destNode() == otherEnd)) { delete it->edge; return; @@ -74,8 +76,11 @@ QVariant Node::itemChange(GraphicsItemChange change, const QVariant &value) { // value is the new position. QPointF newPos = value.toPointF(); + + // the fence is reduced with the size of the node QRectF rect (scene()->sceneRect().topLeft(), - scene()->sceneRect().bottomRight()-boundingRect().bottomRight()); + scene()->sceneRect().bottomRight() - + boundingRect().bottomRight()); if (!rect.contains(newPos)) { @@ -98,28 +103,36 @@ QVariant Node::itemChange(GraphicsItemChange change, const QVariant &value) return QGraphicsItem::itemChange(change, value); } -void Node::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *w) +void Node::paint(QPainter *painter, + const QStyleOptionGraphicsItem *option, + QWidget *w) { - // draw background in hint mode - /// @bug is there a 1pixel wide yellow line at the bottom of borderless item? + // draw background in hint mode. num == -1 : not in hint mode + // if m_numberIsSpecial (can be selected with enter) bg is green, not yellow if (m_number != -1) { painter->setPen(Qt::transparent); painter->setBrush(m_numberIsSpecial ? Qt::green : Qt::yellow); + + /// @bug is there a 1pixel wide yellow line at the + /// bottom of borderless items? painter->drawRect(QRect(boundingRect().topLeft().toPoint(), boundingRect().bottomRight().toPoint())); painter->setBrush(Qt::NoBrush); } + // the text itself QGraphicsTextItem::paint(painter, option, w); - painter->setPen(m_isActive ? Qt::red : Qt::blue); - if (m_hasBorder) + { + painter->setPen(m_isActive ? Qt::red : Qt::blue); painter->drawRect(QRect(boundingRect().topLeft().toPoint(), boundingRect().bottomRight().toPoint() - QPoint(1,1))); + } + // print num to topleft corner in hint mode. if (m_number != -1) { painter->setPen(Qt::white); @@ -135,6 +148,7 @@ void Node::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWid void Node::setActive(const bool &active) { m_isActive = active; + // update border color update(); } @@ -180,7 +194,7 @@ void Node::setBorder(const bool &hasBorder) double Node::calculateBiggestAngle() { if (m_edgeList.empty()) - return 1.5 * Pi; + return OneAndHalfPi; if (m_edgeList.size()==1) { @@ -190,7 +204,7 @@ double Node::calculateBiggestAngle() } else { - return 2 * Pi - m_edgeList.first().edge->getAngle(); + return TwoPi - m_edgeList.first().edge->getAngle(); } } @@ -200,14 +214,13 @@ double Node::calculateBiggestAngle() { tmp.push_back(it->startsFromThisNode ? it->edge->getAngle() : - doubleModulo(Pi + it->edge->getAngle(), 2 * Pi)); + doubleModulo(Pi + it->edge->getAngle(), TwoPi)); } - qSort(tmp.begin(), tmp.end()); double prev(tmp.first()); double max_prev(tmp.last()); - double max(2 * Pi - tmp.last() + tmp.first()); + double max(TwoPi - tmp.last() + tmp.first()); for(QList::const_iterator it = ++tmp.begin(); it!=tmp.end(); it++) { @@ -219,7 +232,7 @@ double Node::calculateBiggestAngle() prev = *it; } - return 2 * Pi - doubleModulo(max_prev + max / 2, 2 * Pi); + return TwoPi - doubleModulo(max_prev + max / 2, TwoPi); } void Node::linkActivated(const QString &link) @@ -231,13 +244,12 @@ void Node::linkActivated(const QString &link) double Node::doubleModulo(const double &devided, const double &devisor) { - return devided - static_cast(devisor * static_cast(devided / devisor)); + return devided - static_cast(devisor * static_cast(devided + / devisor)); } void Node::setEditable(const bool &editable) { - qDebug() << __PRETTY_FUNCTION__; - setTextInteractionFlags( editable ? Qt::TextEditable : @@ -290,10 +302,20 @@ void Node::keyPressEvent(QKeyEvent *event) default: - // not cursor movement + // not cursor movement: editing QGraphicsTextItem::keyPressEvent(event); foreach (EdgeElement element, m_edgeList) element.edge->adjust(); } ///@note leaving editing mode is done with esc, handled by graphwidget } + +bool Node::isConnected(const Node *node) const +{ + foreach (EdgeElement element, m_edgeList) + if (element.edge->sourceNode() == node || + element.edge->destNode() == node) + return true; + + return false; +} diff --git a/node.h b/node.h index 4bfe1a3..4668a69 100644 --- a/node.h +++ b/node.h @@ -17,7 +17,7 @@ public: ~Node(); void addEdge(Edge *edge, bool startsFromThisNode); - void removeEdge(Edge *edge); + void removeEdgeFromList(Edge *edge); void removeEdge(Node *otherEnd); void setBorder(const bool &hasBorder); void setActive(const bool &active = true); @@ -28,6 +28,7 @@ public: // changing visibility from prot to pub void keyPressEvent(QKeyEvent *event); + bool isConnected(const Node *node) const; protected: