shorter lines to fit in 80, bugfix: multiple edges could be added between 2 nodes

master
Denes Matetelki 14 years ago
parent 2797afa329
commit c19af27b62

@ -20,13 +20,12 @@ Edge::Edge(Node *sourceNode, Node *destNode)
m_sourceNode->addEdge(this,true); m_sourceNode->addEdge(this,true);
m_destNode->addEdge(this,false); m_destNode->addEdge(this,false);
adjust(); adjust();
// setZValue(1);
} }
Edge::~Edge() Edge::~Edge()
{ {
m_sourceNode->removeEdge(this); m_sourceNode->removeEdgeFromList(this);
m_destNode->removeEdge(this); m_destNode->removeEdgeFromList(this);
} }
Node *Edge::sourceNode() const 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? /** @note This is brute force. Isn't there a simple fv for this?
* The precision is not the best either * The precision is not the best either
*/ */
QPointF firstNotContainedPoint(const QLineF &line, QPointF firstNotContainedPoint(const QLineF &line,
const QRectF &rect, const QRectF &rect,
bool reverse = false) bool reverse = false)
@ -71,12 +69,16 @@ void Edge::adjust()
prepareGeometryChange(); prepareGeometryChange();
QLineF line(mapFromItem(m_sourceNode, 0, 0) + m_sourceNode->boundingRect().center(), QLineF line(mapFromItem(m_sourceNode, 0, 0) +
mapFromItem(m_destNode, 0, 0) + m_destNode->boundingRect().center()); m_sourceNode->boundingRect().center(),
mapFromItem(m_destNode, 0, 0) +
m_destNode->boundingRect().center());
if (line.length() > qreal(20.)) { if (line.length() > qreal(20.)) {
m_sourcePoint = firstNotContainedPoint(line,m_sourceNode->sceneBoundingRect()); m_sourcePoint = firstNotContainedPoint(line,
m_destPoint = firstNotContainedPoint(line,m_destNode->sceneBoundingRect(),true); m_sourceNode->sceneBoundingRect());
m_destPoint = firstNotContainedPoint(line,
m_destNode->sceneBoundingRect(),true);
} else { } else {
m_sourcePoint = m_destPoint = line.p1(); 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(), return QRectF(m_sourcePoint, QSizeF(m_destPoint.x() - m_sourcePoint.x(),
m_destPoint.y() - m_sourcePoint.y())) m_destPoint.y() - m_sourcePoint.y()))
.normalized() .normalized().adjusted(-extra, -extra, extra, extra);
.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) if (!m_sourceNode || !m_destNode)
return; return;
@ -111,20 +116,28 @@ void Edge::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
return; return;
// Draw the line itself // 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); painter->drawLine(line);
if (line.length() < m_arrowSize) if (line.length() < m_arrowSize)
return; return;
// Draw the arrows // Draw the arrows
QPointF destArrowP1 = m_destPoint + QPointF(sin(m_angle - Pi / 3) * m_arrowSize, QPointF destArrowP1 = m_destPoint +
QPointF(sin(m_angle - Pi / 3) * m_arrowSize,
cos(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, QPointF destArrowP2 = m_destPoint +
QPointF(sin(m_angle - Pi + Pi / 3) * m_arrowSize,
cos(m_angle - Pi + Pi / 3) * m_arrowSize); cos(m_angle - Pi + Pi / 3) * m_arrowSize);
painter->setBrush(Qt::black); painter->setBrush(Qt::black);
painter->drawPolygon(QPolygonF() << line.p2() << destArrowP1 << destArrowP2); painter->drawPolygon(QPolygonF() << line.p2()
<< destArrowP1
<< destArrowP2);
} }
double Edge::getAngle() const double Edge::getAngle() const

