summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--databasemodel.cpp4
-rw-r--r--databaserelationship.cpp116
-rw-r--r--databaserelationship.h15
-rw-r--r--dbmodel.pro1
-rw-r--r--diagramconnection.cpp38
-rw-r--r--diagramconnection.h43
-rw-r--r--range.h68
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
diff --git a/range.h b/range.h
new file mode 100644
index 0000000..e8622e2
--- /dev/null
+++ b/range.h
@@ -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();
+}