mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2025-12-17 20:50:34 +01:00
Rapatriement de la branche 0.2 dans le trunk
git-svn-id: svn+ssh://svn.tuxfamily.org/svnroot/qet/qet/trunk@558 bfdf4180-ca20-0410-9c96-a3a8aa849046
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright 2006-2007 Xavier Guerrin
|
||||
Copyright 2006-2009 Xavier Guerrin
|
||||
This file is part of QElectroTech.
|
||||
|
||||
QElectroTech is free software: you can redistribute it and/or modify
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "qetelementeditor.h"
|
||||
#include <cmath>
|
||||
#include "partline.h"
|
||||
#include "partrectangle.h"
|
||||
#include "partellipse.h"
|
||||
#include "partcircle.h"
|
||||
#include "partpolygon.h"
|
||||
@@ -28,9 +29,7 @@
|
||||
#include "partarc.h"
|
||||
#include "hotspoteditor.h"
|
||||
#include "editorcommands.h"
|
||||
|
||||
const int ElementScene::xGrid = 10;
|
||||
const int ElementScene::yGrid = 10;
|
||||
#include "elementcontent.h"
|
||||
|
||||
/**
|
||||
Constructeur
|
||||
@@ -47,6 +46,8 @@ ElementScene::ElementScene(QETElementEditor *editor, QObject *parent) :
|
||||
element_editor(editor)
|
||||
{
|
||||
current_polygon = NULL;
|
||||
setGrid(1, 1);
|
||||
initPasteArea();
|
||||
undo_stack.setClean();
|
||||
}
|
||||
|
||||
@@ -68,6 +69,13 @@ void ElementScene::slot_addLine() {
|
||||
behavior = Line;
|
||||
}
|
||||
|
||||
/**
|
||||
Passe la scene en mode "ajout de rectangle"
|
||||
*/
|
||||
void ElementScene::slot_addRectangle() {
|
||||
behavior = Rectangle;
|
||||
}
|
||||
|
||||
/**
|
||||
Passe la scene en mode "ajout de cercle"
|
||||
*/
|
||||
@@ -104,7 +112,6 @@ void ElementScene::slot_addTerminal() {
|
||||
behavior = Terminal;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Passe la scene en mode "ajout d'arc de cercle"
|
||||
*/
|
||||
@@ -124,7 +131,17 @@ void ElementScene::slot_addTextField() {
|
||||
@param e objet decrivant l'evenement
|
||||
*/
|
||||
void ElementScene::mouseMoveEvent(QGraphicsSceneMouseEvent *e) {
|
||||
QPointF event_pos = e -> scenePos();
|
||||
if (mustSnapToGrid(e)) snapToGrid(event_pos);
|
||||
|
||||
if (behavior != Polygon && current_polygon != NULL) current_polygon = NULL;
|
||||
if (behavior == PasteArea) {
|
||||
QRectF current_rect(paste_area_ -> rect());
|
||||
current_rect.moveCenter(event_pos);
|
||||
paste_area_ -> setRect(current_rect);
|
||||
return;
|
||||
}
|
||||
|
||||
QRectF temp_rect;
|
||||
qreal radius;
|
||||
QPointF temp_point;
|
||||
@@ -132,21 +149,26 @@ void ElementScene::mouseMoveEvent(QGraphicsSceneMouseEvent *e) {
|
||||
if (e -> buttons() & Qt::LeftButton) {
|
||||
switch(behavior) {
|
||||
case Line:
|
||||
current_line -> setLine(QLineF(current_line -> line().p1(), e -> scenePos()));
|
||||
current_line -> setLine(QLineF(current_line -> line().p1(), event_pos));
|
||||
break;
|
||||
case Rectangle:
|
||||
temp_rect = current_rectangle -> rect();
|
||||
temp_rect.setBottomRight(event_pos);
|
||||
current_rectangle -> setRect(temp_rect);
|
||||
break;
|
||||
case Ellipse:
|
||||
temp_rect = current_ellipse -> rect();
|
||||
temp_rect.setBottomRight(e -> scenePos());
|
||||
temp_rect.setBottomRight(event_pos);
|
||||
current_ellipse -> setRect(temp_rect);
|
||||
break;
|
||||
case Arc:
|
||||
temp_rect = current_arc -> rect();
|
||||
temp_rect.setBottomRight(e -> scenePos());
|
||||
temp_rect.setBottomRight(event_pos);
|
||||
current_arc -> setRect(temp_rect);
|
||||
break;
|
||||
case Circle:
|
||||
temp_rect = current_circle -> rect();
|
||||
temp_point = e -> scenePos() - current_circle -> mapToScene(temp_rect.center());
|
||||
temp_point = event_pos - current_circle -> mapToScene(temp_rect.center());
|
||||
radius = sqrt(pow(temp_point.x(), 2) + pow(temp_point.y(), 2));
|
||||
temp_rect = QRectF(
|
||||
temp_rect.center() - QPointF(radius, radius),
|
||||
@@ -158,17 +180,35 @@ void ElementScene::mouseMoveEvent(QGraphicsSceneMouseEvent *e) {
|
||||
if (current_polygon == NULL) break;
|
||||
temp_polygon = current_polygon -> polygon();
|
||||
temp_polygon.pop_back();
|
||||
temp_polygon << e -> scenePos();
|
||||
temp_polygon << event_pos;
|
||||
current_polygon -> setPolygon(temp_polygon);
|
||||
break;
|
||||
case Normal:
|
||||
default:
|
||||
QGraphicsScene::mouseMoveEvent(e);
|
||||
QList<QGraphicsItem *> selected_items = selectedItems();
|
||||
if (!selected_items.isEmpty()) {
|
||||
// mouvement de souris realise depuis le dernier press event
|
||||
QPointF mouse_movement = e -> scenePos() - moving_press_pos;
|
||||
|
||||
// application de ce mouvement a la fsi_pos enregistre dans le dernier press event
|
||||
QPointF new_fsi_pos = fsi_pos + mouse_movement;
|
||||
|
||||
// snap eventuel de la nouvelle fsi_pos
|
||||
if (mustSnapToGrid(e)) snapToGrid(new_fsi_pos);
|
||||
|
||||
// difference entre la fsi_pos finale et la fsi_pos courante = mouvement a appliquer
|
||||
|
||||
QPointF current_fsi_pos = selected_items.first() -> scenePos();
|
||||
QPointF final_movement = new_fsi_pos - current_fsi_pos;
|
||||
foreach(QGraphicsItem *qgi, selected_items) {
|
||||
qgi -> moveBy(final_movement.x(), final_movement.y());
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (behavior == Polygon && current_polygon != NULL) {
|
||||
temp_polygon = current_polygon -> polygon();
|
||||
temp_polygon.pop_back();
|
||||
temp_polygon << e -> scenePos();
|
||||
temp_polygon << event_pos;
|
||||
current_polygon -> setPolygon(temp_polygon);
|
||||
} else QGraphicsScene::mouseMoveEvent(e);
|
||||
}
|
||||
@@ -178,27 +218,34 @@ void ElementScene::mouseMoveEvent(QGraphicsSceneMouseEvent *e) {
|
||||
@param e objet decrivant l'evenement
|
||||
*/
|
||||
void ElementScene::mousePressEvent(QGraphicsSceneMouseEvent *e) {
|
||||
QPointF event_pos = e -> scenePos();
|
||||
if (mustSnapToGrid(e)) snapToGrid(event_pos);
|
||||
|
||||
if (behavior != Polygon && current_polygon != NULL) current_polygon = NULL;
|
||||
QPolygonF temp_polygon;
|
||||
if (e -> button() & Qt::LeftButton) {
|
||||
switch(behavior) {
|
||||
case Line:
|
||||
current_line = new PartLine(element_editor, 0, this);
|
||||
current_line -> setLine(QLineF(e -> scenePos(), e -> scenePos()));
|
||||
current_line -> setLine(QLineF(event_pos, event_pos));
|
||||
break;
|
||||
case Rectangle:
|
||||
current_rectangle = new PartRectangle(element_editor, 0, this);
|
||||
current_rectangle -> setRect(QRectF(event_pos, QSizeF(0.0, 0.0)));
|
||||
break;
|
||||
case Ellipse:
|
||||
current_ellipse = new PartEllipse(element_editor, 0, this);
|
||||
current_ellipse -> setRect(QRectF(e -> scenePos(), QSizeF(0.0, 0.0)));
|
||||
current_ellipse -> setRect(QRectF(event_pos, QSizeF(0.0, 0.0)));
|
||||
current_ellipse -> setProperty("antialias", true);
|
||||
break;
|
||||
case Arc:
|
||||
current_arc = new PartArc(element_editor, 0, this);
|
||||
current_arc -> setRect(QRectF(e -> scenePos(), QSizeF(0.0, 0.0)));
|
||||
current_arc -> setRect(QRectF(event_pos, QSizeF(0.0, 0.0)));
|
||||
current_arc -> setProperty("antialias", true);
|
||||
break;
|
||||
case Circle:
|
||||
current_circle = new PartCircle(element_editor, 0, this);
|
||||
current_circle -> setRect(QRectF(e -> scenePos(), QSizeF(0.0, 0.0)));
|
||||
current_circle -> setRect(QRectF(event_pos, QSizeF(0.0, 0.0)));
|
||||
current_circle -> setProperty("antialias", true);
|
||||
break;
|
||||
case Polygon:
|
||||
@@ -207,14 +254,23 @@ void ElementScene::mousePressEvent(QGraphicsSceneMouseEvent *e) {
|
||||
temp_polygon = QPolygonF(0);
|
||||
} else temp_polygon = current_polygon -> polygon();
|
||||
// au debut, on insere deux points
|
||||
if (!temp_polygon.count()) temp_polygon << e -> scenePos();
|
||||
temp_polygon << e -> scenePos();
|
||||
if (!temp_polygon.count()) temp_polygon << event_pos;
|
||||
temp_polygon << event_pos;
|
||||
current_polygon -> setPolygon(temp_polygon);
|
||||
break;
|
||||
case Normal:
|
||||
default:
|
||||
QGraphicsScene::mousePressEvent(e);
|
||||
if (!selectedItems().isEmpty()) fsi_pos = selectedItems().first() -> scenePos();
|
||||
// gestion des deplacements de parties
|
||||
if (!selectedItems().isEmpty()) {
|
||||
fsi_pos = selectedItems().first() -> scenePos();
|
||||
moving_press_pos = e -> scenePos();
|
||||
moving_parts_ = true;
|
||||
} else {
|
||||
fsi_pos = QPoint();
|
||||
moving_press_pos = QPoint();
|
||||
moving_parts_ = false;
|
||||
}
|
||||
}
|
||||
} else QGraphicsScene::mousePressEvent(e);
|
||||
}
|
||||
@@ -224,71 +280,97 @@ void ElementScene::mousePressEvent(QGraphicsSceneMouseEvent *e) {
|
||||
@param e objet decrivant l'evenement
|
||||
*/
|
||||
void ElementScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *e) {
|
||||
QPointF event_pos = e -> scenePos();
|
||||
if (mustSnapToGrid(e)) snapToGrid(event_pos);
|
||||
|
||||
PartTerminal *terminal;
|
||||
PartText *text;
|
||||
PartTextField *textfield;
|
||||
if (behavior != Polygon && current_polygon != NULL) current_polygon = NULL;
|
||||
|
||||
if (behavior == PasteArea) {
|
||||
defined_paste_area_ = paste_area_ -> rect();
|
||||
removeItem(paste_area_);
|
||||
emit(pasteAreaDefined(defined_paste_area_));
|
||||
behavior = Normal;
|
||||
return;
|
||||
}
|
||||
|
||||
if (e -> button() & Qt::LeftButton) {
|
||||
switch(behavior) {
|
||||
case Line:
|
||||
if (qgiManager().manages(current_line)) break;
|
||||
undo_stack.push(new AddPartCommand(tr("ligne"), this, current_line));
|
||||
emit(partsAdded());
|
||||
endCurrentBehavior(e);
|
||||
break;
|
||||
case Rectangle:
|
||||
if (qgiManager().manages(current_rectangle)) break;
|
||||
current_rectangle -> setRect(current_rectangle -> rect().normalized());
|
||||
undo_stack.push(new AddPartCommand(tr("rectangle"), this, current_rectangle));
|
||||
emit(partsAdded());
|
||||
endCurrentBehavior(e);
|
||||
break;
|
||||
case Ellipse:
|
||||
if (qgiManager().manages(current_ellipse)) break;
|
||||
current_ellipse -> setRect(current_ellipse -> rect().normalized());
|
||||
undo_stack.push(new AddPartCommand(tr("ellipse"), this, current_ellipse));
|
||||
emit(partsAdded());
|
||||
endCurrentBehavior(e);
|
||||
break;
|
||||
case Arc:
|
||||
if (qgiManager().manages(current_arc)) break;
|
||||
current_arc-> setRect(current_arc -> rect().normalized());
|
||||
undo_stack.push(new AddPartCommand(tr("arc"), this, current_arc));
|
||||
emit(partsAdded());
|
||||
endCurrentBehavior(e);
|
||||
break;
|
||||
case Circle:
|
||||
if (qgiManager().manages(current_circle)) break;
|
||||
current_circle -> setRect(current_circle -> rect().normalized());
|
||||
undo_stack.push(new AddPartCommand(tr("cercle"), this, current_circle));
|
||||
emit(partsAdded());
|
||||
endCurrentBehavior(e);
|
||||
break;
|
||||
case Terminal:
|
||||
terminal = new PartTerminal(element_editor, 0, this);
|
||||
terminal -> setPos(e -> scenePos());
|
||||
terminal -> setPos(event_pos);
|
||||
undo_stack.push(new AddPartCommand(tr("borne"), this, terminal));
|
||||
emit(partsAdded());
|
||||
endCurrentBehavior(e);
|
||||
break;
|
||||
case Text:
|
||||
text = new PartText(element_editor, 0, this);
|
||||
text -> setPos(e -> scenePos());
|
||||
text -> setPos(event_pos);
|
||||
undo_stack.push(new AddPartCommand(tr("texte"), this, text));
|
||||
emit(partsAdded());
|
||||
endCurrentBehavior(e);
|
||||
break;
|
||||
case TextField:
|
||||
textfield = new PartTextField(element_editor, 0, this);
|
||||
textfield -> setPos(e -> scenePos());
|
||||
textfield -> setPos(event_pos);
|
||||
undo_stack.push(new AddPartCommand(tr("champ de texte"), this, textfield));
|
||||
emit(partsAdded());
|
||||
endCurrentBehavior(e);
|
||||
break;
|
||||
case Normal:
|
||||
default:
|
||||
QGraphicsScene::mouseReleaseEvent(e);
|
||||
// detecte les deplacements de parties
|
||||
if (!selectedItems().isEmpty()) {
|
||||
if (!selectedItems().isEmpty() && moving_parts_) {
|
||||
QPointF movement = selectedItems().first() -> scenePos() - fsi_pos;
|
||||
if (!movement.isNull()) {
|
||||
undo_stack.push(new MovePartsCommand(movement, this, selectedItems()));
|
||||
}
|
||||
}
|
||||
QGraphicsScene::mouseReleaseEvent(e);
|
||||
moving_parts_ = false;
|
||||
}
|
||||
} else if (e -> button() & Qt::RightButton) {
|
||||
if (behavior == Polygon && current_polygon != NULL) {
|
||||
behavior = Normal;
|
||||
undo_stack.push(new AddPartCommand(tr("polygone"), this, current_polygon));
|
||||
current_polygon = NULL;
|
||||
emit(partsAdded());
|
||||
emit(needNormalMode());
|
||||
endCurrentBehavior(e);
|
||||
} else QGraphicsScene::mouseReleaseEvent(e);
|
||||
} else QGraphicsScene::mouseReleaseEvent(e);
|
||||
}
|
||||
@@ -317,6 +399,10 @@ void ElementScene::drawBackground(QPainter *p, const QRectF &r) {
|
||||
p -> setBrush(Qt::NoBrush);
|
||||
p -> drawRect(drawable_area);
|
||||
|
||||
// on dessine un point de la grille sur 10
|
||||
int drawn_x_grid = x_grid * 10;
|
||||
int drawn_y_grid = y_grid * 10;
|
||||
|
||||
if (r.width() < 2500 && r.height() < 2500) {
|
||||
// dessine les points de la grille
|
||||
p -> setPen(Qt::black);
|
||||
@@ -325,12 +411,12 @@ void ElementScene::drawBackground(QPainter *p, const QRectF &r) {
|
||||
qreal limite_y = r.y() + r.height();
|
||||
|
||||
int g_x = (int)ceil(r.x());
|
||||
while (g_x % xGrid) ++ g_x;
|
||||
while (g_x % drawn_x_grid) ++ g_x;
|
||||
int g_y = (int)ceil(r.y());
|
||||
while (g_y % yGrid) ++ g_y;
|
||||
while (g_y % drawn_y_grid) ++ g_y;
|
||||
|
||||
for (int gx = g_x ; gx < limite_x ; gx += xGrid) {
|
||||
for (int gy = g_y ; gy < limite_y ; gy += yGrid) {
|
||||
for (int gx = g_x ; gx < limite_x ; gx += drawn_x_grid) {
|
||||
for (int gy = g_y ; gy < limite_y ; gy += drawn_y_grid) {
|
||||
p -> drawPoint(gx, gy);
|
||||
}
|
||||
}
|
||||
@@ -358,11 +444,50 @@ void ElementScene::drawForeground(QPainter *p, const QRectF &) {
|
||||
p -> restore();
|
||||
}
|
||||
|
||||
/**
|
||||
A partir d'un evenement souris, cette methode regarde si la touche shift est
|
||||
enfoncee ou non. Si oui, elle laisse le comportement en cours (cercle,
|
||||
texte, polygone, ...). Si non, elle repasse en mode normal / selection.
|
||||
@param e objet decrivant l'evenement souris
|
||||
*/
|
||||
void ElementScene::endCurrentBehavior(const QGraphicsSceneMouseEvent *event) {
|
||||
if (!(event -> modifiers() & Qt::ShiftModifier)) {
|
||||
// la touche Shift n'est pas enfoncee : on demande le mode normal
|
||||
behavior = Normal;
|
||||
emit(needNormalMode());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@return la taille horizontale de la grille
|
||||
*/
|
||||
int ElementScene::xGrid() const {
|
||||
return(x_grid);
|
||||
}
|
||||
|
||||
/**
|
||||
@return la taille verticale de la grille
|
||||
*/
|
||||
int ElementScene::yGrid() const {
|
||||
return(y_grid);
|
||||
}
|
||||
|
||||
/**
|
||||
@param x_grid Taille horizontale de la grille
|
||||
@param y_grid Taille verticale de la grille
|
||||
*/
|
||||
void ElementScene::setGrid(int x_g, int y_g) {
|
||||
x_grid = x_g ? x_g : 1;
|
||||
y_grid = y_g ? y_g : 1;
|
||||
}
|
||||
|
||||
/**
|
||||
Exporte l'element en XML
|
||||
@param diagram Booleen (a vrai par defaut) indiquant si le XML genere doit
|
||||
representer tout l'element ou seulement les elements selectionnes
|
||||
@return un document XML decrivant l'element
|
||||
*/
|
||||
const QDomDocument ElementScene::toXml() const {
|
||||
const QDomDocument ElementScene::toXml(bool all_parts) const {
|
||||
// document XML
|
||||
QDomDocument xml_document;
|
||||
|
||||
@@ -383,6 +508,8 @@ const QDomDocument ElementScene::toXml() const {
|
||||
QDomElement description = xml_document.createElement("description");
|
||||
// description de l'element
|
||||
foreach(QGraphicsItem *qgi, zItems(true)) {
|
||||
// si l'export ne concerne que la selection, on ignore les parties non selectionnees
|
||||
if (!all_parts && !qgi -> isSelected()) continue;
|
||||
if (CustomElementPart *ce = dynamic_cast<CustomElementPart *>(qgi)) {
|
||||
if (ce -> isUseless()) continue;
|
||||
description.appendChild(ce -> toXml(xml_document));
|
||||
@@ -395,91 +522,90 @@ const QDomDocument ElementScene::toXml() const {
|
||||
}
|
||||
|
||||
/**
|
||||
Lit un element depuis un document XML
|
||||
@param xml_document un document XML decrivant l'element
|
||||
@param xml_document un document XML decrivant un element
|
||||
@return le boundingRect du contenu de l'element
|
||||
*/
|
||||
void ElementScene::fromXml(const QDomDocument &xml_document) {
|
||||
QRectF ElementScene::boundingRectFromXml(const QDomDocument &xml_document) {
|
||||
// charge les parties depuis le document XML
|
||||
ElementContent loaded_content = loadContent(xml_document);
|
||||
if (loaded_content.isEmpty()) return(QRectF());
|
||||
|
||||
// calcule le boundingRect
|
||||
QRectF bounding_rect = elementContentBoundingRect(loaded_content);
|
||||
|
||||
// detruit les parties chargees
|
||||
qDeleteAll(loaded_content);
|
||||
|
||||
return(bounding_rect);
|
||||
}
|
||||
|
||||
/**
|
||||
Importe l'element decrit dans un document XML. Si une position est
|
||||
precisee, les elements importes sont positionnes de maniere a ce que le
|
||||
coin superieur gauche du plus petit rectangle pouvant les entourant tous
|
||||
(le bounding rect) soit a cette position.
|
||||
@param xml_document un document XML decrivant l'element
|
||||
@param position La position des parties importees
|
||||
@param consider_informations Si vrai, les informations complementaires
|
||||
(dimensions, hotspot, etc.) seront prises en compte
|
||||
@param content_ptr si ce pointeur vers un ElementContent est different de 0,
|
||||
il sera rempli avec le contenu ajoute a l'element par le fromXml
|
||||
@return true si l'import a reussi, false sinon
|
||||
*/
|
||||
void ElementScene::fromXml(
|
||||
const QDomDocument &xml_document,
|
||||
const QPointF &position,
|
||||
bool consider_informations,
|
||||
ElementContent *content_ptr
|
||||
) {
|
||||
QString error_message;
|
||||
bool state = true;
|
||||
|
||||
// la racine est supposee etre une definition d'element
|
||||
QDomElement root = xml_document.documentElement();
|
||||
if (root.tagName() != "definition" || root.attribute("type") != "element") {
|
||||
state = false;
|
||||
error_message = tr("Ce document XML n'est pas une definition d'\351l\351ment.");
|
||||
}
|
||||
|
||||
// dimensions et hotspot
|
||||
if (state) {
|
||||
// ces attributs doivent etre presents et valides
|
||||
int w, h, hot_x, hot_y;
|
||||
if (
|
||||
!QET::attributeIsAnInteger(root, QString("width"), &w) ||\
|
||||
!QET::attributeIsAnInteger(root, QString("height"), &h) ||\
|
||||
!QET::attributeIsAnInteger(root, QString("hotspot_x"), &hot_x) ||\
|
||||
!QET::attributeIsAnInteger(root, QString("hotspot_y"), &hot_y)
|
||||
) {
|
||||
state = false;
|
||||
error_message = tr("Les dimensions ou le point de saisie ne sont pas valides.");
|
||||
} else {
|
||||
setWidth(w);
|
||||
setHeight(h);
|
||||
setHotspot(QPoint(hot_x, hot_y));
|
||||
}
|
||||
}
|
||||
|
||||
// orientations et connexions internes
|
||||
if (state) {
|
||||
internal_connections = (root.attribute("ic") == "true");
|
||||
|
||||
if (!ori.fromString(root.attribute("orientation"))) {
|
||||
state = false;
|
||||
error_message = tr("Les orientations ne sont pas valides.");
|
||||
}
|
||||
}
|
||||
|
||||
// extrait les noms de la definition XML
|
||||
if (state) {
|
||||
_names.fromXml(root);
|
||||
// prend en compte les informations de l'element
|
||||
if (consider_informations) {
|
||||
state = applyInformations(xml_document, &error_message);
|
||||
}
|
||||
|
||||
// parcours des enfants de la definition : parties de l'element
|
||||
if (state) {
|
||||
for (QDomNode node = root.firstChild() ; !node.isNull() ; node = node.nextSibling()) {
|
||||
QDomElement elmts = node.toElement();
|
||||
if (elmts.isNull()) continue;
|
||||
if (elmts.tagName() == "description") {
|
||||
// gestion de la description graphique de l'element
|
||||
// = parcours des differentes parties du dessin
|
||||
int z = 1;
|
||||
for (QDomNode n = node.firstChild() ; !n.isNull() ; n = n.nextSibling()) {
|
||||
QDomElement qde = n.toElement();
|
||||
if (qde.isNull()) continue;
|
||||
CustomElementPart *cep;
|
||||
if (qde.tagName() == "line") cep = new PartLine (element_editor, 0, this);
|
||||
else if (qde.tagName() == "ellipse") cep = new PartEllipse (element_editor, 0, this);
|
||||
else if (qde.tagName() == "circle") cep = new PartCircle (element_editor, 0, this);
|
||||
else if (qde.tagName() == "polygon") cep = new PartPolygon (element_editor, 0, this);
|
||||
else if (qde.tagName() == "terminal") cep = new PartTerminal (element_editor, 0, this);
|
||||
else if (qde.tagName() == "text") cep = new PartText (element_editor, 0, this);
|
||||
else if (qde.tagName() == "input") cep = new PartTextField(element_editor, 0, this);
|
||||
else if (qde.tagName() == "arc") cep = new PartArc (element_editor, 0, this);
|
||||
else continue;
|
||||
if (QGraphicsItem *qgi = dynamic_cast<QGraphicsItem *>(cep)) qgi -> setZValue(z++);
|
||||
cep -> fromXml(qde);
|
||||
}
|
||||
}
|
||||
ElementContent loaded_content = loadContent(xml_document, &error_message);
|
||||
if (position != QPointF()) {
|
||||
addContentAtPos(loaded_content, position, &error_message);
|
||||
} else {
|
||||
addContent(loaded_content, &error_message);
|
||||
}
|
||||
|
||||
// renvoie le contenu ajoute a l'element
|
||||
if (content_ptr) {
|
||||
*content_ptr = loaded_content;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@return le rectangle representant les limites de l'element.
|
||||
Ce rectangle a pour dimensions la taille de l'element et pour coin
|
||||
superieur gauche les coordonnees opposees du hotspot.
|
||||
*/
|
||||
QRectF ElementScene::borderRect() const {
|
||||
return(QRectF(-_hotspot, QSizeF(width(), height())));
|
||||
}
|
||||
|
||||
/**
|
||||
@return un rectangle englobant toutes les parties ainsi que le
|
||||
"bounding rect" de l'element
|
||||
*/
|
||||
QRectF ElementScene::sceneContent() const {
|
||||
return(itemsBoundingRect().unite(QRectF(-_hotspot, QSizeF(width(), height()))));
|
||||
return(itemsBoundingRect().unite(borderRect()));
|
||||
}
|
||||
|
||||
/**
|
||||
@return true si toutes les parties graphiques composant l'element sont
|
||||
integralement contenues dans le rectangle representant les limites de
|
||||
l'element.
|
||||
*/
|
||||
bool ElementScene::borderContainsEveryParts() const {
|
||||
return(borderRect().contains(itemsBoundingRect()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -496,6 +622,64 @@ QGIManager &ElementScene::qgiManager() {
|
||||
return(qgi_manager);
|
||||
}
|
||||
|
||||
/**
|
||||
@return true si le presse-papier semble contenir un element
|
||||
*/
|
||||
bool ElementScene::clipboardMayContainElement() {
|
||||
QString clipboard_text = QApplication::clipboard() -> text().trimmed();
|
||||
bool may_be_element = clipboard_text.startsWith("<definition") && clipboard_text.endsWith("</definition>");
|
||||
return(may_be_element);
|
||||
}
|
||||
|
||||
/**
|
||||
@param clipboard_content chaine de caractere, provenant vraisemblablement du
|
||||
presse-papier.
|
||||
@return true si clipboard_content a ete copie depuis cet element.
|
||||
*/
|
||||
bool ElementScene::wasCopiedFromThisElement(const QString &clipboard_content) {
|
||||
return(clipboard_content == last_copied_);
|
||||
}
|
||||
|
||||
/**
|
||||
Gere le fait de couper la selection = l'exporter en XML dans le
|
||||
presse-papier puis la supprimer.
|
||||
*/
|
||||
void ElementScene::cut() {
|
||||
copy();
|
||||
QList<QGraphicsItem *> cut_content = selectedItems();
|
||||
clearSelection();
|
||||
undoStack().push(new CutPartsCommand(this, cut_content));
|
||||
}
|
||||
|
||||
/**
|
||||
Gere le fait de copier la selection = l'exporter en XML dans le
|
||||
presse-papier.
|
||||
*/
|
||||
void ElementScene::copy() {
|
||||
// accede au presse-papier
|
||||
QClipboard *clipboard = QApplication::clipboard();
|
||||
|
||||
// genere la description XML de la selection
|
||||
QString clipboard_content = toXml(false).toString(4);
|
||||
|
||||
// met la description XML dans le presse-papier
|
||||
if (clipboard -> supportsSelection()) {
|
||||
clipboard -> setText(clipboard_content, QClipboard::Selection);
|
||||
}
|
||||
clipboard -> setText(clipboard_content);
|
||||
|
||||
// retient le dernier contenu copie
|
||||
last_copied_ = clipboard_content;
|
||||
}
|
||||
|
||||
/**
|
||||
Gere le fait de coller le contenu du presse-papier = l'importer dans le
|
||||
presse-papier a une position donnee.
|
||||
*/
|
||||
void ElementScene::paste() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
Selectionne tout
|
||||
*/
|
||||
@@ -538,7 +722,7 @@ void ElementScene::slot_editSizeHotSpot() {
|
||||
// cree un dialogue
|
||||
QDialog dialog_sh(element_editor);
|
||||
dialog_sh.setModal(true);
|
||||
dialog_sh.setWindowTitle(tr("\311diter la taille et le point de saisie"));
|
||||
dialog_sh.setWindowTitle(tr("\311diter la taille et le point de saisie", "window title"));
|
||||
QVBoxLayout *dialog_layout = new QVBoxLayout(&dialog_sh);
|
||||
|
||||
// ajoute un HotspotEditor au dialogue
|
||||
@@ -578,7 +762,7 @@ void ElementScene::slot_editOrientations() {
|
||||
QDialog dialog_ori(element_editor);
|
||||
dialog_ori.setModal(true);
|
||||
dialog_ori.setMinimumSize(400, 260);
|
||||
dialog_ori.setWindowTitle(tr("\311diter les orientations"));
|
||||
dialog_ori.setWindowTitle(tr("\311diter les orientations", "window title"));
|
||||
QVBoxLayout *dialog_layout = new QVBoxLayout(&dialog_ori);
|
||||
|
||||
// ajoute un champ explicatif au dialogue
|
||||
@@ -624,7 +808,7 @@ void ElementScene::slot_editNames() {
|
||||
QDialog dialog(element_editor);
|
||||
dialog.setModal(true);
|
||||
dialog.setMinimumSize(400, 330);
|
||||
dialog.setWindowTitle(tr("\311diter les noms"));
|
||||
dialog.setWindowTitle(tr("\311diter les noms", "window title"));
|
||||
QVBoxLayout *dialog_layout = new QVBoxLayout(&dialog);
|
||||
|
||||
// ajoute un champ explicatif au dialogue
|
||||
@@ -716,6 +900,30 @@ QList<QGraphicsItem *> ElementScene::zItems(bool include_terminals) const {
|
||||
return(all_items_list);
|
||||
}
|
||||
|
||||
/**
|
||||
@return les parties graphiques selectionnees
|
||||
*/
|
||||
ElementContent ElementScene::selectedContent() const {
|
||||
ElementContent content;
|
||||
foreach(QGraphicsItem *qgi, zItems(true)) {
|
||||
if (qgi -> isSelected()) content << qgi;
|
||||
}
|
||||
return(content);
|
||||
}
|
||||
|
||||
/**
|
||||
@param to_paste Rectangle englobant les parties a coller
|
||||
@return le rectangle ou il faudra coller ces parties
|
||||
*/
|
||||
void ElementScene::getPasteArea(const QRectF &to_paste) {
|
||||
// on le dessine sur la scene
|
||||
paste_area_ -> setRect(to_paste);
|
||||
addItem(paste_area_);
|
||||
|
||||
// on passe la scene en mode "recherche de zone pour copier/coller"
|
||||
behavior = PasteArea;
|
||||
}
|
||||
|
||||
/**
|
||||
Supprime les parties de l'element et les objets d'annulations.
|
||||
Les autres caracteristiques sont conservees.
|
||||
@@ -729,3 +937,200 @@ void ElementScene::reset() {
|
||||
qgiManager().release(qgi);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@param content Contenu ( = parties) d'un element
|
||||
@return le boundingRect de ces parties, exprime dans les coordonnes de la
|
||||
scene
|
||||
*/
|
||||
QRectF ElementScene::elementContentBoundingRect(const ElementContent &content) {
|
||||
QRectF bounding_rect;
|
||||
foreach(QGraphicsItem *qgi, content) {
|
||||
bounding_rect |= qgi -> sceneBoundingRect();
|
||||
}
|
||||
return(bounding_rect);
|
||||
}
|
||||
|
||||
/**
|
||||
Applique les informations (dimensions, hostpot, orientations, connexions
|
||||
internes et noms) contenu dans un document XML.
|
||||
@param xml_document Document XML a analyser
|
||||
@param error_message pointeur vers une QString ; si error_message est
|
||||
different de 0, un message d'erreur sera stocke dedans si necessaire
|
||||
@return true si la lecture et l'application des informations s'est bien
|
||||
passee, false sinon.
|
||||
*/
|
||||
bool ElementScene::applyInformations(const QDomDocument &xml_document, QString *error_message) {
|
||||
// la racine est supposee etre une definition d'element
|
||||
QDomElement root = xml_document.documentElement();
|
||||
if (root.tagName() != "definition" || root.attribute("type") != "element") {
|
||||
if (error_message) {
|
||||
*error_message = tr("Ce document XML n'est pas une d\351finition d'\351l\351ment.", "error message");
|
||||
}
|
||||
return(false);
|
||||
}
|
||||
|
||||
// dimensions et hotspot : ces attributs doivent etre presents et valides
|
||||
int w, h, hot_x, hot_y;
|
||||
if (
|
||||
!QET::attributeIsAnInteger(root, QString("width"), &w) ||\
|
||||
!QET::attributeIsAnInteger(root, QString("height"), &h) ||\
|
||||
!QET::attributeIsAnInteger(root, QString("hotspot_x"), &hot_x) ||\
|
||||
!QET::attributeIsAnInteger(root, QString("hotspot_y"), &hot_y)
|
||||
) {
|
||||
if (error_message) {
|
||||
*error_message = tr("Les dimensions ou le point de saisie ne sont pas valides.", "error message");
|
||||
}
|
||||
return(false);
|
||||
}
|
||||
//
|
||||
setWidth(w);
|
||||
setHeight(h);
|
||||
setHotspot(QPoint(hot_x, hot_y));
|
||||
|
||||
// orientations
|
||||
internal_connections = (root.attribute("ic") == "true");
|
||||
|
||||
// connexions internes
|
||||
if (!ori.fromString(root.attribute("orientation"))) {
|
||||
if (error_message) {
|
||||
*error_message = tr("Les orientations ne sont pas valides.", "error message");
|
||||
}
|
||||
return(false);
|
||||
}
|
||||
|
||||
// extrait les noms de la definition XML
|
||||
_names.fromXml(root);
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
/**
|
||||
Par le document XML xml_document et retourne le contenu ( = liste de
|
||||
parties) correspondant.
|
||||
@param xml_document Document XML a analyser
|
||||
@param error_message pointeur vers une QString ; si error_message est
|
||||
different de 0, un message d'erreur sera stocke dedans si necessaire
|
||||
*/
|
||||
ElementContent ElementScene::loadContent(const QDomDocument &xml_document, QString *error_message) {
|
||||
ElementContent loaded_parts;
|
||||
|
||||
// la racine est supposee etre une definition d'element
|
||||
QDomElement root = xml_document.documentElement();
|
||||
if (root.tagName() != "definition" || root.attribute("type") != "element") {
|
||||
if (error_message) {
|
||||
*error_message = tr("Ce document XML n'est pas une d\351finition d'\351l\351ment.", "error message");
|
||||
}
|
||||
return(loaded_parts);
|
||||
}
|
||||
|
||||
// chargement de la description graphique de l'element
|
||||
for (QDomNode node = root.firstChild() ; !node.isNull() ; node = node.nextSibling()) {
|
||||
QDomElement elmts = node.toElement();
|
||||
if (elmts.isNull()) continue;
|
||||
if (elmts.tagName() == "description") {
|
||||
|
||||
// = parcours des differentes parties du dessin
|
||||
int z = 1;
|
||||
for (QDomNode n = node.firstChild() ; !n.isNull() ; n = n.nextSibling()) {
|
||||
QDomElement qde = n.toElement();
|
||||
if (qde.isNull()) continue;
|
||||
CustomElementPart *cep;
|
||||
if (qde.tagName() == "line") cep = new PartLine (element_editor, 0, 0);
|
||||
else if (qde.tagName() == "rect") cep = new PartRectangle(element_editor, 0, 0);
|
||||
else if (qde.tagName() == "ellipse") cep = new PartEllipse (element_editor, 0, 0);
|
||||
else if (qde.tagName() == "circle") cep = new PartCircle (element_editor, 0, 0);
|
||||
else if (qde.tagName() == "polygon") cep = new PartPolygon (element_editor, 0, 0);
|
||||
else if (qde.tagName() == "terminal") cep = new PartTerminal (element_editor, 0, 0);
|
||||
else if (qde.tagName() == "text") cep = new PartText (element_editor, 0, 0);
|
||||
else if (qde.tagName() == "input") cep = new PartTextField(element_editor, 0, 0);
|
||||
else if (qde.tagName() == "arc") cep = new PartArc (element_editor, 0, 0);
|
||||
else continue;
|
||||
if (QGraphicsItem *qgi = dynamic_cast<QGraphicsItem *>(cep)) {
|
||||
qgi -> setZValue(z++);
|
||||
loaded_parts << qgi;
|
||||
}
|
||||
cep -> fromXml(qde);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return(loaded_parts);
|
||||
}
|
||||
|
||||
/**
|
||||
Ajoute le contenu content a cet element
|
||||
@param content contenu ( = liste de parties) a charger
|
||||
@param error_message pointeur vers une QString ; si error_message est
|
||||
different de 0, un message d'erreur sera stocke dedans si necessaire
|
||||
@return Le contenu ajoute
|
||||
*/
|
||||
ElementContent ElementScene::addContent(const ElementContent &content, QString */*error_message*/) {
|
||||
foreach(QGraphicsItem *part, content) {
|
||||
addItem(part);
|
||||
}
|
||||
return(content);
|
||||
}
|
||||
|
||||
/**
|
||||
Ajoute le contenu content a cet element
|
||||
@param content contenu ( = liste de parties) a charger
|
||||
@param pos Position du coin superieur gauche du contenu apres avoir ete ajoute
|
||||
@param error_message pointeur vers une QString ; si error_message est
|
||||
different de 0, un message d'erreur sera stocke dedans si necessaire
|
||||
@return Le contenu ajoute
|
||||
*/
|
||||
ElementContent ElementScene::addContentAtPos(const ElementContent &content, const QPointF &pos, QString */*error_message*/) {
|
||||
// calcule le boundingRect du contenu a ajouter
|
||||
QRectF bounding_rect = elementContentBoundingRect(content);
|
||||
|
||||
// en deduit le decalage a appliquer aux parties pour les poser au point demander
|
||||
QPointF offset = pos - bounding_rect.topLeft();
|
||||
|
||||
// ajoute les parties avec le decalage adequat
|
||||
foreach(QGraphicsItem *part, content) {
|
||||
part -> setPos(part -> pos() + offset);
|
||||
addItem(part);
|
||||
}
|
||||
return(content);
|
||||
}
|
||||
|
||||
/**
|
||||
Initialise la zone de collage
|
||||
*/
|
||||
void ElementScene::initPasteArea() {
|
||||
paste_area_ = new QGraphicsRectItem();
|
||||
paste_area_ -> setZValue(1000000);
|
||||
|
||||
QPen paste_area_pen;
|
||||
paste_area_pen.setStyle(Qt::DashDotLine);
|
||||
paste_area_pen.setColor(QColor(30, 56, 86, 255));
|
||||
|
||||
QBrush paste_area_brush;
|
||||
paste_area_brush.setStyle(Qt::SolidPattern);
|
||||
paste_area_brush.setColor(QColor(90, 167, 255, 64));
|
||||
|
||||
paste_area_ -> setPen(paste_area_pen);
|
||||
paste_area_ -> setBrush(paste_area_brush);
|
||||
}
|
||||
|
||||
/**
|
||||
Arrondit les coordonnees du point passees en parametre de facon a ce que ce
|
||||
point soit aligne sur la grille.
|
||||
@param point une reference vers un QPointF. Cet objet sera modifie.
|
||||
|
||||
*/
|
||||
void ElementScene::snapToGrid(QPointF &point) {
|
||||
point.rx() = qRound(point.x() / x_grid) * x_grid;
|
||||
point.ry() = qRound(point.y() / y_grid) * y_grid;
|
||||
}
|
||||
|
||||
/**
|
||||
@param e Evenement souris
|
||||
@return true s'il faut utiliser le snap-to-grid
|
||||
Typiquement, cette methode retourne true si l'evenement souris se produit
|
||||
sans la touche Ctrl enfoncee.
|
||||
*/
|
||||
bool ElementScene::mustSnapToGrid(QGraphicsSceneMouseEvent *e) {
|
||||
return(!(e -> modifiers() & Qt::ControlModifier));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user