/**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the examples of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial Usage ** Licensees holding valid Qt Commercial licenses may use this file in ** accordance with the Qt Commercial License Agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and Nokia. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU General Public License version 3.0 requirements will be ** met: http://www.gnu.org/copyleft/gpl.html. ** ** If you have questions regarding the use of this file, please contact ** Nokia at qt-info@nokia.com. ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include #include "diagramscene.h" #include "arrow.h" DiagramScene::DiagramScene(QMenu *itemMenu, MainWindow *ownerWindow, QObject *parent) : QGraphicsScene(parent) { myItemMenu = itemMenu; myMode = MoveItem; myItemType = ""; line = 0; textItem = 0; myItemColor = Qt::white; myTextColor = Qt::black; myLineColor = Qt::black; snapToGrid=1; myGrid=10; drawGrid=1; myOwnerWindow=ownerWindow; } void DiagramScene::setLineColor(const QColor &color) { myLineColor = color; if (isItemChange(Arrow::Type)) { Arrow *item = qgraphicsitem_cast(selectedItems().first()); item->setColor(myLineColor); update(); } } void DiagramScene::setTextColor(const QColor &color) { myTextColor = color; if (isItemChange(DiagramTextItem::Type)) { DiagramTextItem *item = qgraphicsitem_cast(selectedItems().first()); item->setDefaultTextColor(myTextColor); } } void DiagramScene::setItemColor(const QColor &color) { myItemColor = color; if (isItemChange(DiagramItem::Type)) { DiagramItem *item = qgraphicsitem_cast(selectedItems().first()); item->setColor(myItemColor); } } void DiagramScene::setFont(const QFont &font) { myFont = font; if (isItemChange(DiagramTextItem::Type)) { QGraphicsTextItem *item = qgraphicsitem_cast(selectedItems().first()); //At this point the selection can change so the first selected item might not be a DiagramTextItem if (item) item->setFont(myFont); } } void DiagramScene::setMode(Mode mode) { myMode = mode; } void DiagramScene::setItemType(QString type) { myItemType = type; } void DiagramScene::editorLostFocus(DiagramTextItem *item) { QTextCursor cursor = item->textCursor(); cursor.clearSelection(); item->setTextCursor(cursor); if (item->toPlainText().isEmpty()) { removeItem(item); item->deleteLater(); } } void DiagramScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent) { doSnapToGrid(mouseEvent); if (mouseEvent->button() != Qt::LeftButton) return; DiagramItem *item; switch (myMode) { case InsertItem: item = new DiagramItem(myItemMenu,myItemType, domElementsByName.value(myItemType),0,this); item->setColor(myItemColor); addItem(item); item->setPos(mouseEvent->scenePos()); emit itemInserted(item); break; case InsertLine: line = new QGraphicsLineItem(QLineF(mouseEvent->scenePos(), mouseEvent->scenePos())); line->setPen(QPen(myLineColor, 2)); line->setZValue(1000.0); addItem(line); snapToGrid=0; break; case InsertText: textItem = new DiagramTextItem(); textItem->setFont(myFont); textItem->setTextInteractionFlags(Qt::TextEditorInteraction); textItem->setZValue(1000.0); connect(textItem, SIGNAL(lostFocus(DiagramTextItem*)), this, SLOT(editorLostFocus(DiagramTextItem*))); connect(textItem, SIGNAL(selectedChange(QGraphicsItem*)), this, SIGNAL(itemSelected(QGraphicsItem*))); addItem(textItem); textItem->setDefaultTextColor(myTextColor); textItem->setPos(mouseEvent->scenePos()); emit textInserted(textItem); default: ; } QGraphicsScene::mousePressEvent(mouseEvent); } void DiagramScene::doSnapToGrid(QGraphicsSceneMouseEvent *mouseEvent) { if(snapToGrid){ mouseEvent->setScenePos(QPointF( int(mouseEvent->scenePos().x()/myGrid)*myGrid, int(mouseEvent->scenePos().y()/myGrid)*myGrid )); } } void DiagramScene::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent) { doSnapToGrid(mouseEvent); if (myMode == InsertLine && line != 0) { QLineF newLine(line->line().p1(), mouseEvent->scenePos()); line->setLine(newLine); } else if (myMode == MoveItem) { QGraphicsScene::mouseMoveEvent(mouseEvent); } } void DiagramScene::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *mouseEvent) { doSnapToGrid(mouseEvent); QGraphicsScene::mouseDoubleClickEvent(mouseEvent); } void DiagramScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent) { doSnapToGrid(mouseEvent); if (line != 0 && myMode == InsertLine) { QList startItems = items(line->line().p1()); if (startItems.count() && startItems.first() == line) startItems.removeFirst(); QList endItems = items(line->line().p2()); if (endItems.count() && endItems.first() == line) endItems.removeFirst(); removeItem(line); delete line; //Diferents items and valid type if (startItems.count() > 0 && endItems.count() > 0 && startItems.first()->type() == DiagramTextItem::Type && endItems.first()->type() == DiagramTextItem::Type && startItems.first() != endItems.first()) { DiagramTextItem *startItem_ = qgraphicsitem_cast(startItems.first()); DiagramTextItem *endItem_ = qgraphicsitem_cast(endItems.first()); //Real first and end item DiagramTextItem *startItem = startItem_; DiagramTextItem *endItem = endItem_; if(startItem_->styleIO()>>7) { startItem = endItem_; endItem = startItem_; } //Inputs to outputs and diferent owner diagram item if(startItem->styleIO()>0 && endItem->styleIO()>0 && (startItem->styleIO()>>7 != endItem->styleIO()>>7) && (startItem->ownerItem() != endItem->ownerItem()) && !endItem->ownerItem()->existArrow(startItem,endItem) ) { Arrow *arrow = new Arrow(startItem, endItem,0,this); arrow->setColor(myLineColor); startItem->ownerItem()->addArrow(arrow); endItem->ownerItem()->addArrow(arrow); arrow->setZValue(0.0); addItem(arrow); arrow->updatePosition(); } } } line = 0; snapToGrid=1; QGraphicsScene::mouseReleaseEvent(mouseEvent); } bool DiagramScene::isItemChange(int type) { foreach (QGraphicsItem *item, selectedItems()) { if (item->type() == type) return true; } return false; } QDomDocument DiagramScene::toXmlFormat() { QDomDocument document; QDomComment initialComments=document.createComment( "\nFile for SIE Code Generator.\n" "**WARNING**If you are going to edit this file note that:\n" "In order to segmentation faults prevention the load process \n" "is started loading the libraries, then items and finally arrows.\n" "Arrows depend of items, and items depend of libraries!!!!\n"); document.appendChild(initialComments); QDomElement diagram = document.createElement("Diagram"); document.appendChild(diagram); //Lists of items QList Items; QList Arrows; foreach(QGraphicsItem *item, items()) { if(item->type() == DiagramItem::Type) Items.append(qgraphicsitem_cast(item)); else if(item->type() == Arrow::Type) Arrows.append(qgraphicsitem_cast(item)); } //Create the XML structure QDomElement element; if(!libraryList.isEmpty()) { QDomElement libraries = document.createElement("Libraries"); foreach(QString lib, libraryList) { element = document.createElement("Library"); element.setAttribute("Dir",lib); libraries.appendChild(element); } diagram.appendChild(libraries); } if(!Items.isEmpty()) { QDomElement diagramItems = document.createElement("DiagramItems"); foreach(DiagramItem *item, Items) { element = item->toXml(document); element.setAttribute("ID",Items.indexOf(item)); //save index diagramItems.appendChild(element); } diagram.appendChild(diagramItems); } if(!Arrows.isEmpty()) { QDomElement arrowItems = document.createElement("Arrows"); foreach(Arrow *item, Arrows) { element = item->toXml(document,Items); element.setAttribute("ID",Arrows.indexOf(item)); //save index arrowItems.appendChild(element); } diagram.appendChild(arrowItems); } return(document); } int DiagramScene::fromXmlFormat(QDomDocument document) { //Read diagrams TODO: in future... add multi projects functionality QHash DiagramsID; QDomNodeList diagrams = document.elementsByTagName("Diagram"); if(!diagrams.at(0).isElement()) return 0; //Load the first diagram in the document QDomElement diagram = diagrams.at(0).toElement(); //In order to segmentation faults prevention the load process //is started loading the libraries, then items and finally arrows. //Arrows depend of items, and items depend of libraries!!! //TODO: rewrite this process for reading in the order specified for (QDomNode node = diagram.firstChild() ; !node.isNull() ; node = node.nextSibling()) { QDomElement element = node.toElement(); if(element.tagName()=="Libraries") { libraryList.clear(); for (QDomNode node = element.firstChild() ; !node.isNull() ; node = node.nextSibling()) { //Load library directory QDomElement Library = node.toElement(); if(Library.tagName()!="Library") return 0; libraryList.append(Library.attribute("Dir")); } myOwnerWindow->updateLibraries(); } else if(element.tagName()=="DiagramItems") //Load diagram items { for (QDomNode node = element.firstChild() ; !node.isNull() ; node = node.nextSibling()) { //Load diagram item and add to scene QDomElement diagramItem = node.toElement(); if(diagramItem.tagName()!="DiagramItem") return 0; QPointF position = QPointF(diagramItem.attribute("x").toFloat(), diagramItem.attribute("y").toFloat()); //PREVENT Segmentation faults: if(!domElementsByName.contains( diagramItem.attribute("type"))) { QMessageBox::critical(0,"Error",QObject::tr( "Diagram can't be loaded, because the" " library for block [") + diagramItem.attribute("type") +tr( "] can't be found.")); return 0; } DiagramItem *newItem=new DiagramItem( myItemMenu, diagramItem.attribute("type"), domElementsByName.value(diagramItem.attribute("type")), 0,this, position, diagramItem.attribute("z").toDouble()); newItem->setColor(QColor(diagramItem.attribute("color"))); addItem(newItem); DiagramsID.insert(diagramItem.attribute("ID").toInt(),newItem); for (QDomNode node = diagramItem.firstChild() ; !node.isNull() ; node = node.nextSibling()) { //Load diagram text values and set on diagram item QDomElement diagramValues = node.toElement(); if(diagramValues.tagName()!="diagramValues") return 0; for (QDomNode node = diagramValues.firstChild() ; !node.isNull() ; node = node.nextSibling()) { QDomElement diagramValue = node.toElement(); if(diagramValue.tagName()!="diagramValue") return 0; newItem->setValue(diagramValue.attribute("ID").toInt(), diagramValue.attribute("value")); } } } } else if(element.tagName()=="Arrows") { for (QDomNode node = element.firstChild() ; !node.isNull() ; node = node.nextSibling()) { //Load arrow item and add to scene QDomElement arrow = node.toElement(); if(arrow.tagName()!="Arrow") return 0; DiagramTextItem *startItem= DiagramsID.value(arrow.attribute("start-Owner").toInt()) ->pointerText(arrow.attribute("start-ID").toInt()); DiagramTextItem *endItem= DiagramsID.value(arrow.attribute("end-Owner").toInt()) ->pointerText(arrow.attribute("end-ID").toInt()); Arrow *newArrow = new Arrow(startItem, endItem,0,this); newArrow->setColor(QColor(arrow.attribute("color"))); startItem->ownerItem()->addArrow(newArrow); endItem->ownerItem()->addArrow(newArrow); newArrow->setZValue(0.0); addItem(newArrow); newArrow->updatePosition(); for (QDomNode node = arrow.firstChild() ; !node.isNull() ; node = node.nextSibling()) { //Load diagram text values and set on diagram item QDomElement arrowCorners = node.toElement(); if(arrowCorners.tagName()!="arrowCorners") return 0; int i=0; for (QDomNode node = arrowCorners.firstChild() ; !node.isNull() ; node = node.nextSibling()) { QDomElement arrowCorner = node.toElement(); if(arrowCorner.tagName()!="arrowCorner") return 0; QPointF cornerPos = QPointF(arrowCorner.attribute("x").toFloat(), arrowCorner.attribute("y").toFloat()); newArrow->createCorner(cornerPos,++i); } } } } } return 1; } void DiagramScene::cleanScene() { //Lists of items QList Items; QList Arrows; foreach(QGraphicsItem *item, items()) { if(item->type() == DiagramItem::Type) Items.append(qgraphicsitem_cast(item)); else if(item->type() == Arrow::Type) Arrows.append(qgraphicsitem_cast(item)); } //Delete only DiagramItems: When a diagramitem is deleted his arrows and //textitems have to be deleted too, so if we delete only diagramitems then //we are deleting all items in the scene. This is in order to prevent //segmentation faults. foreach(DiagramItem *item, Items) { item->removeArrows(); item->removeTextItems(); removeItem(item); delete(item); } //Delete the text items without parents foreach(QGraphicsItem *item, items()) { removeItem(item); delete(item); } } void DiagramScene::drawBackground(QPainter *p, const QRectF &r) { QGraphicsScene::drawBackground(p,r); if(drawGrid) { p -> save(); p -> setRenderHint(QPainter::Antialiasing, false); p -> setRenderHint(QPainter::TextAntialiasing, true); p -> setRenderHint(QPainter::SmoothPixmapTransform, false); p -> setPen(Qt::NoPen); p -> setBrush(Qt::white); p -> drawRect(r); p -> setPen(Qt::black); p -> setBrush(Qt::NoBrush); qreal limite_x = r.x() + r.width(); qreal limite_y = r.y() + r.height(); int g_x = (int)ceil(r.x()); while (g_x % myGrid) ++ g_x; int g_y = (int)ceil(r.y()); while (g_y % myGrid) ++ g_y; QPolygon points; for (int gx = g_x ; gx < limite_x ; gx += myGrid) { for (int gy = g_y ; gy < limite_y ; gy += myGrid) { points << QPoint(gx, gy); } } p -> drawPoints(points); p -> restore(); } }