// 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 "databasemodel.h" #include "databasetable.h" #include "databaserelation.h" #include "column.h" #include #include #include #include DatabaseModel::DatabaseModel(QObject *parent) : QGraphicsScene(parent), m_line(NULL) { connect(this, SIGNAL(tableMoved(DatabaseTable *)), SLOT(updatePositions(DatabaseTable *))); } DatabaseModel::Mode DatabaseModel::mode() { return m_mode; } void DatabaseModel::setMode(Mode mode) { m_mode = mode; emit modeChanged(mode); } void DatabaseModel::updatePositions(DatabaseTable *table) { foreach (DatabaseRelation *relation, findTableRelations(table)) { relation->updatePositions(); } } void DatabaseModel::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 DatabaseModel::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { if (m_line) { m_line->setLine(QLineF(m_line->line().p1(), event->scenePos())); event->accept(); return; } QGraphicsScene::mouseMoveEvent(event); } void DatabaseModel::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { if (m_line) { removeItem(m_line); DatabaseTable *source = qgraphicsitem_cast(itemAt(m_line->line().p1())); DatabaseTable *target = qgraphicsitem_cast(itemAt(m_line->line().p2())); if (source && target && source != target) { qDebug() << "Add relation between " << source << " and " << target; DatabaseRelation *relation = new DatabaseRelation(); 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 * DatabaseModel::selectedTable() { QList items = selectedItems(); if (items.size() != 1) return NULL; return qgraphicsitem_cast(items[0]); } void DatabaseModel::deleteSelectedItems() { foreach (QGraphicsItem *item, selectedItems()) { DatabaseTable *table = qgraphicsitem_cast(item); if (table) { foreach (DatabaseRelation *relation, findTableRelations(table)) { removeItem(relation); m_relations.removeAll(relation); } removeItem(table); m_tables.removeAll(table); } } } QList DatabaseModel::findTableRelations(DatabaseTable *table) { QList result; foreach (DatabaseRelation *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 DatabaseModel::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->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 (DatabaseRelation *relation, m_relations) { QDomElement relationElement = doc.createElement("relation"); relationElement.setAttribute("from", QString::number(m_tables.indexOf(relation->source()))); relationElement.setAttribute("to", QString::number(m_tables.indexOf(relation->target()))); relationListElement.appendChild(relationElement); } QFile file(fileName); if (file.open(QIODevice::WriteOnly)) { QTextStream stream(&file); doc.save(stream, 0); file.close(); } setFileName(fileName); } void DatabaseModel::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 = table->addColumn(); 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")); 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) { DatabaseRelation *relation = new DatabaseRelation(); relation->setSource(m_tables[index0]); relation->setTarget(m_tables[index1]); m_relations << relation; addItem(relation); } } } }