summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLukáš Lalinský <lalinsky@gmail.com>2008-12-07 01:05:09 +0100
committerLukáš Lalinský <lalinsky@gmail.com>2008-12-07 01:05:09 +0100
commit364531ec14761f07b22dbec6461376aad81159f6 (patch)
treed12861cb31805dfb551a9b1361a5c8513bbfd7a3 /src
parent67ee0e1c5b11cc2a4c70018f524c9ce00da30b60 (diff)
downloaddbmodel-364531ec14761f07b22dbec6461376aad81159f6.tar.xz
Move source code to src/ and add translation support
Diffstat (limited to 'src')
-rw-r--r--src/column.cpp68
-rw-r--r--src/column.h65
-rw-r--r--src/columnlist.cpp79
-rw-r--r--src/columnlist.h57
-rw-r--r--src/columnlistmodel.cpp208
-rw-r--r--src/columnlistmodel.h55
-rw-r--r--src/columnlistview.cpp103
-rw-r--r--src/columnlistview.h47
-rw-r--r--src/commands.cpp127
-rw-r--r--src/commands.h88
-rw-r--r--src/databaserelationship.cpp243
-rw-r--r--src/databaserelationship.h55
-rw-r--r--src/databasetable.cpp178
-rw-r--r--src/databasetable.h72
-rw-r--r--src/diagramconnection.cpp38
-rw-r--r--src/diagramconnection.h43
-rw-r--r--src/diagramdocument.cpp298
-rw-r--r--src/diagramdocument.h80
-rw-r--r--src/diagramitem.cpp22
-rw-r--r--src/diagramitem.h33
-rw-r--r--src/diagramobject.cpp22
-rw-r--r--src/diagramobject.h28
-rw-r--r--src/diagramview.cpp83
-rw-r--r--src/diagramview.h47
-rw-r--r--src/main.cpp35
-rw-r--r--src/mainwindow.cpp330
-rw-r--r--src/mainwindow.h78
-rw-r--r--src/range.h69
-rw-r--r--src/src.pro60
-rw-r--r--src/tableproperties.cpp96
-rw-r--r--src/tableproperties.h48
-rw-r--r--src/tableproperties.ui137
32 files changed, 2992 insertions, 0 deletions
diff --git a/src/column.cpp b/src/column.cpp
new file mode 100644
index 0000000..e8a355b
--- /dev/null
+++ b/src/column.cpp
@@ -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 "column.h"
+#include "columnlist.h"
+
+Column::Column(ColumnList *columnList)
+ : QObject(columnList), m_primaryKey(false), m_required(false)
+{
+}
+
+void
+Column::setName(const QString &name)
+{
+ if (m_name != name) {
+ m_name = name;
+ emit propertyChanged("name", name);
+ }
+}
+
+void
+Column::setNotes(const QString &notes)
+{
+ if (m_notes != notes) {
+ m_notes = notes;
+ emit propertyChanged("notes", notes);
+ }
+}
+
+void
+Column::setDataType(const QString &dataType)
+{
+ if (m_dataType != dataType) {
+ m_dataType = dataType;
+ emit propertyChanged("dataType", dataType);
+ }
+}
+
+void
+Column::setPrimaryKey(bool primaryKey)
+{
+ if (m_primaryKey != primaryKey) {
+ m_primaryKey = primaryKey;
+ emit propertyChanged("primaryKey", primaryKey);
+ }
+}
+
+void
+Column::setRequired(bool required)
+{
+ if (m_required != required) {
+ m_required = required;
+ emit propertyChanged("required", required);
+ }
+}
diff --git a/src/column.h b/src/column.h
new file mode 100644
index 0000000..2930efa
--- /dev/null
+++ b/src/column.h
@@ -0,0 +1,65 @@
+// 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 COLUMN_H
+#define COLUMN_H
+
+#include <QObject>
+#include <QString>
+#include "columnlist.h"
+
+class Column : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QString name READ name WRITE setName)
+ Q_PROPERTY(QString notes READ notes WRITE setNotes)
+ Q_PROPERTY(QString dataType READ dataType WRITE setDataType)
+ Q_PROPERTY(bool primaryKey READ isPrimaryKey WRITE setPrimaryKey)
+ Q_PROPERTY(bool required READ isRequired WRITE setRequired)
+
+public:
+
+ Column(ColumnList *columnList = 0);
+
+ ColumnList *columnList() const { return qobject_cast<ColumnList *>(parent()); }
+
+ QString name() const { return m_name; }
+ void setName(const QString &name);
+
+ QString notes() const { return m_notes; }
+ void setNotes(const QString &notes);
+
+ QString dataType() const { return m_dataType; }
+ void setDataType(const QString &dataType);
+
+ bool isPrimaryKey() const { return m_primaryKey; }
+ void setPrimaryKey(bool primaryKey);
+
+ bool isRequired() const { return m_required; }
+ void setRequired(bool required);
+
+signals:
+ void propertyChanged(const QString &name, const QVariant &value);
+
+private:
+ QString m_name;
+ QString m_notes;
+ QString m_dataType;
+ bool m_primaryKey;
+ bool m_required;
+};
+
+#endif
diff --git a/src/columnlist.cpp b/src/columnlist.cpp
new file mode 100644
index 0000000..b1ed623
--- /dev/null
+++ b/src/columnlist.cpp
@@ -0,0 +1,79 @@
+// 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>
+#include "columnlist.h"
+#include "column.h"
+#include "databasetable.h"
+
+ColumnList::ColumnList(DatabaseTable *table)
+ : QObject(table)
+{
+}
+
+int
+ColumnList::insertColumn(int index, Column *column)
+{
+ Q_ASSERT(m_columns.contains(column) == false);
+ column->setParent(this);
+ connect(column, SIGNAL(propertyChanged(const QString &, const QVariant &)), this, SLOT(updateColumn(const QString &, const QVariant &)));
+ emit columnAboutToBeInserted(index);
+ m_columns.insert(index, column);
+ emit columnInserted(index);
+ return index;
+}
+
+int
+ColumnList::appendColumn(Column *column)
+{
+ return insertColumn(columnCount(), column);
+}
+
+int
+ColumnList::removeColumn(Column *column)
+{
+ int index = m_columns.indexOf(column);
+ removeColumn(index);
+ return index;
+}
+
+Column *
+ColumnList::removeColumn(int index)
+{
+ emit columnAboutToBeRemoved(index);
+ Column *column = m_columns.takeAt(index);
+ emit columnRemoved(index);
+ disconnect(column, 0, this, 0);
+ column->setParent(0);
+ return column;
+}
+
+void
+ColumnList::swapColumns(int oldIndex, int newIndex)
+{
+ m_columns.move(oldIndex, newIndex);
+ emit columnChanged(oldIndex);
+ emit columnChanged(newIndex);
+}
+
+void
+ColumnList::updateColumn(const QString &, const QVariant &)
+{
+ Column *column = qobject_cast<Column *>(sender());
+ int index = m_columns.indexOf(column);
+ Q_ASSERT(index != -1);
+ emit columnChanged(index);
+}
diff --git a/src/columnlist.h b/src/columnlist.h
new file mode 100644
index 0000000..51a25be
--- /dev/null
+++ b/src/columnlist.h
@@ -0,0 +1,57 @@
+// 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 COLUMNLIST_H
+#define COLUMNLIST_H
+
+#include <QAbstractTableModel>
+#include "databasetable.h"
+class Column;
+
+class ColumnList : public QObject
+{
+ Q_OBJECT
+
+public:
+ ColumnList(DatabaseTable *table);
+
+ DatabaseTable *table() { return qobject_cast<DatabaseTable *>(parent()); }
+
+ QList<Column *> columns() { return m_columns; }
+ int columnCount() const { return m_columns.size(); }
+ int indexOf(Column *column) const { return m_columns.indexOf(column); }
+ Column *column(int index) { return m_columns[index]; }
+ int insertColumn(int, Column *);
+ int appendColumn(Column *);
+ void swapColumns(int, int);
+ int removeColumn(Column *);
+ Column *removeColumn(int);
+
+signals:
+ void columnAboutToBeInserted(int index);
+ void columnInserted(int index);
+ void columnAboutToBeRemoved(int index);
+ void columnRemoved(int index);
+ void columnChanged(int index);
+
+protected slots:
+ void updateColumn(const QString &name, const QVariant&);
+
+private:
+ QList<Column *> m_columns;
+};
+
+#endif
diff --git a/src/columnlistmodel.cpp b/src/columnlistmodel.cpp
new file mode 100644
index 0000000..5a282c8
--- /dev/null
+++ b/src/columnlistmodel.cpp
@@ -0,0 +1,208 @@
+// 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>
+#include "columnlistmodel.h"
+#include "diagramdocument.h"
+#include "databasetable.h"
+#include "commands.h"
+#include "column.h"
+#include "columnlist.h"
+
+#define COLUMN_COUNT 5
+
+ColumnListModel::ColumnListModel(QObject *parent)
+ : QAbstractTableModel(parent), m_columnList(0)
+{
+}
+
+void
+ColumnListModel::setColumnList(ColumnList *columnList)
+{
+ if (m_columnList) {
+ disconnect(m_columnList, 0, this, 0);
+ }
+ m_columnList = columnList;
+ if (m_columnList) {
+ connect(m_columnList, SIGNAL(columnAboutToBeInserted(int)), this, SLOT(_columnAboutToBeInserted(int)));
+ connect(m_columnList, SIGNAL(columnInserted(int)), this, SLOT(_columnInserted()));
+ connect(m_columnList, SIGNAL(columnAboutToBeRemoved(int)), this, SLOT(_columnAboutToBeRemoved(int)));
+ connect(m_columnList, SIGNAL(columnRemoved(int)), this, SLOT(_columnRemoved()));
+ connect(m_columnList, SIGNAL(columnChanged(int)), this, SLOT(_columnChanged(int)));
+ }
+ reset();
+}
+
+int
+ColumnListModel::rowCount(const QModelIndex &parent) const
+{
+ if (parent.isValid())
+ return 0;
+ return m_columnList ? m_columnList->columnCount() : 0;
+}
+
+int
+ColumnListModel::columnCount(const QModelIndex &parent) const
+{
+ if (parent.isValid())
+ return 0;
+ return COLUMN_COUNT;
+}
+
+QVariant
+ColumnListModel::data(const QModelIndex &index, int role) const
+{
+ if (m_columnList) {
+ Q_ASSERT(index.isValid());
+ Column *column = m_columnList->column(index.row());
+ if (role == Qt::DisplayRole || role == Qt::EditRole) {
+ if (index.column() == 0) {
+ return column->name();
+ }
+ if (index.column() == 1) {
+ return column->dataType();
+ }
+ if (index.column() == 4) {
+ return column->notes();
+ }
+ }
+ if (role == Qt::CheckStateRole) {
+ if (index.column() == 2) {
+ return column->isRequired() ? Qt::Checked : Qt::Unchecked;
+ }
+ if (index.column() == 3) {
+ return column->isPrimaryKey() ? Qt::Checked : Qt::Unchecked;
+ }
+ }
+ }
+ return QVariant();
+}
+
+bool
+ColumnListModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+ if (m_columnList) {
+ Q_ASSERT(index.isValid());
+ Column *column = m_columnList->column(index.row());
+ if (role == Qt::DisplayRole || role == Qt::EditRole) {
+ QString text = value.toString();
+ if (index.column() == 0) {
+ m_columnList->table()->model()->undoStack()->push(
+ new SetObjectPropertyCommand(column, "name", text));
+ goto OK;
+ }
+ if (index.column() == 1) {
+ m_columnList->table()->model()->undoStack()->push(
+ new SetObjectPropertyCommand(column, "dataType", text));
+ goto OK;
+ }
+ if (index.column() == 4) {
+ m_columnList->table()->model()->undoStack()->push(
+ new SetObjectPropertyCommand(column, "notes", text));
+ goto OK;
+ }
+ }
+ if (role == Qt::CheckStateRole) {
+ bool checked = value.toInt() == Qt::Checked ? true : false;
+ if (index.column() == 2) {
+ m_columnList->table()->model()->undoStack()->push(
+ new SetObjectPropertyCommand(column, "required", checked));
+ goto OK;
+ }
+ if (index.column() == 3) {
+ m_columnList->table()->model()->undoStack()->push(
+ new SetObjectPropertyCommand(column, "primaryKey", checked));
+ if (!column->isRequired()) {
+ // TODO is there a simple way to group this with the previous command?
+ m_columnList->table()->model()->undoStack()->push(
+ new SetObjectPropertyCommand(column, "required", true));
+ }
+ goto OK;
+ }
+ }
+ }
+ return false;
+OK:
+ emit dataChanged(createIndex(index.row(), 0), createIndex(index.row(), COLUMN_COUNT));
+ return true;
+}
+
+Qt::ItemFlags
+ColumnListModel::flags(const QModelIndex &index) const
+{
+ Q_ASSERT(index.isValid());
+ if (index.column() == 0 || index.column() == 1 || index.column() == 4) {
+ return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable;
+ }
+ if (index.column() == 2 || index.column() == 3) {
+ return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable;
+ }
+ return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
+}
+
+QVariant
+ColumnListModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ if (role == Qt::DisplayRole && orientation == Qt::Horizontal) {
+ if (section == 0)
+ return tr("Name");
+ if (section == 1)
+ return tr("Data Type");
+ if (section == 2)
+ return tr("Req'd");
+ if (section == 3)
+ return tr("PK");
+ if (section == 4)
+ return tr("Notes");
+ }
+ return QVariant();
+}
+
+QModelIndex
+ColumnListModel::indexFromRow(int i) const
+{
+ return createIndex(i, 0);
+}
+
+void
+ColumnListModel::_columnAboutToBeInserted(int index)
+{
+ beginInsertRows(QModelIndex(), index, index);
+}
+
+void
+ColumnListModel::_columnInserted()
+{
+ endInsertRows();
+}
+
+void
+ColumnListModel::_columnAboutToBeRemoved(int index)
+{
+ beginRemoveRows(QModelIndex(), index, index);
+}
+
+void
+ColumnListModel::_columnRemoved()
+{
+ endRemoveRows();
+}
+
+void
+ColumnListModel::_columnChanged(int index)
+{
+ emit dataChanged(createIndex(index, 0), createIndex(index, COLUMN_COUNT));
+}
diff --git a/src/columnlistmodel.h b/src/columnlistmodel.h
new file mode 100644
index 0000000..2944223
--- /dev/null
+++ b/src/columnlistmodel.h
@@ -0,0 +1,55 @@
+// 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 COLUMNLISTMODEL_H
+#define COLUMNLISTMODEL_H
+
+#include <QAbstractTableModel>
+class Column;
+class ColumnList;
+
+class ColumnListModel : public QAbstractTableModel
+{
+ Q_OBJECT
+
+public:
+ ColumnListModel(QObject *parent = 0);
+
+ ColumnList *columnList() { return m_columnList; }
+ void setColumnList(ColumnList *columnList);
+
+ // QAbstractItemModel methods
+ int rowCount(const QModelIndex &parent) const;
+ int columnCount(const QModelIndex &parent) const;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+ QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
+ Qt::ItemFlags flags(const QModelIndex &index) const;
+ bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
+
+ QModelIndex indexFromRow(int i) const;
+
+private slots:
+ void _columnAboutToBeInserted(int index);
+ void _columnInserted();
+ void _columnAboutToBeRemoved(int index);
+ void _columnRemoved();
+ void _columnChanged(int index);
+
+private:
+ ColumnList *m_columnList;
+};
+
+#endif
diff --git a/src/columnlistview.cpp b/src/columnlistview.cpp
new file mode 100644
index 0000000..dd73fb6
--- /dev/null
+++ b/src/columnlistview.cpp
@@ -0,0 +1,103 @@
+// 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 "columnlist.h"
+#include "columnlistmodel.h"
+#include "columnlistview.h"
+#include "commands.h"
+#include "diagramdocument.h"
+
+ColumnListView::ColumnListView(QWidget *parent)
+ : QTreeView(parent)
+{
+ setModel(new ColumnListModel(this));
+}
+
+void
+ColumnListView::setColumnList(ColumnList *columnList)
+{
+ columnListModel()->setColumnList(columnList);
+}
+
+void
+ColumnListView::addColumn()
+{
+ AddColumnCommand *command = new AddColumnCommand(columnList());
+ columnList()->table()->model()->undoStack()->push(command);
+ QModelIndex index = columnListModel()->indexFromRow(command->index());
+ setCurrentIndex(index);
+ edit(index);
+}
+
+void
+ColumnListView::removeColumn()
+{
+ QList<int> indexes = selectedColumns();
+ if (indexes.size() == 1) {
+ columnList()->table()->model()->undoStack()->push(
+ new RemoveColumnCommand(columnList(), indexes[0]));
+ }
+}
+
+void
+ColumnListView::moveColumnDown()
+{
+ QList<int> indexes = selectedColumns();
+ if (indexes.size() == 1) {
+ int i = indexes[0];
+ if (i + 1 < columnList()->columnCount()) {
+ columnList()->table()->model()->undoStack()->push(
+ new SwapColumnsCommand(columnList(), i, i + 1));
+ setCurrentIndex(columnListModel()->indexFromRow(i + 1));
+ }
+ }
+}
+
+void
+ColumnListView::moveColumnUp()
+{
+ QList<int> indexes = selectedColumns();
+ if (indexes.size() == 1) {
+ int i = indexes[0];
+ if (i > 0) {
+ columnList()->table()->model()->undoStack()->push(
+ new SwapColumnsCommand(columnList(), i, i - 1));
+ setCurrentIndex(columnListModel()->indexFromRow(i - 1));
+ }
+ }
+}
+
+QModelIndexList
+ColumnListView::selectedIndexes() const
+{
+ QModelIndexList indexes;
+ foreach (QModelIndex index, selectionModel()->selectedIndexes()) {
+ if (index.column() == 0) {
+ indexes << index;
+ }
+ }
+ return indexes;
+}
+
+QList<int>
+ColumnListView::selectedColumns() const
+{
+ QList<int> columns;
+ foreach (QModelIndex index, selectedIndexes()) {
+ columns << index.row();
+ }
+ return columns;
+}
diff --git a/src/columnlistview.h b/src/columnlistview.h
new file mode 100644
index 0000000..8e2bb47
--- /dev/null
+++ b/src/columnlistview.h
@@ -0,0 +1,47 @@
+// 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 COLUMNLISTVIEW_H
+#define COLUMNLISTVIEW_H
+
+#include <QTreeView>
+#include "columnlistmodel.h"
+
+class ColumnListView : public QTreeView
+{
+ Q_OBJECT
+
+public:
+ ColumnListView(QWidget *parent = 0);
+
+ void setColumnList(ColumnList *columnList);
+ ColumnListModel *columnListModel() { return qobject_cast<ColumnListModel *>(model()); }
+
+ ColumnList *columnList() { return columnListModel()->columnList(); }
+
+ QList<int> selectedColumns() const;
+
+public slots:
+ void addColumn();
+ void removeColumn();
+ void moveColumnUp();
+ void moveColumnDown();
+
+protected:
+ QModelIndexList selectedIndexes() const;
+};
+
+#endif
diff --git a/src/commands.cpp b/src/commands.cpp
new file mode 100644
index 0000000..ca23345
--- /dev/null
+++ b/src/commands.cpp
@@ -0,0 +1,127 @@
+// 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>
+#include "commands.h"
+#include "databasetable.h"
+#include "column.h"
+
+SetObjectPropertyCommand::SetObjectPropertyCommand(QObject *object, const char *name, const QVariant &value, QUndoCommand *parent)
+ : QUndoCommand(parent), m_object(object), m_name(name), m_newValue(value)
+{
+ m_oldValue = object->property(name);
+}
+
+void
+SetObjectPropertyCommand::redo()
+{
+ m_object->setProperty(m_name.latin1(), m_newValue);
+}
+
+void
+SetObjectPropertyCommand::undo()
+{
+ m_object->setProperty(m_name.latin1(), m_oldValue);
+}
+
+int
+SetObjectPropertyCommand::id() const
+{
+ return COMMAND_SET_OBJECT_PROPERTY;
+}
+
+bool
+SetObjectPropertyCommand::mergeWith(const QUndoCommand *o)
+{
+ return false;
+ Q_ASSERT(id() == o->id());
+ const SetObjectPropertyCommand *other = static_cast<const SetObjectPropertyCommand *>(o);
+ if (m_object != other->m_object || m_name != other->m_name)
+ return false;
+ m_newValue = other->m_newValue;
+ return true;
+}
+
+
+AddColumnCommand::AddColumnCommand(ColumnList *columnList, QUndoCommand *parent)
+ : QUndoCommand(parent), m_columnList(columnList)
+{
+ m_column = new Column();
+ m_index = columnList->columnCount();
+}
+
+AddColumnCommand::~AddColumnCommand()
+{
+ if (m_column)
+ delete m_column;
+}
+
+void
+AddColumnCommand::redo()
+{
+ m_columnList->insertColumn(m_index, m_column);
+ m_column = 0;
+}
+
+void
+AddColumnCommand::undo()
+{
+ m_column = m_columnList->removeColumn(m_index);
+}
+
+
+RemoveColumnCommand::RemoveColumnCommand(ColumnList *columnList, int index, QUndoCommand *parent)
+ : QUndoCommand(parent), m_columnList(columnList), m_index(index), m_column(0)
+{
+}
+
+RemoveColumnCommand::~RemoveColumnCommand()
+{
+ if (m_column)
+ delete m_column;
+}
+
+void
+RemoveColumnCommand::redo()
+{
+ m_column = m_columnList->removeColumn(m_index);
+}
+
+void
+RemoveColumnCommand::undo()
+{
+ Q_ASSERT(m_column != 0);
+ m_columnList->insertColumn(m_index, m_column);
+ m_column = 0;
+}
+
+
+SwapColumnsCommand::SwapColumnsCommand(ColumnList *columnList, int oldIndex, int newIndex, QUndoCommand *parent)
+ : QUndoCommand(parent), m_columnList(columnList), m_oldIndex(oldIndex), m_newIndex(newIndex)
+{
+}
+
+void
+SwapColumnsCommand::redo()
+{
+ m_columnList->swapColumns(m_oldIndex, m_newIndex);
+}
+
+void
+SwapColumnsCommand::undo()
+{
+ m_columnList->swapColumns(m_newIndex, m_oldIndex);
+}
diff --git a/src/commands.h b/src/commands.h
new file mode 100644
index 0000000..53fc947
--- /dev/null
+++ b/src/commands.h
@@ -0,0 +1,88 @@
+// 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 COMMANDS_H
+#define COMMANDS_H
+
+#include <QUndoCommand>
+#include <QVariant>
+#include <QLatin1String>
+
+class DatabaseTable;
+class Column;
+#include "column.h"
+
+enum {
+ COMMAND_SET_OBJECT_PROPERTY,
+};
+
+class SetObjectPropertyCommand : public QUndoCommand
+{
+public:
+ SetObjectPropertyCommand(QObject *object, const char *name, const QVariant &value, QUndoCommand *parent = 0);
+ void undo();
+ void redo();
+ int id() const;
+ bool mergeWith(const QUndoCommand *command);
+
+private:
+ QObject *m_object;
+ QLatin1String m_name;
+ QVariant m_oldValue, m_newValue;
+};
+
+class AddColumnCommand : public QUndoCommand
+{
+public:
+ AddColumnCommand(ColumnList *columnList, QUndoCommand *parent = 0);
+ ~AddColumnCommand();
+ void undo();
+ void redo();
+ int index() { return m_index; }
+
+private:
+ ColumnList *m_columnList;
+ int m_index;
+ Column *m_column;
+};
+
+class RemoveColumnCommand : public QUndoCommand
+{
+public:
+ RemoveColumnCommand(ColumnList *columnList, int index, QUndoCommand *parent = 0);
+ ~RemoveColumnCommand();
+ void undo();
+ void redo();
+
+private:
+ ColumnList *m_columnList;
+ int m_index;
+ Column *m_column;
+};
+
+class SwapColumnsCommand : public QUndoCommand
+{
+public:
+ SwapColumnsCommand(ColumnList *columnList, int oldIndex, int newIndex, QUndoCommand *parent = 0);
+ void undo();
+ void redo();
+
+private:
+ ColumnList *m_columnList;
+ int m_oldIndex, m_newIndex;
+};
+
+#endif
diff --git a/src/databaserelationship.cpp b/src/databaserelationship.cpp
new file mode 100644
index 0000000..d7c3dd1
--- /dev/null
+++ b/src/databaserelationship.cpp
@@ -0,0 +1,243 @@
+// 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 <QGraphicsScene>
+#include <QDebug>
+#include "databasetable.h"
+#include "databaserelationship.h"
+#include "range.h"
+
+DatabaseRelationship::DatabaseRelationship(DiagramItem *parent)
+ : DiagramConnection(parent)
+{
+ setFlag(ItemIsSelectable);
+ connect(this, SIGNAL(endPointChanged()), this, SLOT(updateLayout()));
+}
+
+QRectF
+DatabaseRelationship::boundingRect() const
+{
+ return shape().boundingRect();
+ //return QRectF(m_line.p1(), m_line.p2()).normalized();
+}
+
+QPainterPath
+DatabaseRelationship::shape() const
+{
+ QPainterPath path;
+ if (m_line.isEmpty())
+ return path;
+ path.moveTo(m_line[0]);
+ for (int i = 1; i < m_line.size(); i++)
+ path.lineTo(m_line[i]);
+ path.addPolygon(m_arrowHead);
+ QPen pen(QPen(QColor(0, 0, 0), 1));
+ pen.setJoinStyle(Qt::MiterJoin);
+ QPainterPathStroker ps;
+ ps.setCapStyle(pen.capStyle());
+ ps.setWidth(pen.widthF() + 0.3);
+ ps.setJoinStyle(pen.joinStyle());
+ ps.setMiterLimit(pen.miterLimit());
+ return ps.createStroke(path);
+}
+
+void
+DatabaseRelationship::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
+{
+ Q_UNUSED(option);
+ Q_UNUSED(widget);
+
+ QPen pen(QPen(QColor(0, 0, 0), 1));
+ pen.setJoinStyle(Qt::MiterJoin);
+ painter->setPen(pen);
+ painter->drawPolyline(m_line);
+ painter->setBrush(pen.color());
+ painter->drawPolygon(m_arrowHead);
+}
+
+QVariant
+DatabaseRelationship::itemChange(GraphicsItemChange change, const QVariant &value)
+{
+ if (change == ItemSceneHasChanged) {
+ updateLayout();
+ }
+ return QGraphicsItem::itemChange(change, value);
+}
+
+void
+DatabaseRelationship::updatePositions()
+{
+ updateLayout();
+}
+
+void
+DatabaseRelationship::updateLayout()
+{
+ if (!scene())
+ return;
+
+ DatabaseTable *source = sourceTable();
+ DatabaseTable *target = targetTable();
+ if (!source || !target)
+ return;
+
+ prepareGeometryChange();
+
+ QRectF rect1 = source->boundingRect().translated(source->pos());
+ QRectF rect2 = target->boundingRect().translated(target->pos());
+
+ bool haveLine = false;
+
+ Range<qreal> verticalRange1(rect1.top(), rect1.bottom());
+ Range<qreal> verticalRange2(rect2.top(), rect2.bottom());
+ Range<qreal> verticalIntersection = verticalRange1.intersected(verticalRange2);
+
+ Range<qreal> horizontalRange1(rect1.left(), rect1.right());
+ Range<qreal> horizontalRange2(rect2.left(), rect2.right());
+ Range<qreal> horizontalIntersection = horizontalRange1.intersected(horizontalRange2);
+
+ // Straight horizontal line
+ if (!haveLine) {
+ if (!verticalIntersection.isNull() && horizontalIntersection.isNull()) {
+ qreal y = verticalIntersection.min() + verticalIntersection.length() / 2;
+ if (rect1.right() < rect2.left()) {
+ m_line = QPolygonF() << QPointF(rect1.right(), y) << QPointF(rect2.left(), y);
+ }
+ else {
+ m_line = QPolygonF() << QPointF(rect1.left(), y) << QPointF(rect2.right(), y);
+ }
+ haveLine = true;
+ }
+ }
+
+ // Straight vertical line
+ if (!haveLine) {
+ if (verticalIntersection.isNull() && !horizontalIntersection.isNull()) {
+ qreal x = horizontalIntersection.min() + horizontalIntersection.length() / 2;
+ if (rect1.bottom() < rect2.top()) {
+ m_line = QPolygonF() << QPointF(x, rect1.bottom()) << QPointF(x, rect2.top());
+ }
+ else {
+ m_line = QPolygonF() << QPointF(x, rect1.top()) << QPointF(x, rect2.bottom());
+ }
+ haveLine = true;
+ }
+ }
+
+ // Two-segment line
+ if (!haveLine) {
+
+ qreal x1, x2, x3, y1, y2, y3;
+
+ if (rect1.right() < rect2.left()) {
+ x1 = rect1.right();
+ y1 = verticalRange1.center();
+
+ x2 = horizontalRange2.center();
+ y2 = verticalRange1.center();
+
+ if (rect1.bottom() < rect2.top()) {
+ x3 = horizontalRange2.center();
+ y3 = rect2.top();
+ }
+ else {
+ x3 = horizontalRange2.center();
+ y3 = rect2.bottom();
+ }
+ }
+ else {
+ x1 = rect1.left();
+ y1 = verticalRange1.center();
+
+ x2 = horizontalRange2.center();
+ y2 = verticalRange1.center();
+
+ if (rect1.bottom() < rect2.top()) {
+ x3 = horizontalRange2.center();
+ y3 = rect2.top();
+ }
+ else {
+ x3 = horizontalRange2.center();
+ y3 = rect2.bottom();
+ }
+ }
+
+ m_line = QPolygonF()
+ << QPointF(x1, y1)
+ << QPointF(x2, y2)
+ << QPointF(x3, y3);
+ haveLine = true;
+
+
+/*
+ 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;
+ }*/
+ }
+
+ // Simple center<->center line
+ if (!haveLine) {
+ QPointF p1 = rect1.center();
+ QPointF p2 = rect2.center();
+ QLineF finalLine = 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 (finalLine.intersect(line, &intersectionPoint) == QLineF::BoundedIntersection) {
+ finalLine.setP1(intersectionPoint);
+ break;
+ }
+ }
+
+ polygon = rect2;
+ for (int i = 0; i < 4; i++) {
+ QLineF line(polygon[i], polygon[(i+1)%4]);
+ QPointF intersectionPoint;
+ if (finalLine.intersect(line, &intersectionPoint) == QLineF::BoundedIntersection) {
+ finalLine.setP2(intersectionPoint);
+ break;
+ }
+ }
+
+ m_line = QPolygonF() << finalLine.p1() << finalLine.p2();
+ haveLine = true;
+ }
+
+ Q_ASSERT(haveLine);
+
+ int size = m_line.size();
+ QLineF lastSegment(m_line[size-2], m_line[size-1]);
+
+ m_arrowHead.resize(3);
+ m_arrowHead[0] = QPointF(0.0, 0.0);
+ m_arrowHead[1] = QPointF(-4.5, 10.0);
+ m_arrowHead[2] = QPointF(4.5, 10.0);
+ QMatrix matrix;
+ matrix.rotate(-lastSegment.angle() + 90);
+ m_arrowHead = matrix.map(m_arrowHead);
+ m_arrowHead.translate(lastSegment.p2());
+}
diff --git a/src/databaserelationship.h b/src/databaserelationship.h
new file mode 100644
index 0000000..f0edd68
--- /dev/null
+++ b/src/databaserelationship.h
@@ -0,0 +1,55 @@
+// 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 DATABASERELATION_H
+#define DATABASERELATION_H
+
+#include <QGraphicsItem>
+#include <QPainter>
+#include "diagramconnection.h"
+#include "databasetable.h"
+
+class DatabaseRelationship : public DiagramConnection
+{
+ Q_OBJECT
+
+public:
+ DatabaseRelationship(DiagramItem *parent = 0);
+
+ QRectF boundingRect() const;
+ QPainterPath shape() const;
+ void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0);
+
+ DatabaseTable *sourceTable() { return qobject_cast<DatabaseTable *>(source()); }
+ DatabaseTable *targetTable() { return qobject_cast<DatabaseTable *>(target()); }
+
+ enum { Type = DiagramItem::Relation };
+ virtual int type() const { return Type; }
+
+ void updatePositions();
+
+protected slots:
+ void updateLayout();
+
+protected:
+ QVariant itemChange(GraphicsItemChange change, const QVariant &value);
+
+private:
+ QPolygonF m_line;
+ QPolygonF m_arrowHead;
+};
+
+#endif
diff --git a/src/databasetable.cpp b/src/databasetable.cpp
new file mode 100644
index 0000000..968a3f2
--- /dev/null
+++ b/src/databasetable.cpp
@@ -0,0 +1,178 @@
+// 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 <QGraphicsScene>
+#include <QDebug>
+#include "databasetable.h"
+#include "diagramdocument.h"
+#include "column.h"
+#include "columnlist.h"
+
+DatabaseTable::DatabaseTable(DiagramItem *parent)
+ : DiagramObject(parent)
+{
+ setFlag(ItemIsMovable);
+ setFlag(ItemIsSelectable);
+ m_name = "Table";
+ m_columnList = new ColumnList(this);
+ connect(m_columnList, SIGNAL(columnInserted(int)), this, SLOT(updateLayout()));
+ connect(m_columnList, SIGNAL(columnRemoved(int)), this, SLOT(updateLayout()));
+ connect(m_columnList, SIGNAL(columnChanged(int)), this, SLOT(updateLayout()));
+}
+
+DiagramDocument *
+DatabaseTable::model() const
+{
+ return qobject_cast<DiagramDocument *>(scene());
+}
+
+QRectF
+DatabaseTable::boundingRect() const
+{
+ return m_outerRect;
+}
+
+void
+DatabaseTable::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
+{
+ Q_UNUSED(option);
+ Q_UNUSED(widget);
+
+ QFont font = scene()->font();
+ QFont boldFont = font;
+ boldFont.setBold(true);
+ QFont boldFontWithUnderline = boldFont;
+ boldFontWithUnderline.setUnderline(true);
+
+ QPen pen(QPen(QColor(0, 0, 0)));
+ pen.setJoinStyle(Qt::MiterJoin);
+ QPen borderPen(pen);
+ if (isSelected()) {
+ borderPen.setColor(QColor(0, 96, 255));
+ borderPen.setWidth(2);
+ }
+
+ painter->setPen(pen);
+ painter->setFont(font);
+
+ painter->fillRect(m_outerRect, QColor(255, 255, 255));
+
+ // Draw the table name
+ painter->fillRect(m_nameBgRect, QColor(205, 205, 205));
+ painter->drawLine(m_nameBgRect.bottomLeft(), m_nameBgRect.bottomRight());
+ painter->drawText(m_namePos, m_name);
+
+ painter->drawLine(
+ m_leftSideWidth, m_nameBgRect.bottom(),
+ m_leftSideWidth, m_outerRect.bottom());
+
+ // Draw the table name
+ QPointF colPos = m_firstColPos;
+ QPointF leftSizePos = colPos - QPointF(m_leftSideWidth, 0);
+ foreach (Column *column, m_columnList->columns()) {
+ painter->setFont(column->isRequired()
+ ? (column->isPrimaryKey() ? boldFontWithUnderline : boldFont)
+ : font);
+ painter->drawText(colPos, column->name());
+ if (column->isPrimaryKey()) {
+ painter->setFont(column->isRequired() ? boldFont : font);
+ painter->drawText(leftSizePos, "PK");
+ }
+ colPos += m_colPosIncrement;
+ leftSizePos += m_colPosIncrement;
+ }
+
+ // Draw the outside border
+ painter->setPen(borderPen);
+ painter->drawRect(m_outerRect);
+}
+
+void
+DatabaseTable::setName(const QString &name)
+{
+ m_name = name;
+ updateLayout();
+ emit propertyChanged("name", name);
+}
+
+QVariant
+DatabaseTable::itemChange(GraphicsItemChange change, const QVariant &value)
+{
+ if (change == ItemSceneHasChanged) {
+ updateLayout();
+ }
+ if (change == ItemPositionChange) {
+ DiagramDocument *model = qobject_cast<DiagramDocument *>(scene());
+ if (model) {
+ emit model->tableMoved(this);
+ }
+ }
+ return QGraphicsItem::itemChange(change, value);
+}
+
+void
+DatabaseTable::updateLayout()
+{
+ if (!scene())
+ return;
+
+ prepareGeometryChange();
+
+ QFont font = scene()->font();
+ QFontMetricsF fontMetrics(font);
+
+ QFont boldFont = font;
+ boldFont.setBold(true);
+ QFontMetricsF boldFontMetrics(boldFont);
+
+ qreal spaceWidth = fontMetrics.width(' ');
+ qreal nameWidth = fontMetrics.width(m_name);
+ qreal height = fontMetrics.height();
+
+ m_leftSideWidth = fontMetrics.width("PK");
+
+ qreal width = nameWidth + spaceWidth * 2;
+
+ qreal maxColumnWidth = 0;
+ foreach (Column *column, m_columnList->columns()) {
+ qreal columnWidth = column->isRequired() ? boldFontMetrics.width(column->name()) : fontMetrics.width(column->name());
+ maxColumnWidth = qMax(maxColumnWidth, columnWidth);
+ qreal columnLeftSideWidth = 0;
+ if (column->isPrimaryKey()) {
+ if (column->isRequired()) {
+ columnLeftSideWidth = boldFontMetrics.width("PK");
+ }
+ else {
+ columnLeftSideWidth = fontMetrics.width("PK");
+ }
+ }
+ m_leftSideWidth = qMax(m_leftSideWidth, columnLeftSideWidth);
+ }
+ m_leftSideWidth += spaceWidth * 2;
+ width = qMax(nameWidth + spaceWidth * 4, m_leftSideWidth + maxColumnWidth + spaceWidth * 2);
+
+ qreal nameHeight = height + spaceWidth;
+ m_outerRect = QRectF(0, 0, width, nameHeight + qMax(0.66, qreal(m_columnList->columnCount())) * fontMetrics.lineSpacing()
+ - fontMetrics.leading() + fontMetrics.descent());
+
+ m_nameBgRect = QRectF(0, 0, width, nameHeight);
+ m_namePos = QPointF((width - nameWidth) / 2, fontMetrics.ascent() + spaceWidth / 2);
+
+ m_firstColPos = QPointF(m_leftSideWidth + spaceWidth * 1 - 1, nameHeight + fontMetrics.ascent() + 2);
+ m_colPosIncrement = QPointF(0, fontMetrics.lineSpacing());
+
+ update();
+}
diff --git a/src/databasetable.h b/src/databasetable.h
new file mode 100644
index 0000000..5765a97
--- /dev/null
+++ b/src/databasetable.h
@@ -0,0 +1,72 @@
+// 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 DATABASETABLE_H
+#define DATABASETABLE_H
+
+#include <QGraphicsItem>
+#include <QPainter>
+#include "diagramobject.h"
+
+class Column;
+class ColumnList;
+class DiagramDocument;
+
+class DatabaseTable : public DiagramObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QString name READ name WRITE setName)
+
+public:
+ DatabaseTable(DiagramItem *parent = 0);
+
+ DiagramDocument *model() const;
+
+ QRectF boundingRect() const;
+ void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0);
+
+ QString name() const { return m_name; }
+ void setName(const QString &name);
+
+ ColumnList *columnList() { return m_columnList; }
+
+// void setColumn(int index, const QString &name);
+// void removeColumn(int index);
+// Column *addColumn(const QString &name = QString());
+// void swapColumns(int index1, int index2);
+
+ enum { Type = DiagramItem::Table };
+ virtual int type() const { return Type; }
+
+signals:
+ void propertyChanged(const QString &name, const QVariant &value);
+
+protected slots:
+ void updateLayout();
+
+protected:
+ QVariant itemChange(GraphicsItemChange change, const QVariant &value);
+
+private:
+ QString m_name;
+ ColumnList *m_columnList;
+
+ QRectF m_outerRect, m_nameBgRect;
+ QPointF m_namePos, m_firstColPos, m_colPosIncrement;
+ qreal m_leftSideWidth;
+};
+
+#endif
diff --git a/src/diagramconnection.cpp b/src/diagramconnection.cpp
new file mode 100644
index 0000000..a996994
--- /dev/null
+++ b/src/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/src/diagramconnection.h b/src/diagramconnection.h
new file mode 100644
index 0000000..26810a7
--- /dev/null
+++ b/src/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/src/diagramdocument.cpp b/src/diagramdocument.cpp
new file mode 100644
index 0000000..573d08c
--- /dev/null
+++ b/src/diagramdocument.cpp
@@ -0,0 +1,298 @@
+// 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 "diagramdocument.h"
+#include "databasetable.h"
+#include "databaserelationship.h"
+#include "column.h"
+#include <QGraphicsItem>
+#include <QDebug>
+#include <QFile>
+#include <QTextStream>
+
+DiagramDocument::DiagramDocument(QObject *parent)
+ : QGraphicsScene(parent), m_mode(DiagramDocument::Select), m_line(NULL)
+{
+ m_undoStack = new QUndoStack(this);
+ connect(this, SIGNAL(tableMoved(DatabaseTable *)), SLOT(updatePositions(DatabaseTable *)));
+}
+
+DiagramDocument::Mode
+DiagramDocument::mode()
+{
+ return m_mode;
+}
+
+void
+DiagramDocument::setMode(Mode mode)
+{
+ m_mode = mode;
+ emit modeChanged(mode);
+}
+
+void
+DiagramDocument::updatePositions(DatabaseTable *table)
+{
+ foreach (DatabaseRelationship *relation, findTableRelations(table)) {
+ relation->updatePositions();
+ }
+}
+
+void
+DiagramDocument::mousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ if (m_mode == AddTable && event->button() == Qt::LeftButton) {
+ DatabaseTable *table = new DatabaseTable();
+ table->setPos(event->scenePos());
+ table->setZValue(10.0);
+ m_tables << table;
+ addItem(table);
+ clearSelection();
+ table->setSelected(true);
+ setMode(Select);
+ event->accept();
+ return;
+ }
+ if (m_mode == AddRelation && event->button() == Qt::LeftButton) {
+ m_line = new QGraphicsLineItem();
+ m_line->setLine(QLineF(event->scenePos(), event->scenePos()));
+ m_line->setZValue(1000.0);
+ addItem(m_line);
+ event->accept();
+ return;
+ }
+ QGraphicsScene::mousePressEvent(event);
+}
+
+void
+DiagramDocument::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
+{
+ if (m_line) {
+ m_line->setLine(QLineF(m_line->line().p1(), event->scenePos()));
+ event->accept();
+ return;
+ }
+ QGraphicsScene::mouseMoveEvent(event);
+}
+
+void
+DiagramDocument::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+{
+ if (m_line) {
+ removeItem(m_line);
+ DatabaseTable *source = qgraphicsitem_cast<DatabaseTable *>(itemAt(m_line->line().p1()));
+ DatabaseTable *target = qgraphicsitem_cast<DatabaseTable *>(itemAt(m_line->line().p2()));
+ if (source && target && source != target) {
+ //qDebug() << "Add relation between " << source << " and " << target;
+ DatabaseRelationship *relation = new DatabaseRelationship();
+ relation->setSource(source);
+ relation->setTarget(target);
+ relation->setZValue(1.0);
+ addItem(relation);
+ m_relations << relation;
+ }
+
+ delete m_line;
+ m_line = NULL;
+ setMode(Select);
+ event->accept();
+ return;
+ }
+ QGraphicsScene::mouseReleaseEvent(event);
+}
+
+DatabaseTable *
+DiagramDocument::selectedTable()
+{
+ QList<QGraphicsItem *> items = selectedItems();
+ if (items.size() != 1)
+ return NULL;
+ return qgraphicsitem_cast<DatabaseTable *>(items[0]);
+}
+
+void
+DiagramDocument::deleteSelectedItems()
+{
+ foreach (QGraphicsItem *item, selectedItems()) {
+ DatabaseTable *table = qgraphicsitem_cast<DatabaseTable *>(item);
+ if (table) {
+ foreach (DatabaseRelationship *relation, findTableRelations(table)) {
+ removeItem(relation);
+ m_relations.removeAll(relation);
+ }
+ removeItem(table);
+ m_tables.removeAll(table);
+ }
+ }
+}
+
+QList<DatabaseRelationship *>
+DiagramDocument::findTableRelations(DatabaseTable *table)
+{
+ QList<DatabaseRelationship *> result;
+ foreach (DatabaseRelationship *relation, m_relations) {
+ if (relation->source() == table || relation->target() == table) {
+ result << relation;
+ }
+ }
+ return result;
+}
+
+void
+appendStringElement(QDomDocument &doc, QDomElement &parent, const QString &name, const QString &value)
+{
+ if (!value.isEmpty()) {
+ QDomElement element = doc.createElement(name);
+ element.appendChild(doc.createTextNode(value));
+ parent.appendChild(element);
+ }
+}
+
+QString
+readStringElement(QDomElement &parent, const QString &name, const QString &defaultValue = QString())
+{
+ QDomElement element = parent.firstChildElement(name);
+ if (!element.isNull()) {
+ return element.text();
+ }
+ return defaultValue;
+}
+
+void
+DiagramDocument::save(const QString &fileName)
+{
+ QDomDocument doc;
+
+ QDomElement root = doc.createElement("database-model");
+ doc.appendChild(root);
+
+ QDomElement tableListElement = doc.createElement("table-list");
+ root.appendChild(tableListElement);
+
+ foreach (DatabaseTable *table, m_tables) {
+ QDomElement tableElement = doc.createElement("table");
+ tableListElement.appendChild(tableElement);
+
+ QDomElement positionElement = doc.createElement("position");
+ positionElement.setAttribute("x", table->pos().x());
+ positionElement.setAttribute("y", table->pos().y());
+ tableElement.appendChild(positionElement);
+
+ QDomElement nameElement = doc.createElement("name");
+ nameElement.appendChild(doc.createTextNode(table->name()));
+ tableElement.appendChild(nameElement);
+
+ QDomElement columnListElement = doc.createElement("column-list");
+ tableElement.appendChild(columnListElement);
+
+ foreach (Column *column, table->columnList()->columns()) {
+ QDomElement columnElement = doc.createElement("column");
+ columnListElement.appendChild(columnElement);
+ appendStringElement(doc, columnElement, "name", column->name());
+ appendStringElement(doc, columnElement, "data-type", column->dataType());
+ appendStringElement(doc, columnElement, "required", column->isRequired() ? "yes" : QString());
+ appendStringElement(doc, columnElement, "primary-key", column->isPrimaryKey() ? "yes" : QString());
+ appendStringElement(doc, columnElement, "notes", column->notes());
+ }
+ }
+
+ QDomElement relationListElement = doc.createElement("relation-list");
+ root.appendChild(relationListElement);
+
+ foreach (DatabaseRelationship *relation, m_relations) {
+ QDomElement relationElement = doc.createElement("relation");
+ relationElement.setAttribute("from", QString::number(m_tables.indexOf(relation->sourceTable())));
+ relationElement.setAttribute("to", QString::number(m_tables.indexOf(relation->targetTable())));
+ relationListElement.appendChild(relationElement);
+ }
+
+ QFile file(fileName);
+ if (file.open(QIODevice::WriteOnly)) {
+ QTextStream stream(&file);
+ doc.save(stream, 0);
+ file.close();
+ }
+
+ setFileName(fileName);
+}
+
+void
+DiagramDocument::load(const QString &fileName)
+{
+ QDomDocument doc;
+ QFile file(fileName);
+ if (file.open(QIODevice::ReadOnly)) {
+ doc.setContent(&file);
+ file.close();
+ }
+
+ setFileName(fileName);
+
+ QDomElement root = doc.firstChildElement("database-model");
+
+ QDomElement tableListElement = root.firstChildElement("table-list");
+ QDomElement tableElement = tableListElement.firstChildElement("table");
+ while (!tableElement.isNull()) {
+ DatabaseTable *table = new DatabaseTable;
+
+ QDomElement positionElement = tableElement.firstChildElement("position");
+ if (!positionElement.isNull()) {
+ QPoint pos;
+ pos.setX(positionElement.attribute("x", "0").toInt());
+ pos.setY(positionElement.attribute("y", "0").toInt());
+ table->setPos(pos);
+ }
+
+ table->setName(readStringElement(tableElement, "name"));
+
+ QDomElement columnListElement = tableElement.firstChildElement("column-list");
+ QDomElement columnElement = columnListElement.firstChildElement("column");
+ while (!columnElement.isNull()) {
+ Column *column = new Column();
+ column->setName(readStringElement(columnElement, "name"));
+ column->setDataType(readStringElement(columnElement, "data-type"));
+ column->setRequired(readStringElement(columnElement, "required") == "yes");
+ column->setPrimaryKey(readStringElement(columnElement, "primary-key") == "yes");
+ column->setNotes(readStringElement(columnElement, "notes"));
+ table->columnList()->appendColumn(column);
+ columnElement = columnElement.nextSiblingElement("column");
+ }
+
+ m_tables << table;
+ addItem(table);
+
+ tableElement = tableElement.nextSiblingElement("table");
+ }
+
+ QDomElement relationListElement = root.firstChildElement("relation-list");
+ QDomElement relationElement = relationListElement.firstChildElement("relation");
+ while (!relationElement.isNull()) {
+ relationElement = relationElement.nextSiblingElement("relation");
+ bool ok;
+ int index0 = relationElement.attribute("from").toInt(&ok);
+ if (ok) {
+ int index1 = relationElement.attribute("to").toInt(&ok);
+ if (ok) {
+ DatabaseRelationship *relation = new DatabaseRelationship();
+ relation->setSource(m_tables[index0]);
+ relation->setTarget(m_tables[index1]);
+ m_relations << relation;
+ addItem(relation);
+ }
+ }
+ }
+
+}
diff --git a/src/diagramdocument.h b/src/diagramdocument.h
new file mode 100644
index 0000000..b7890f6
--- /dev/null
+++ b/src/diagramdocument.h
@@ -0,0 +1,80 @@
+// 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 DATABASEMODEL_H
+#define DATABASEMODEL_H
+
+#include <QUndoStack>
+#include <QGraphicsScene>
+#include <QGraphicsSceneMouseEvent>
+#include <QDomDocument>
+#include <QGraphicsLineItem>
+
+class DatabaseTable;
+class DatabaseRelationship;
+
+class DiagramDocument : public QGraphicsScene
+{
+ Q_OBJECT
+
+public:
+ DiagramDocument(QObject *parent = 0);
+
+ enum Mode {
+ Select = 0,
+ AddTable,
+ AddRelation
+ };
+
+ Mode mode();
+ void setMode(Mode mode);
+
+ DatabaseTable *selectedTable();
+ void deleteSelectedItems();
+ QList<DatabaseRelationship *> findTableRelations(DatabaseTable *table);
+
+ void save(const QString &fileName);
+ void load(const QString &fileName);
+
+ QString fileName() { return m_fileName; }
+ void setFileName(const QString &fileName) { m_fileName = fileName; }
+
+ QUndoStack *undoStack() const { return m_undoStack; }
+
+signals:
+ void modeChanged(DiagramDocument::Mode mode);
+ void tableMoved(DatabaseTable *table);
+
+ friend class DatabaseTable;
+
+protected slots:
+ void updatePositions(DatabaseTable *table);
+
+protected:
+ void mousePressEvent(QGraphicsSceneMouseEvent *event);
+ void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
+ void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
+
+private:
+ QUndoStack *m_undoStack;
+ Mode m_mode;
+ QString m_fileName;
+ QGraphicsLineItem *m_line;
+ QList<DatabaseTable *> m_tables;
+ QList<DatabaseRelationship *> m_relations;
+};
+
+#endif
diff --git a/src/diagramitem.cpp b/src/diagramitem.cpp
new file mode 100644
index 0000000..ddb6269
--- /dev/null
+++ b/src/diagramitem.cpp
@@ -0,0 +1,22 @@
+// 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 "diagramitem.h"
+
+DiagramItem::DiagramItem(DiagramItem *parent)
+ : QGraphicsItem(parent)
+{
+}
diff --git a/src/diagramitem.h b/src/diagramitem.h
new file mode 100644
index 0000000..f66a48c
--- /dev/null
+++ b/src/diagramitem.h
@@ -0,0 +1,33 @@
+// 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 DATABASEMODELITEM_H
+#define DATABASEMODELITEM_H
+
+#include <QGraphicsItem>
+
+class DiagramItem : public QObject, public QGraphicsItem
+{
+public:
+ enum {
+ Table = UserType + 1,
+ Relation
+ };
+
+ DiagramItem(DiagramItem *parent = 0);
+};
+
+#endif
diff --git a/src/diagramobject.cpp b/src/diagramobject.cpp
new file mode 100644
index 0000000..8b0d5b3
--- /dev/null
+++ b/src/diagramobject.cpp
@@ -0,0 +1,22 @@
+// 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 "diagramobject.h"
+
+DiagramObject::DiagramObject(DiagramItem *parent)
+ : DiagramItem(parent)
+{
+}
diff --git a/src/diagramobject.h b/src/diagramobject.h
new file mode 100644
index 0000000..1ca086e
--- /dev/null
+++ b/src/diagramobject.h
@@ -0,0 +1,28 @@
+// 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 DIAGRAMOBJECT_H
+#define DIAGRAMOBJECT_H
+
+#include "diagramitem.h"
+
+class DiagramObject : public DiagramItem
+{
+public:
+ DiagramObject(DiagramItem *parent = 0);
+};
+
+#endif
diff --git a/src/diagramview.cpp b/src/diagramview.cpp
new file mode 100644
index 0000000..490cca6
--- /dev/null
+++ b/src/diagramview.cpp
@@ -0,0 +1,83 @@
+// 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 <QMouseEvent>
+#include <QScrollBar>
+#include <QDebug>
+#include "diagramview.h"
+
+DiagramView::DiagramView(QWidget *parent)
+ : QGraphicsView(parent), m_handScrolling(false)
+{
+ setAlignment(Qt::AlignLeft | Qt::AlignTop);
+ setRenderHint(QPainter::Antialiasing);
+}
+
+void
+DiagramView::setScene(QGraphicsScene *scene)
+{
+ QGraphicsView::setScene(scene);
+ updateSceneRect2(scene->sceneRect());
+ connect(scene, SIGNAL(sceneRectChanged(const QRectF &)), SLOT(updateSceneRect2(const QRectF &)));
+}
+
+void
+DiagramView::updateSceneRect2(const QRectF &rect)
+{
+ QRectF sceneRect = rect.united(QRectF(QPointF(0, 0), QPointF(100, 100)));
+ setSceneRect(sceneRect);
+}
+
+void
+DiagramView::mousePressEvent(QMouseEvent *event)
+{
+ if (event->button() == Qt::MidButton) {
+ m_handScrolling = true;
+ m_handScrollingOrigin = QPoint(event->pos());
+ m_handScrollingValueX = horizontalScrollBar()->value();
+ m_handScrollingValueY = verticalScrollBar()->value();
+ m_savedCursor = viewport()->cursor();
+ viewport()->setCursor(Qt::ClosedHandCursor);
+ event->accept();
+ return;
+ }
+ QGraphicsView::mousePressEvent(event);
+}
+
+void
+DiagramView::mouseMoveEvent(QMouseEvent *event)
+{
+ if (m_handScrolling) {
+ QPoint delta = event->pos() - m_handScrollingOrigin;
+ horizontalScrollBar()->setValue(m_handScrollingValueX - delta.x());
+ verticalScrollBar()->setValue(m_handScrollingValueY - delta.y());
+ event->accept();
+ return;
+ }
+ QGraphicsView::mouseMoveEvent(event);
+}
+
+void
+DiagramView::mouseReleaseEvent(QMouseEvent *event)
+{
+ if (m_handScrolling) {
+ m_handScrolling = false;
+ viewport()->setCursor(m_savedCursor);
+ event->accept();
+ return;
+ }
+ QGraphicsView::mouseReleaseEvent(event);
+}
diff --git a/src/diagramview.h b/src/diagramview.h
new file mode 100644
index 0000000..d5f1c56
--- /dev/null
+++ b/src/diagramview.h
@@ -0,0 +1,47 @@
+// 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 DATABASEMODELVIEW_H
+#define DATABASEMODELVIEW_H
+
+#include <QGraphicsView>
+
+class DiagramView : public QGraphicsView
+{
+ Q_OBJECT
+
+public:
+ DiagramView(QWidget *parent = 0);
+
+ void setScene(QGraphicsScene *scene);
+
+protected:
+ void mousePressEvent(QMouseEvent *event);
+ void mouseMoveEvent(QMouseEvent *event);
+ void mouseReleaseEvent(QMouseEvent *event);
+
+protected slots:
+ void updateSceneRect2(const QRectF &rect);
+
+private:
+ bool m_handScrolling;
+ QPoint m_handScrollingOrigin;
+ QCursor m_savedCursor;
+ int m_handScrollingValueX;
+ int m_handScrollingValueY;
+};
+
+#endif
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100644
index 0000000..79a7a4b
--- /dev/null
+++ b/src/main.cpp
@@ -0,0 +1,35 @@
+// 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>
+#include <QTranslator>
+#include <QApplication>
+#include "mainwindow.h"
+
+int
+main(int argc, char **argv)
+{
+ Q_INIT_RESOURCE(dbmodel);
+ QApplication app(argc, argv);
+
+ QTranslator translator;
+ translator.load("dbmodel_" + QLocale::system().name(), ":/translations/");
+ app.installTranslator(&translator);
+
+ MainWindow window;
+ window.show();
+ return app.exec();
+}
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
new file mode 100644
index 0000000..1afb262
--- /dev/null
+++ b/src/mainwindow.cpp
@@ -0,0 +1,330 @@
+// 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 <cmath>
+#include <QMenuBar>
+#include <QMenu>
+#include <QComboBox>
+#include <QToolBar>
+#include <QFileDialog>
+#include <QIcon>
+#include <QImage>
+#include <QSvgGenerator>
+#include <QMessageBox>
+#include <QDebug>
+#include "mainwindow.h"
+#include "databasetable.h"
+
+using namespace std;
+
+MainWindow::MainWindow()
+ : QMainWindow(), m_model(NULL)
+{
+ m_undoGroup = new QUndoGroup(this);
+ setupActions();
+ setupUi();
+ newModel();
+}
+
+MainWindow::~MainWindow()
+{
+ if (m_model) {
+ m_undoGroup->removeStack(m_model->undoStack());
+ }
+}
+
+void
+MainWindow::setupUi()
+{
+ setWindowTitle(tr("DB Model"));
+ resize(QSize(780, 580));
+
+ setupToolBar();
+ setupMenuBar();
+
+ m_properties = new TableProperties(this, this);
+
+ m_view = new DiagramView(this);
+
+ m_splitter = new QSplitter(Qt::Vertical, this);
+ setCentralWidget(m_splitter);
+ m_splitter->addWidget(m_view);
+ m_splitter->addWidget(m_properties);
+
+ m_splitter->setStretchFactor(0, 6);
+ m_splitter->setStretchFactor(1, 1);
+}
+
+void
+MainWindow::setupActions()
+{
+ m_actionNew = new QAction(this);
+ m_actionNew->setText(tr("&New"));
+ m_actionNew->setIcon(QIcon(":/icons/16x16/document-new.png"));
+ m_actionNew->setShortcut(QKeySequence(tr("Ctrl+N")));
+ connect(m_actionNew, SIGNAL(triggered(bool)), SLOT(newModel()));
+
+ m_actionOpen = new QAction(this);
+ m_actionOpen->setText(tr("&Open..."));
+ m_actionOpen->setIcon(QIcon(":/icons/16x16/document-open.png"));
+ m_actionOpen->setShortcut(QKeySequence(tr("Ctrl+O")));
+ connect(m_actionOpen, SIGNAL(triggered(bool)), SLOT(open()));
+
+ m_actionSave = new QAction(this);
+ m_actionSave->setText(tr("&Save"));
+ m_actionSave->setIcon(QIcon(":/icons/16x16/document-save.png"));
+ m_actionSave->setShortcut(QKeySequence(tr("Ctrl+S")));
+ m_actionSave->setDisabled(true);
+ connect(m_actionSave, SIGNAL(triggered(bool)), SLOT(save()));
+
+ m_actionSaveAs = new QAction(this);
+ m_actionSaveAs->setText(tr("Save &As..."));
+ m_actionSaveAs->setIcon(QIcon(":/icons/16x16/document-save-as.png"));
+ m_actionSaveAs->setDisabled(true);
+ connect(m_actionSaveAs, SIGNAL(triggered(bool)), SLOT(saveAs()));
+
+ connect(m_undoGroup, SIGNAL(cleanChanged(bool)), m_actionSave, SLOT(setDisabled(bool)));
+ connect(m_undoGroup, SIGNAL(cleanChanged(bool)), m_actionSaveAs, SLOT(setDisabled(bool)));
+
+ m_actionExportPNG = new QAction(this);
+ m_actionExportPNG->setText(tr("Export..."));
+ connect(m_actionExportPNG, SIGNAL(triggered(bool)), SLOT(exportPNG()));
+
+ m_actionSwitchMode[0] = new QAction(this);
+ m_actionSwitchMode[0]->setText(tr("Select"));
+ m_actionSwitchMode[0]->setIcon(QIcon(":/icons/cr16-action-mouse_pointer.png"));
+ m_actionSwitchMode[0]->setCheckable(true);
+ m_actionSwitchMode[0]->setChecked(true);
+
+ m_actionSwitchMode[1] = new QAction(this);
+ m_actionSwitchMode[1]->setText(tr("Add new table"));
+ m_actionSwitchMode[1]->setIcon(QIcon(":/icons/cr16-action-table_newobj.png"));
+ m_actionSwitchMode[1]->setCheckable(true);
+
+ m_actionSwitchMode[2] = new QAction(this);
+ m_actionSwitchMode[2]->setText(tr("Add new relation"));
+ m_actionSwitchMode[2]->setIcon(QIcon(":/icons/cr16-action-relation_newobj.png"));
+ m_actionSwitchMode[2]->setCheckable(true);
+
+ m_actionUndo = m_undoGroup->createUndoAction(this, tr("&Undo"));
+ m_actionUndo->setShortcut(QKeySequence(tr("Ctrl+Z")));
+ m_actionUndo->setIcon(QIcon(":/icons/16x16/edit-undo.png"));
+ m_actionRedo = m_undoGroup->createRedoAction(this, tr("Re&do"));
+ m_actionRedo->setShortcut(QKeySequence(tr("Ctrl+Shift+Z")));
+ m_actionRedo->setIcon(QIcon(":/icons/16x16/edit-redo.png"));
+
+ connect(m_actionSwitchMode[0], SIGNAL(triggered(bool)), SLOT(switchModeSelect()));
+ connect(m_actionSwitchMode[1], SIGNAL(triggered(bool)), SLOT(switchModeAddTable()));
+ connect(m_actionSwitchMode[2], SIGNAL(triggered(bool)), SLOT(switchModeAddRelation()));
+}
+
+void
+MainWindow::setupToolBar()
+{
+ QToolBar *toolBar = addToolBar(tr("&File"));
+ toolBar->setIconSize(QSize(16, 16));
+ toolBar->addAction(m_actionNew);
+ toolBar->addAction(m_actionOpen);
+ toolBar->addSeparator();
+ toolBar->addAction(m_actionSave);
+ toolBar->addAction(m_actionSaveAs);
+ toolBar->addSeparator();
+ toolBar->addAction(m_actionUndo);
+ toolBar->addAction(m_actionRedo);
+ toolBar = addToolBar(tr("&Mode"));
+ toolBar->setIconSize(QSize(16, 16));
+ toolBar->addAction(m_actionSwitchMode[0]);
+ toolBar->addAction(m_actionSwitchMode[1]);
+ toolBar->addAction(m_actionSwitchMode[2]);
+
+ QComboBox *sceneScaleCombo = new QComboBox;
+ QStringList scales;
+ scales << tr("50%") << tr("70%") << tr("85%") << tr("100%") << tr("125%") << tr("150%");
+ sceneScaleCombo->addItems(scales);
+ sceneScaleCombo->setEditable(true);
+ sceneScaleCombo->setCurrentIndex(3);
+ connect(sceneScaleCombo, SIGNAL(currentIndexChanged(const QString &)),
+ this, SLOT(setViewScale(const QString &)));
+
+ toolBar = addToolBar(tr("View"));
+ toolBar->addWidget(sceneScaleCombo);
+
+}
+
+void
+MainWindow::setViewScale(const QString &scale)
+{
+ double newScale = scale.left(scale.indexOf(tr("%"))).toDouble() / 100.0;
+ QMatrix oldMatrix = m_view->matrix();
+ m_view->resetMatrix();
+ m_view->translate(oldMatrix.dx(), oldMatrix.dy());
+ m_view->scale(newScale, newScale);
+}
+
+void
+MainWindow::setupMenuBar()
+{
+ QMenu *menu = menuBar()->addMenu(tr("&File"));
+ menu->addAction(m_actionNew);
+ menu->addAction(m_actionOpen);
+ menu->addSeparator();
+ menu->addAction(m_actionSave);
+ menu->addAction(m_actionSaveAs);
+ menu->addSeparator();
+ menu->addAction(m_actionExportPNG);
+ menu->addSeparator();
+ menu->addAction(tr("&Quit"), this, SLOT(close()), QKeySequence(tr("Ctrl+Q")));
+
+ menu = menuBar()->addMenu(tr("&Edit"));
+ menu->addAction(m_actionUndo);
+ menu->addAction(m_actionRedo);
+ menu->addSeparator();
+ menu->addAction(tr("&Delete"), this, SLOT(deleteSelectedItems()), QKeySequence(tr("Del")));
+}
+
+void
+MainWindow::deleteSelectedItems()
+{
+ m_model->deleteSelectedItems();
+}
+
+void
+MainWindow::open()
+{
+ QString fileName = QFileDialog::getOpenFileName(this, QString(), QString(), "Database Model (*.dmf)");
+ if (!fileName.isNull()) {
+ DiagramDocument *model = new DiagramDocument(this);
+ model->load(fileName);
+ newModel(model);
+ }
+}
+
+void
+MainWindow::save()
+{
+ QString fileName = m_model->fileName();
+ if (fileName.isEmpty()) {
+ saveAs();
+ }
+ else {
+ m_model->save(fileName);
+ }
+}
+
+void
+MainWindow::saveAs()
+{
+ QString fileName = QFileDialog::getSaveFileName(this, QString(), m_model->fileName(), "Database Model (*.dmf)");
+ if (!fileName.isNull()) {
+ m_model->save(fileName);
+ }
+}
+
+void
+MainWindow::exportPNG()
+{
+ QStringList filters;
+ filters << "Portable Network Graphics (*.png)";
+ filters << "Scalable Vector Graphics (*.svg)";
+ QString fileName = QFileDialog::getSaveFileName(this, QString(), QString(), filters.join(";;"));
+ if (!fileName.isNull()) {
+ QRectF boundingRect = m_model->itemsBoundingRect().adjusted(-2, -2, 2, 2);
+ QSize size(int(ceil(boundingRect.width())), int(ceil(boundingRect.height())));
+ if (fileName.endsWith(".svg", Qt::CaseInsensitive)) {
+ QSvgGenerator generator;
+ generator.setSize(size);
+ generator.setFileName(fileName);
+ QPainter painter(&generator);
+ painter.setRenderHints(QPainter::HighQualityAntialiasing | QPainter::Antialiasing);
+ m_model->render(&painter, QRectF(), boundingRect);
+ }
+ else if (fileName.endsWith(".png", Qt::CaseInsensitive)) {
+ QImage image(size, QImage::Format_RGB32);
+ QPainter painter(&image);
+ painter.setRenderHints(QPainter::HighQualityAntialiasing | QPainter::Antialiasing);
+ painter.fillRect(image.rect(), Qt::white);
+ m_model->render(&painter, image.rect(), boundingRect);
+ if (true)
+ image.convertToFormat(QImage::Format_Indexed8).save(fileName, "PNG");
+ else
+ image.save(fileName, "PNG");
+ }
+ else {
+ QMessageBox::critical(this, tr("Error"), tr("Unknown format."));
+ }
+ }
+}
+
+void
+MainWindow::newModel(DiagramDocument *newModel)
+{
+ if (!newModel)
+ newModel = new DiagramDocument(this);
+
+ m_view->setScene(newModel);
+ if (m_model) {
+ m_undoGroup->removeStack(m_model->undoStack());
+ delete m_model;
+ }
+ m_model = newModel;
+ updateMode(m_model->mode());
+ m_undoGroup->addStack(m_model->undoStack());
+ m_undoGroup->setActiveStack(m_model->undoStack());
+
+ connect(m_model,
+ SIGNAL(modeChanged(DiagramDocument::Mode)),
+ SLOT(updateMode(DiagramDocument::Mode)));
+ connect(m_model, SIGNAL(selectionChanged()), SLOT(updateSelection()));
+}
+
+void
+MainWindow::updateSelection()
+{
+ DatabaseTable *table = m_model->selectedTable();
+ m_properties->setTable(table);
+}
+
+void
+MainWindow::updateMode(DiagramDocument::Mode mode)
+{
+ m_actionSwitchMode[0]->setChecked(mode == DiagramDocument::Select);
+ m_actionSwitchMode[1]->setChecked(mode == DiagramDocument::AddTable);
+ m_actionSwitchMode[2]->setChecked(mode == DiagramDocument::AddRelation);
+}
+
+void
+MainWindow::switchModeSelect()
+{
+ m_model->setMode(DiagramDocument::Select);
+}
+
+void
+MainWindow::switchModeAddTable()
+{
+ m_model->setMode(DiagramDocument::AddTable);
+}
+
+void
+MainWindow::switchModeAddRelation()
+{
+ m_model->setMode(DiagramDocument::AddRelation);
+}
+
+QUndoStack *
+MainWindow::currentUndoStack()
+{
+ return m_undoGroup->activeStack();
+}
diff --git a/src/mainwindow.h b/src/mainwindow.h
new file mode 100644
index 0000000..bd8e6f8
--- /dev/null
+++ b/src/mainwindow.h
@@ -0,0 +1,78 @@
+// 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 MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include <QMainWindow>
+#include <QSplitter>
+#include <QStackedWidget>
+#include <QUndoGroup>
+#include <QAction>
+#include "diagramview.h"
+#include "diagramdocument.h"
+#include "tableproperties.h"
+
+class MainWindow: public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ MainWindow();
+ ~MainWindow();
+
+ QUndoStack *currentUndoStack();
+
+public slots:
+ void newModel(DiagramDocument *newModel = 0);
+
+ void updateMode(DiagramDocument::Mode mode);
+ void switchModeSelect();
+ void switchModeAddTable();
+ void switchModeAddRelation();
+
+ void updateSelection();
+ void deleteSelectedItems();
+
+ void open();
+ void save();
+ void saveAs();
+ void exportPNG();
+ void setViewScale(const QString &scale);
+
+protected:
+ void setupUi();
+ void setupActions();
+ void setupToolBar();
+ void setupMenuBar();
+
+private:
+ QUndoGroup *m_undoGroup;
+ QSplitter *m_splitter;
+ TableProperties *m_properties;
+ DiagramView *m_view;
+ DiagramDocument *m_model;
+
+ QAction *m_actionUndo, *m_actionRedo;
+ QAction *m_actionSwitchMode[3];
+ QAction *m_actionNew;
+ QAction *m_actionOpen;
+ QAction *m_actionSave;
+ QAction *m_actionSaveAs;
+ QAction *m_actionExportPNG;
+};
+
+#endif
diff --git a/src/range.h b/src/range.h
new file mode 100644
index 0000000..1c0bbf1
--- /dev/null
+++ b/src/range.h
@@ -0,0 +1,69 @@
+// 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; }
+ T center() const { return m_min + length() / 2; }
+
+ 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();
+}
diff --git a/src/src.pro b/src/src.pro
new file mode 100644
index 0000000..6a6fa5a
--- /dev/null
+++ b/src/src.pro
@@ -0,0 +1,60 @@
+TARGET = dbmodel
+
+QT += xml svg
+CONFIG += debug
+SOURCES = \
+ column.cpp \
+ columnlist.cpp \
+ columnlistmodel.cpp \
+ columnlistview.cpp \
+ main.cpp \
+ mainwindow.cpp \
+ diagramview.cpp \
+ diagramdocument.cpp \
+ databasetable.cpp \
+ databaserelationship.cpp \
+ diagramconnection.cpp \
+ diagramitem.cpp \
+ diagramobject.cpp \
+ tableproperties.cpp \
+ commands.cpp
+HEADERS = \
+ column.h \
+ columnlist.h \
+ columnlistmodel.h \
+ columnlistview.h \
+ mainwindow.h \
+ diagramview.h \
+ diagramdocument.h \
+ databasetable.h \
+ databaserelationship.h \
+ diagramconnection.h \
+ diagramitem.h \
+ diagramobject.h \
+ tableproperties.h \
+ range.h \
+ commands.h
+FORMS = tableproperties.ui
+RESOURCES = ../dbmodel.qrc
+
+DESTDIR = ../
+
+TRANSLATIONS = \
+ ../translations/dbmodel_sk.ts
+
+isEmpty(QMAKE_LRELEASE) {
+ win32:QMAKE_LRELEASE = $$[QT_INSTALL_BINS]\lrelease.exe
+ else:QMAKE_LRELEASE = $$[QT_INSTALL_BINS]/lrelease
+}
+
+updateqm.input = TRANSLATIONS
+updateqm.output = ../translations/${QMAKE_FILE_BASE}.qm
+updateqm.commands = $$QMAKE_LRELEASE ${QMAKE_FILE_IN} -qm ../translations/${QMAKE_FILE_BASE}.qm
+updateqm.CONFIG += no_link
+QMAKE_EXTRA_COMPILERS += updateqm
+PRE_TARGETDEPS += compiler_updateqm_make_all
+
+MOC_DIR = $$PWD/.build
+OBJECTS_DIR = $$PWD/.build
+UI_DIR = $$PWD/.build
+RCC_DIR = $$PWD/.build
diff --git a/src/tableproperties.cpp b/src/tableproperties.cpp
new file mode 100644
index 0000000..b54e4db
--- /dev/null
+++ b/src/tableproperties.cpp
@@ -0,0 +1,96 @@
+// 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 "tableproperties.h"
+#include "databasetable.h"
+#include "mainwindow.h"
+#include "commands.h"
+#include "column.h"
+#include <QCheckBox>
+#include <QDebug>
+
+TableProperties::TableProperties(MainWindow *window, QWidget *parent)
+ : QWidget(parent), m_window(window), m_table(0)
+{
+ ui.setupUi(this);
+ connect(ui.nameEdit,
+ SIGNAL(textEdited(const QString &)),
+ SLOT(setSelectedTableName(const QString &)));
+ connect(ui.addColumnButton, SIGNAL(clicked()), ui.columnsWidget, SLOT(addColumn()));
+ connect(ui.removeColumnButton, SIGNAL(clicked()), ui.columnsWidget, SLOT(removeColumn()));
+ connect(ui.moveColumnUpButton, SIGNAL(clicked()), ui.columnsWidget, SLOT(moveColumnUp()));
+ connect(ui.moveColumnDownButton, SIGNAL(clicked()), ui.columnsWidget, SLOT(moveColumnDown()));
+ connect(ui.columnsWidget->selectionModel(),
+ SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)),
+ SLOT(updateColumnSelection()));
+}
+
+void
+TableProperties::setSelectedTableName(const QString &name)
+{
+ if (m_table) {
+ m_window->currentUndoStack()->push(new SetObjectPropertyCommand(m_table, "name", name));
+ }
+}
+
+void
+TableProperties::setTable(DatabaseTable *table)
+{
+ // Disconnect all connections from the previous table
+ if (m_table) {
+ disconnect(m_table, 0, this, 0);
+ }
+
+ m_table = NULL;
+ if (table == NULL) {
+ setEnabled(false);
+ ui.nameEdit->clear();
+ ui.columnsWidget->setColumnList(0);
+ }
+ else {
+ setEnabled(true);
+ ui.nameEdit->setText(table->name());
+ ui.columnsWidget->setColumnList(table->columnList());
+ connect(table, SIGNAL(propertyChanged(const QString &, const QVariant &)), SLOT(updateProperty(const QString &, const QVariant &)));
+ }
+ m_table = table;
+ updateColumnSelection();
+}
+
+void
+TableProperties::updateProperty(const QString &name, const QVariant &value)
+{
+ if (name == "name") {
+ ui.nameEdit->setText(value.toString());
+ }
+}
+
+void
+TableProperties::updateColumnSelection()
+{
+ QList<int> columns = ui.columnsWidget->selectedColumns();
+ if (columns.isEmpty()) {
+ ui.removeColumnButton->setEnabled(false);
+ ui.moveColumnUpButton->setEnabled(false);
+ ui.moveColumnDownButton->setEnabled(false);
+ }
+ else {
+ int index = columns[0];
+ ui.removeColumnButton->setEnabled(true);
+ ui.moveColumnUpButton->setEnabled(index > 0);
+ ui.moveColumnDownButton->setEnabled(index + 1 < m_table->columnList()->columnCount());
+ }
+}
diff --git a/src/tableproperties.h b/src/tableproperties.h
new file mode 100644
index 0000000..6ad51a5
--- /dev/null
+++ b/src/tableproperties.h
@@ -0,0 +1,48 @@
+// 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 TABLEPROPERTIES_H
+#define TABLEPROPERTIES_H
+
+#include <QWidget>
+#include <QTreeWidget>
+#include "ui_tableproperties.h"
+
+class DatabaseTable;
+class MainWindow;
+
+class TableProperties : public QWidget
+{
+ Q_OBJECT
+
+public:
+ TableProperties(MainWindow *window, QWidget *parent = 0);
+
+ DatabaseTable *table() { return m_table; }
+ void setTable(DatabaseTable *table);
+
+protected slots:
+ void setSelectedTableName(const QString &name);
+ void updateColumnSelection();
+ void updateProperty(const QString &name, const QVariant &value);
+
+private:
+ MainWindow *m_window;
+ DatabaseTable *m_table;
+ Ui_TableProperties ui;
+};
+
+#endif
diff --git a/src/tableproperties.ui b/src/tableproperties.ui
new file mode 100644
index 0000000..7336cee
--- /dev/null
+++ b/src/tableproperties.ui
@@ -0,0 +1,137 @@
+<ui version="4.0" >
+ <class>TableProperties</class>
+ <widget class="QWidget" name="TableProperties" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>471</width>
+ <height>192</height>
+ </rect>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QTabWidget" name="tabWidget" >
+ <property name="currentIndex" >
+ <number>0</number>
+ </property>
+ <widget class="QWidget" name="tab" >
+ <attribute name="title" >
+ <string>&amp;Definition</string>
+ </attribute>
+ <layout class="QGridLayout" name="gridLayout_2" >
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label" >
+ <property name="text" >
+ <string>Name:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" >
+ <widget class="QLineEdit" name="nameEdit" />
+ </item>
+ <item row="1" column="0" colspan="2" >
+ <spacer name="verticalSpacer" >
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>158</width>
+ <height>113</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="tab_2" >
+ <attribute name="title" >
+ <string>&amp;Columns</string>
+ </attribute>
+ <layout class="QGridLayout" name="gridLayout_3" >
+ <item rowspan="5" row="0" column="0" >
+ <widget class="ColumnListView" name="columnsWidget" >
+ <property name="rootIsDecorated" >
+ <bool>false</bool>
+ </property>
+ <property name="itemsExpandable" >
+ <bool>false</bool>
+ </property>
+ <property name="expandsOnDoubleClick" >
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" >
+ <widget class="QPushButton" name="addColumnButton" >
+ <property name="toolTip" >
+ <string>Add new column</string>
+ </property>
+ <property name="text" >
+ <string>&amp;Add</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QPushButton" name="removeColumnButton" >
+ <property name="toolTip" >
+ <string>Remove selected column</string>
+ </property>
+ <property name="text" >
+ <string>&amp;Remove</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1" >
+ <widget class="QPushButton" name="moveColumnUpButton" >
+ <property name="toolTip" >
+ <string>Move selected column up</string>
+ </property>
+ <property name="text" >
+ <string>Move &amp;Up</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1" >
+ <widget class="QPushButton" name="moveColumnDownButton" >
+ <property name="toolTip" >
+ <string>Move selected column down</string>
+ </property>
+ <property name="text" >
+ <string>Move &amp;Down</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1" >
+ <spacer name="verticalSpacer_2" >
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>17</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>ColumnListView</class>
+ <extends>QTreeView</extends>
+ <header>columnlistview.h</header>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>