@ -231,7 +231,6 @@ void GraphWidget::keyPressEvent(QKeyEvent *event)
dynamic_cast<MainWindow *>(m_parent)->getStatusBar()->showMessage( dynamic_cast<MainWindow *>(m_parent)->getStatusBar()->showMessage(
tr("No active node."), tr("No active node."),
5000); // millisec 5000); // millisec
} }
else else
{ {
@ -291,7 +290,7 @@ void GraphWidget::keyPressEvent(QKeyEvent *event)
if (m_edgeAdding) if (m_edgeAdding)
{ {
m_scene->addItem(new Edge(m_activeNode, m_hintNode)); addEdge(m_activeNode, m_hintNode);
m_edgeAdding = false; m_edgeAdding = false;
} }
if (m_edgeDeleting) if (m_edgeDeleting)
@ -341,8 +340,18 @@ void GraphWidget::keyPressEvent(QKeyEvent *event)
if (m_showingNodeNumbers) if (m_showingNodeNumbers)
{ {
m_showingNodeNumbers = false;
showingAllNodeNumbers(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 else
@ -352,6 +361,8 @@ void GraphWidget::keyPressEvent(QKeyEvent *event)
5000); // millisec 5000); // millisec
} }
break;
// add edge to active node // add edge to active node
case Qt::Key_A: case Qt::Key_A:
@ -378,7 +389,7 @@ void GraphWidget::keyPressEvent(QKeyEvent *event)
if (m_activeNode) if (m_activeNode)
{ {
dynamic_cast<MainWindow *>(m_parent)->getStatusBar()->showMessage( dynamic_cast<MainWindow *>(m_parent)->getStatusBar()->showMessage(
tr("Delete edge: select destination node"), tr("Delete edge: select other end-node"),
5000); // millisec 5000); // millisec
m_edgeDeleting = true; m_edgeDeleting = true;
@ -442,7 +453,6 @@ void GraphWidget::insertNode()
{ {
double angle(m_activeNode->calculateBiggestAngle()); double angle(m_activeNode->calculateBiggestAngle());
qreal length(100); qreal length(100);
QPointF pos(length * cos(angle), length * sin(angle)); QPointF pos(length * cos(angle), length * sin(angle));
@ -452,11 +462,10 @@ void GraphWidget::insertNode()
m_scene->addItem(node); m_scene->addItem(node);
node->setPos(m_activeNode->sceneBoundingRect().center() + node->setPos(m_activeNode->sceneBoundingRect().center() +
pos - pos -
node->boundingRect().center() node->boundingRect().center());
);
m_nodeList.append(node); m_nodeList.append(node);
m_scene->addItem(new Edge(m_activeNode, node)); addEdge(m_activeNode, node);
setActiveNode(node); setActiveNode(node);
setActiveNodeEditable(); setActiveNodeEditable();
@ -497,7 +506,7 @@ void GraphWidget::showingNodeNumbersBeginWithNumber(const int &number,
if (m_edgeAdding) if (m_edgeAdding)
{ {
m_scene->addItem(new Edge(m_activeNode, m_hintNode)); addEdge(m_activeNode, m_hintNode);
m_edgeAdding = false; m_edgeAdding = false;
} }
if (m_edgeDeleting) if (m_edgeDeleting)
@ -538,7 +547,7 @@ void GraphWidget::nodeSelected(Node *node)
{ {
if (m_edgeAdding) if (m_edgeAdding)
{ {
m_scene->addItem(new Edge(m_activeNode, node)); addEdge(m_activeNode, node);
m_edgeAdding = false; m_edgeAdding = false;
} }
if (m_edgeDeleting) if (m_edgeDeleting)
@ -551,3 +560,17 @@ void GraphWidget::nodeSelected(Node *node)
setActiveNode(node); setActiveNode(node);
} }
} }
void GraphWidget::addEdge(const Node *source, const Node *destination)
{
if (source->isConnected(destination))
{
dynamic_cast<MainWindow *>(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));
}
}

@ -37,6 +37,7 @@ private:
const bool &show = true); const bool &show = true);
bool numberStartsWithNumber(const int &number, const int &prefix); bool numberStartsWithNumber(const int &number, const int &prefix);
qreal calculateBiggestAngle(Node *node); qreal calculateBiggestAngle(Node *node);
void addEdge(const Node *source, const Node *destination);
QList<Node *> m_nodeList; QList<Node *> m_nodeList;
QWidget *m_parent; QWidget *m_parent;

@ -7,6 +7,8 @@
#include <QTextDocument> #include <QTextDocument>
static const double Pi = 3.14159265358979323846264338327950288419717; static const double Pi = 3.14159265358979323846264338327950288419717;
static double TwoPi = 2.0 * Pi;
static double OneAndHalfPi = 1.5 * Pi;
Node::Node(GraphWidget *parent) : Node::Node(GraphWidget *parent) :
m_graph(parent), m_graph(parent),
@ -20,12 +22,12 @@ Node::Node(GraphWidget *parent) :
setCacheMode(DeviceCoordinateCache); setCacheMode(DeviceCoordinateCache);
// shall I use system colors?
setDefaultTextColor(QColor(0,0,0)); setDefaultTextColor(QColor(0,0,0));
} }
Node::~Node() Node::~Node()
{ {
// dtor of Edge will call removeEdgeFromList on booth nodes.
foreach (EdgeElement element, m_edgeList) delete element.edge; foreach (EdgeElement element, m_edgeList) delete element.edge;
} }
@ -35,7 +37,7 @@ void Node::addEdge(Edge *edge, bool startsFromThisNode)
edge->adjust(); edge->adjust();
} }
void Node::removeEdge(Edge *edge) void Node::removeEdgeFromList(Edge *edge)
{ {
for(QList<EdgeElement>::iterator it = m_edgeList.begin(); for(QList<EdgeElement>::iterator it = m_edgeList.begin();
it != m_edgeList.end(); it++) it != m_edgeList.end(); it++)
@ -50,13 +52,13 @@ void Node::removeEdge(Edge *edge)
void Node::removeEdge(Node *otherEnd) void Node::removeEdge(Node *otherEnd)
{ {
qDebug() << __PRETTY_FUNCTION__;
for(QList<EdgeElement>::iterator it = m_edgeList.begin(); for(QList<EdgeElement>::iterator it = m_edgeList.begin();
it != m_edgeList.end(); it++) it != m_edgeList.end(); it++)
{ {
if ((it->edge->sourceNode() == otherEnd && it->edge->destNode() == this) if ((it->edge->sourceNode() == otherEnd &&
|| (it->edge->sourceNode() == this && it->edge->destNode() == otherEnd)) it->edge->destNode() == this)
|| (it->edge->sourceNode() == this &&
it->edge->destNode() == otherEnd))
{ {
delete it->edge; delete it->edge;
return; return;
@ -74,8 +76,11 @@ QVariant Node::itemChange(GraphicsItemChange change, const QVariant &value)
{ {
// value is the new position. // value is the new position.
QPointF newPos = value.toPointF(); QPointF newPos = value.toPointF();
// the fence is reduced with the size of the node
QRectF rect (scene()->sceneRect().topLeft(), QRectF rect (scene()->sceneRect().topLeft(),
scene()->sceneRect().bottomRight()-boundingRect().bottomRight()); scene()->sceneRect().bottomRight() -
boundingRect().bottomRight());
if (!rect.contains(newPos)) if (!rect.contains(newPos))
{ {
@ -98,28 +103,36 @@ QVariant Node::itemChange(GraphicsItemChange change, const QVariant &value)
return QGraphicsItem::itemChange(change, 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 // draw background in hint mode. num == -1 : not in hint mode
/// @bug is there a 1pixel wide yellow line at the bottom of borderless item? // if m_numberIsSpecial (can be selected with enter) bg is green, not yellow
if (m_number != -1) if (m_number != -1)
{ {
painter->setPen(Qt::transparent); painter->setPen(Qt::transparent);
painter->setBrush(m_numberIsSpecial ? Qt::green : Qt::yellow); 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(), painter->drawRect(QRect(boundingRect().topLeft().toPoint(),
boundingRect().bottomRight().toPoint())); boundingRect().bottomRight().toPoint()));
painter->setBrush(Qt::NoBrush); painter->setBrush(Qt::NoBrush);
} }
// the text itself
QGraphicsTextItem::paint(painter, option, w); QGraphicsTextItem::paint(painter, option, w);
painter->setPen(m_isActive ? Qt::red : Qt::blue);
if (m_hasBorder) if (m_hasBorder)
{
painter->setPen(m_isActive ? Qt::red : Qt::blue);
painter->drawRect(QRect(boundingRect().topLeft().toPoint(), painter->drawRect(QRect(boundingRect().topLeft().toPoint(),
boundingRect().bottomRight().toPoint() - boundingRect().bottomRight().toPoint() -
QPoint(1,1))); QPoint(1,1)));
}
// print num to topleft corner in hint mode.
if (m_number != -1) if (m_number != -1)
{ {
painter->setPen(Qt::white); painter->setPen(Qt::white);
@ -135,6 +148,7 @@ void Node::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWid
void Node::setActive(const bool &active) void Node::setActive(const bool &active)
{ {
m_isActive = active; m_isActive = active;
// update border color
update(); update();
} }
@ -180,7 +194,7 @@ void Node::setBorder(const bool &hasBorder)
double Node::calculateBiggestAngle() double Node::calculateBiggestAngle()
{ {
if (m_edgeList.empty()) if (m_edgeList.empty())
return 1.5 * Pi; return OneAndHalfPi;
if (m_edgeList.size()==1) if (m_edgeList.size()==1)
{ {
@ -190,7 +204,7 @@ double Node::calculateBiggestAngle()
} }
else 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 ? tmp.push_back(it->startsFromThisNode ?
it->edge->getAngle() : it->edge->getAngle() :
doubleModulo(Pi + it->edge->getAngle(), 2 * Pi)); doubleModulo(Pi + it->edge->getAngle(), TwoPi));
} }
qSort(tmp.begin(), tmp.end()); qSort(tmp.begin(), tmp.end());
double prev(tmp.first()); double prev(tmp.first());
double max_prev(tmp.last()); double max_prev(tmp.last());
double max(2 * Pi - tmp.last() + tmp.first()); double max(TwoPi - tmp.last() + tmp.first());
for(QList<double>::const_iterator it = ++tmp.begin(); it!=tmp.end(); it++) for(QList<double>::const_iterator it = ++tmp.begin(); it!=tmp.end(); it++)
{ {
@ -219,7 +232,7 @@ double Node::calculateBiggestAngle()
prev = *it; 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) 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) double Node::doubleModulo(const double &devided, const double &devisor)
{ {
return devided - static_cast<double>(devisor * static_cast<int>(devided / devisor)); return devided - static_cast<double>(devisor * static_cast<int>(devided
/ devisor));
} }
void Node::setEditable(const bool &editable) void Node::setEditable(const bool &editable)
{ {
qDebug() << __PRETTY_FUNCTION__;
setTextInteractionFlags( setTextInteractionFlags(
editable ? editable ?
Qt::TextEditable : Qt::TextEditable :
@ -290,10 +302,20 @@ void Node::keyPressEvent(QKeyEvent *event)
default: default:
// not cursor movement // not cursor movement: editing
QGraphicsTextItem::keyPressEvent(event); QGraphicsTextItem::keyPressEvent(event);
foreach (EdgeElement element, m_edgeList) element.edge->adjust(); foreach (EdgeElement element, m_edgeList) element.edge->adjust();
} }
///@note leaving editing mode is done with esc, handled by graphwidget ///@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;
}

@ -17,7 +17,7 @@ public:
~Node(); ~Node();
void addEdge(Edge *edge, bool startsFromThisNode); void addEdge(Edge *edge, bool startsFromThisNode);
void removeEdge(Edge *edge); void removeEdgeFromList(Edge *edge);
void removeEdge(Node *otherEnd); void removeEdge(Node *otherEnd);
void setBorder(const bool &hasBorder); void setBorder(const bool &hasBorder);
void setActive(const bool &active = true); void setActive(const bool &active = true);
@ -28,6 +28,7 @@ public:
// changing visibility from prot to pub // changing visibility from prot to pub
void keyPressEvent(QKeyEvent *event); void keyPressEvent(QKeyEvent *event);
bool isConnected(const Node *node) const;
protected: protected:

Loading…
Cancel
Save