diff options
-rw-r--r-- | databasemodel.cpp | 4 | ||||
-rw-r--r-- | databaserelationship.cpp | 116 | ||||
-rw-r--r-- | databaserelationship.h | 15 | ||||
-rw-r--r-- | dbmodel.pro | 1 | ||||
-rw-r--r-- | diagramconnection.cpp | 38 | ||||
-rw-r--r-- | diagramconnection.h | 43 | ||||
-rw-r--r-- | range.h | 68 |
7 files changed, 232 insertions, 53 deletions
diff --git a/databasemodel.cpp b/databasemodel.cpp index 4068ca5..d130402 100644 --- a/databasemodel.cpp +++ b/databasemodel.cpp @@ -214,8 +214,8 @@ DatabaseModel::save(const QString &fileName) foreach (DatabaseRelationship *relation, m_relations) { QDomElement relationElement = doc.createElement("relation"); - relationElement.setAttribute("from", QString::number(m_tables.indexOf(relation->source()))); - relationElement.setAttribute("to", QString::number(m_tables.indexOf(relation->target()))); + relationElement.setAttribute("from", QString::number(m_tables.indexOf(relation->sourceTable()))); + relationElement.setAttribute("to", QString::number(m_tables.indexOf(relation->targetTable()))); relationListElement.appendChild(relationElement); } diff --git a/databaserelationship.cpp b/databaserelationship.cpp index b114a4a..270d793 100644 --- a/databaserelationship.cpp +++ b/databaserelationship.cpp @@ -18,11 +18,13 @@ #include <QDebug> #include "databasetable.h" #include "databaserelationship.h" +#include "range.h" DatabaseRelationship::DatabaseRelationship(DiagramItem *parent) - : DiagramConnection(parent), m_source(0), m_target(0) + : DiagramConnection(parent) { setFlag(ItemIsSelectable); + connect(this, SIGNAL(endPointChanged()), this, SLOT(updateLayout())); } QRectF @@ -63,24 +65,6 @@ DatabaseRelationship::paint(QPainter *painter, const QStyleOptionGraphicsItem *o painter->drawPolygon(m_arrowHead); } -void -DatabaseRelationship::setSource(DatabaseTable *source) -{ - m_source = source; - if (scene()) { - updateLayout(); - } -} - -void -DatabaseRelationship::setTarget(DatabaseTable *target) -{ - m_target = target; - if (scene()) { - updateLayout(); - } -} - QVariant DatabaseRelationship::itemChange(GraphicsItemChange change, const QVariant &value) { @@ -102,37 +86,87 @@ DatabaseRelationship::updateLayout() if (!scene()) return; - prepareGeometryChange(); - - QRectF rect1 = m_source->boundingRect().translated(m_source->pos()); - QRectF rect2 = m_target->boundingRect().translated(m_target->pos()); + DatabaseTable *source = sourceTable(); + DatabaseTable *target = targetTable(); + if (!source || !target) + return; - QPointF p1 = rect1.center(); - QPointF p2 = rect2.center(); - m_line = QLineF(p1, p2); + prepareGeometryChange(); - QPolygonF polygon; + QRectF rect1 = source->boundingRect().translated(source->pos()); + QRectF rect2 = target->boundingRect().translated(target->pos()); + + bool haveLine = false; + + Range<qreal> verticalIntersection = + Range<qreal>(rect1.top(), rect1.bottom()).intersected( + Range<qreal>(rect2.top(), rect2.bottom())); + + Range<qreal> horizontalIntersection = + Range<qreal>(rect1.left(), rect1.right()).intersected( + Range<qreal>(rect2.left(), rect2.right())); + + // Straight horizontal line + if (!haveLine) { + if (!verticalIntersection.isNull() && horizontalIntersection.isNull()) { + qreal y = verticalIntersection.min() + verticalIntersection.length() / 2; + if (rect1.right() < rect2.left()) { + m_line = QLineF(rect1.right(), y, rect2.left(), y); + } + else { + m_line = QLineF(rect1.left(), y, rect2.right(), y); + } + haveLine = true; + } + } - polygon = rect1; - for (int i = 0; i < 4; i++) { - QLineF line(polygon[i], polygon[(i+1)%4]); - QPointF intersectionPoint; - if (m_line.intersect(line, &intersectionPoint) == QLineF::BoundedIntersection) { - m_line.setP1(intersectionPoint); - break; + // Straight vertical line + if (!haveLine) { + if (verticalIntersection.isNull() && !horizontalIntersection.isNull()) { + qreal x = horizontalIntersection.min() + horizontalIntersection.length() / 2; + if (rect1.bottom() < rect2.top()) { + m_line = QLineF(x, rect1.bottom(), x, rect2.top()); + } + else { + m_line = QLineF(x, rect1.top(), x, rect2.bottom()); + } + haveLine = true; } } - polygon = rect2; - for (int i = 0; i < 4; i++) { - QLineF line(polygon[i], polygon[(i+1)%4]); - QPointF intersectionPoint; - if (m_line.intersect(line, &intersectionPoint) == QLineF::BoundedIntersection) { - m_line.setP2(intersectionPoint); - break; + // Simple center<->center line + if (!haveLine) { + QPointF p1 = rect1.center(); + QPointF p2 = rect2.center(); + m_line = QLineF(p1, p2); + + QPolygonF polygon; + + polygon = rect1; + for (int i = 0; i < 4; i++) { + QLineF line(polygon[i], polygon[(i+1)%4]); + QPointF intersectionPoint; + if (m_line.intersect(line, &intersectionPoint) == QLineF::BoundedIntersection) { + m_line.setP1(intersectionPoint); + break; + } + } + + polygon = rect2; + for (int i = 0; i < 4; i++) { + QLineF line(polygon[i], polygon[(i+1)%4]); + QPointF intersectionPoint; + if (m_line.intersect(line, &intersectionPoint) == QLineF::BoundedIntersection) { + m_line.setP2(intersectionPoint); + break; + } } + + haveLine = true; } + Q_ASSERT(haveLine); + m_arrowHead.resize(3); m_arrowHead[0] = QPointF(0.0, 0.0); m_arrowHead[1] = QPointF(-4.5, 10.0); diff --git a/databaserelationship.h b/databaserelationship.h index b761e15..b2a7c3c 100644 --- a/databaserelationship.h +++ b/databaserelationship.h @@ -20,11 +20,12 @@ #include <QGraphicsItem> #include <QPainter> #include "diagramconnection.h" - -class DatabaseTable; +#include "databasetable.h" class DatabaseRelationship : public DiagramConnection { + Q_OBJECT + public: DatabaseRelationship(DiagramItem *parent = 0); @@ -32,11 +33,8 @@ public: QPainterPath shape() const; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); - DatabaseTable *source() { return m_source; } - void setSource(DatabaseTable *source); - - DatabaseTable *target() { return m_target; } - void setTarget(DatabaseTable *target); + DatabaseTable *sourceTable() { return qobject_cast<DatabaseTable *>(source()); } + DatabaseTable *targetTable() { return qobject_cast<DatabaseTable *>(target()); } enum { Type = DiagramItem::Relation }; virtual int type() const { return Type; } @@ -50,9 +48,6 @@ protected: QVariant itemChange(GraphicsItemChange change, const QVariant &value); private: - DatabaseTable *m_source; - DatabaseTable *m_target; - QLineF m_line; QPolygonF m_arrowHead; }; diff --git a/dbmodel.pro b/dbmodel.pro index db0cf76..7ed7baa 100644 --- a/dbmodel.pro +++ b/dbmodel.pro @@ -30,6 +30,7 @@ HEADERS = \ diagramitem.h \ diagramobject.h \ tableproperties.h \ + range.h \ commands.h RESOURCES = dbmodel.qrc FORMS = tableproperties.ui diff --git a/diagramconnection.cpp b/diagramconnection.cpp new file mode 100644 index 0000000..a996994 --- /dev/null +++ b/diagramconnection.cpp @@ -0,0 +1,38 @@ +// Copyright (C) 2008 Lukas Lalinsky +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +#include "diagramconnection.h" + +DiagramConnection::DiagramConnection(DiagramItem *parent) + : DiagramItem(parent) +{ + m_objects[0] = 0; + m_objects[1] = 0; +} + +void +DiagramConnection::setSource(DiagramObject *object) +{ + m_objects[0] = object; + emit endPointChanged(); +} + +void +DiagramConnection::setTarget(DiagramObject *object) +{ + m_objects[1] = object; + emit endPointChanged(); +} diff --git a/diagramconnection.h b/diagramconnection.h new file mode 100644 index 0000000..26810a7 --- /dev/null +++ b/diagramconnection.h @@ -0,0 +1,43 @@ +// Copyright (C) 2008 Lukas Lalinsky +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +#ifndef DIAGRAMCONNECTION_H +#define DIAGRAMCONNECTION_H + +#include "diagramitem.h" +class DiagramObject; + +class DiagramConnection : public DiagramItem +{ + Q_OBJECT + +public: + DiagramConnection(DiagramItem *parent = 0); + + DiagramObject *source() { return m_objects[0]; } + DiagramObject *target() { return m_objects[1]; } + + void setSource(DiagramObject *object); + void setTarget(DiagramObject *object); + +signals: + void endPointChanged(); + +private: + DiagramObject *m_objects[2]; +}; + +#endif @@ -0,0 +1,68 @@ +// Copyright (C) 2008 Lukas Lalinsky +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +#include <QDebug> + +template <class T> +class Range { +public: + Range() : m_min(0), m_max(0) {} + Range(T min, T max) + { + Q_ASSERT(min <= max); + m_min = min; + m_max = max; + } + + T min() const { return m_min; } + T max() const { return m_max; } + + bool isNull() const { return m_max == m_min; } + + T length() const { return m_max - m_min; } + + Range<T> intersected(const Range<T> &other) const + { + const Range<T> *a = this; + const Range<T> *b = &other; + + if (a->isNull()) return *a; + if (b->isNull()) return *b; + + if (a->min() > b->min()) + qSwap(a, b); + + if (a->max() < b->min()) + return Range<T>(); + + T p1 = b->min(); + T p2 = qMin(a->max(), b->max()); + + return Range<T>(p1, p2); + } + +private: + T m_min; + T m_max; +}; + + +template <class T> inline +QDebug operator<<(QDebug dbg, const Range<T> &r) +{ + dbg.nospace() << "Range(" << r.min() << ", " << r.max() << ")"; + return dbg.space(); +} |