nn-usb-fpga/Software/sie_cg/diagramscene.cpp

550 lines
19 KiB
C++

/****************************************************************************
**
** 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 <QtGui>
#include <QHash>
#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<Arrow *>(selectedItems().first());
item->setColor(myLineColor);
update();
}
}
void DiagramScene::setTextColor(const QColor &color)
{
myTextColor = color;
if (isItemChange(DiagramTextItem::Type)) {
DiagramTextItem *item =
qgraphicsitem_cast<DiagramTextItem *>(selectedItems().first());
item->setDefaultTextColor(myTextColor);
}
}
void DiagramScene::setItemColor(const QColor &color)
{
myItemColor = color;
if (isItemChange(DiagramItem::Type)) {
DiagramItem *item =
qgraphicsitem_cast<DiagramItem *>(selectedItems().first());
item->setColor(myItemColor);
}
}
void DiagramScene::setFont(const QFont &font)
{
myFont = font;
if (isItemChange(DiagramTextItem::Type)) {
QGraphicsTextItem *item =
qgraphicsitem_cast<DiagramTextItem *>(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(
round(mouseEvent->scenePos().x()/myGrid)*myGrid,
round(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<QGraphicsItem *> startItems = items(line->line().p1());
if (startItems.count() && startItems.first() == line)
startItems.removeFirst();
QList<QGraphicsItem *> 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<DiagramTextItem *>(startItems.first());
DiagramTextItem *endItem_ =
qgraphicsitem_cast<DiagramTextItem *>(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);
QDomElement test = document.createElement("Test");
test.text().fromAscii("TEXT HERE");
document.appendChild(test);
//Lists of items
QList<DiagramItem *> Items;
QList<Arrow *> Arrows;
foreach(QGraphicsItem *item, items())
{
if(item->type() == DiagramItem::Type)
Items.append(qgraphicsitem_cast<DiagramItem *>(item));
else if(item->type() == Arrow::Type)
Arrows.append(qgraphicsitem_cast<Arrow *>(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<int , DiagramItem *> 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<DiagramItem *> Items;
QList<Arrow *> Arrows;
foreach(QGraphicsItem *item, items())
{
if(item->type() == DiagramItem::Type)
Items.append(qgraphicsitem_cast<DiagramItem *>(item));
else if(item->type() == Arrow::Type)
Arrows.append(qgraphicsitem_cast<Arrow *>(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();
}
}