2007-12-01 10:47:15 +00:00
/*
2013-06-18 11:10:19 +00:00
Copyright 2006 - 2013 The QElectroTech Team
2007-12-01 10:47:15 +00:00
This file is part of QElectroTech .
QElectroTech 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 .
QElectroTech 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 QElectroTech . If not , see < http : //www.gnu.org/licenses/>.
*/
2007-08-25 03:43:05 +00:00
# include "elementscene.h"
# include "qetelementeditor.h"
2013-02-08 22:05:15 +00:00
# include "elementprimitivedecorator.h"
2007-06-30 17:41:07 +00:00
# include <cmath>
# include "partline.h"
2009-04-03 19:30:25 +00:00
# include "partrectangle.h"
2007-06-30 17:41:07 +00:00
# include "partellipse.h"
# include "partpolygon.h"
# include "partterminal.h"
# include "parttext.h"
2007-08-18 04:42:39 +00:00
# include "parttextfield.h"
2007-07-10 22:54:22 +00:00
# include "partarc.h"
2007-08-23 15:33:55 +00:00
# include "editorcommands.h"
2009-04-03 19:30:25 +00:00
# include "elementcontent.h"
2011-05-25 14:09:47 +00:00
# include "nameslist.h"
2007-06-30 17:41:07 +00:00
2007-12-05 21:16:01 +00:00
/**
Constructeur
@ param editor L ' editeur d ' element concerne
@ param parent le Widget parent
*/
2007-08-25 03:43:05 +00:00
ElementScene : : ElementScene ( QETElementEditor * editor , QObject * parent ) :
2007-06-30 17:41:07 +00:00
QGraphicsScene ( parent ) ,
2007-12-09 10:30:35 +00:00
internal_connections ( false ) ,
2007-08-25 03:43:05 +00:00
qgi_manager ( this ) ,
2013-02-08 22:05:15 +00:00
element_editor ( editor ) ,
decorator_ ( 0 )
2007-06-30 17:41:07 +00:00
{
2010-02-28 16:13:45 +00:00
setItemIndexMethod ( NoIndex ) ;
2007-06-30 17:41:07 +00:00
current_polygon = NULL ;
2009-04-03 19:30:25 +00:00
setGrid ( 1 , 1 ) ;
initPasteArea ( ) ;
2007-08-25 15:46:09 +00:00
undo_stack . setClean ( ) ;
2013-02-08 22:05:15 +00:00
decorator_lock_ = new QMutex ( QMutex : : NonRecursive ) ;
connect ( & undo_stack , SIGNAL ( indexChanged ( int ) ) , this , SLOT ( managePrimitivesGroups ( ) ) ) ;
connect ( this , SIGNAL ( selectionChanged ( ) ) , this , SLOT ( managePrimitivesGroups ( ) ) ) ;
2007-06-30 17:41:07 +00:00
}
2007-12-05 21:16:01 +00:00
/// Destructeur
2007-08-25 03:43:05 +00:00
ElementScene : : ~ ElementScene ( ) {
2013-02-08 22:05:15 +00:00
delete decorator_lock_ ;
2007-06-30 17:41:07 +00:00
}
2007-12-05 21:16:01 +00:00
/**
Passe la scene en mode " selection et deplacement de parties "
*/
2007-08-25 03:43:05 +00:00
void ElementScene : : slot_move ( ) {
2007-06-30 17:41:07 +00:00
behavior = Normal ;
}
2007-12-05 21:16:01 +00:00
/**
Passe la scene en mode " ajout de ligne "
*/
2007-08-25 03:43:05 +00:00
void ElementScene : : slot_addLine ( ) {
2007-06-30 17:41:07 +00:00
behavior = Line ;
}
2009-04-03 19:30:25 +00:00
/**
Passe la scene en mode " ajout de rectangle "
*/
void ElementScene : : slot_addRectangle ( ) {
behavior = Rectangle ;
}
2007-12-05 21:16:01 +00:00
/**
Passe la scene en mode " ajout de cercle "
*/
2007-08-25 03:43:05 +00:00
void ElementScene : : slot_addCircle ( ) {
2007-06-30 17:41:07 +00:00
behavior = Circle ;
}
2007-12-05 21:16:01 +00:00
/**
Passe la scene en mode " ajout d'ellipse "
*/
2007-08-25 03:43:05 +00:00
void ElementScene : : slot_addEllipse ( ) {
2007-06-30 17:41:07 +00:00
behavior = Ellipse ;
}
2007-12-05 21:16:01 +00:00
/**
Passe la scene en mode " ajout de polygone "
*/
2007-08-25 03:43:05 +00:00
void ElementScene : : slot_addPolygon ( ) {
2007-06-30 17:41:07 +00:00
behavior = Polygon ;
}
2007-12-05 21:16:01 +00:00
/**
Passe la scene en mode " ajout de texte statique "
*/
2007-08-25 03:43:05 +00:00
void ElementScene : : slot_addText ( ) {
2007-06-30 17:41:07 +00:00
behavior = Text ;
}
2007-12-05 21:16:01 +00:00
/**
Passe la scene en mode " ajout de borne "
*/
2007-08-25 03:43:05 +00:00
void ElementScene : : slot_addTerminal ( ) {
2007-06-30 17:41:07 +00:00
behavior = Terminal ;
}
2007-12-05 21:16:01 +00:00
/**
Passe la scene en mode " ajout d'arc de cercle "
*/
2007-08-25 03:43:05 +00:00
void ElementScene : : slot_addArc ( ) {
2007-06-30 17:41:07 +00:00
behavior = Arc ;
}
2007-12-05 21:16:01 +00:00
/**
Passe la scene en mode " ajout de champ de texte "
*/
2007-08-25 03:43:05 +00:00
void ElementScene : : slot_addTextField ( ) {
2007-06-30 17:41:07 +00:00
behavior = TextField ;
}
2007-12-05 21:16:01 +00:00
/**
Gere les mouvements de la souris
@ param e objet decrivant l ' evenement
*/
2007-08-25 03:43:05 +00:00
void ElementScene : : mouseMoveEvent ( QGraphicsSceneMouseEvent * e ) {
2009-04-03 19:30:25 +00:00
QPointF event_pos = e - > scenePos ( ) ;
if ( mustSnapToGrid ( e ) ) snapToGrid ( event_pos ) ;
2007-06-30 17:41:07 +00:00
if ( behavior ! = Polygon & & current_polygon ! = NULL ) current_polygon = NULL ;
2009-04-03 19:30:25 +00:00
if ( behavior = = PasteArea ) {
QRectF current_rect ( paste_area_ - > rect ( ) ) ;
current_rect . moveCenter ( event_pos ) ;
paste_area_ - > setRect ( current_rect ) ;
return ;
}
2007-06-30 17:41:07 +00:00
QRectF temp_rect ;
QPointF temp_point ;
QPolygonF temp_polygon ;
if ( e - > buttons ( ) & Qt : : LeftButton ) {
switch ( behavior ) {
case Line :
2009-04-03 19:30:25 +00:00
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 ) ;
2007-06-30 17:41:07 +00:00
break ;
case Ellipse :
temp_rect = current_ellipse - > rect ( ) ;
2009-04-03 19:30:25 +00:00
temp_rect . setBottomRight ( event_pos ) ;
2007-06-30 17:41:07 +00:00
current_ellipse - > setRect ( temp_rect ) ;
break ;
2007-07-10 22:54:22 +00:00
case Arc :
temp_rect = current_arc - > rect ( ) ;
2009-04-03 19:30:25 +00:00
temp_rect . setBottomRight ( event_pos ) ;
2007-07-10 22:54:22 +00:00
current_arc - > setRect ( temp_rect ) ;
break ;
2007-06-30 17:41:07 +00:00
case Polygon :
if ( current_polygon = = NULL ) break ;
temp_polygon = current_polygon - > polygon ( ) ;
temp_polygon . pop_back ( ) ;
2009-04-03 19:30:25 +00:00
temp_polygon < < event_pos ;
2007-06-30 17:41:07 +00:00
current_polygon - > setPolygon ( temp_polygon ) ;
break ;
2007-09-21 11:48:37 +00:00
case Normal :
2007-06-30 17:41:07 +00:00
default :
2013-02-08 22:05:15 +00:00
QGraphicsScene : : mouseMoveEvent ( e ) ;
2007-06-30 17:41:07 +00:00
}
} else if ( behavior = = Polygon & & current_polygon ! = NULL ) {
temp_polygon = current_polygon - > polygon ( ) ;
temp_polygon . pop_back ( ) ;
2009-04-03 19:30:25 +00:00
temp_polygon < < event_pos ;
2007-06-30 17:41:07 +00:00
current_polygon - > setPolygon ( temp_polygon ) ;
} else QGraphicsScene : : mouseMoveEvent ( e ) ;
}
2007-12-05 21:16:01 +00:00
/**
Gere les appuis sur les boutons de la souris
@ param e objet decrivant l ' evenement
*/
2007-08-25 03:43:05 +00:00
void ElementScene : : mousePressEvent ( QGraphicsSceneMouseEvent * e ) {
2009-04-03 19:30:25 +00:00
QPointF event_pos = e - > scenePos ( ) ;
if ( mustSnapToGrid ( e ) ) snapToGrid ( event_pos ) ;
2007-06-30 17:41:07 +00:00
if ( behavior ! = Polygon & & current_polygon ! = NULL ) current_polygon = NULL ;
QPolygonF temp_polygon ;
if ( e - > button ( ) & Qt : : LeftButton ) {
switch ( behavior ) {
case Line :
2007-08-25 03:43:05 +00:00
current_line = new PartLine ( element_editor , 0 , this ) ;
2009-04-03 19:30:25 +00:00
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 ) ) ) ;
2007-06-30 17:41:07 +00:00
break ;
case Ellipse :
2007-08-25 03:43:05 +00:00
current_ellipse = new PartEllipse ( element_editor , 0 , this ) ;
2009-04-03 19:30:25 +00:00
current_ellipse - > setRect ( QRectF ( event_pos , QSizeF ( 0.0 , 0.0 ) ) ) ;
2007-10-06 19:46:44 +00:00
current_ellipse - > setProperty ( " antialias " , true ) ;
2007-06-30 17:41:07 +00:00
break ;
2007-07-10 22:54:22 +00:00
case Arc :
2007-08-25 03:43:05 +00:00
current_arc = new PartArc ( element_editor , 0 , this ) ;
2009-04-03 19:30:25 +00:00
current_arc - > setRect ( QRectF ( event_pos , QSizeF ( 0.0 , 0.0 ) ) ) ;
2007-10-06 19:46:44 +00:00
current_arc - > setProperty ( " antialias " , true ) ;
2007-07-10 22:54:22 +00:00
break ;
2007-06-30 17:41:07 +00:00
case Polygon :
if ( current_polygon = = NULL ) {
2007-08-25 03:43:05 +00:00
current_polygon = new PartPolygon ( element_editor , 0 , this ) ;
2007-06-30 17:41:07 +00:00
temp_polygon = QPolygonF ( 0 ) ;
} else temp_polygon = current_polygon - > polygon ( ) ;
// au debut, on insere deux points
2009-04-03 19:30:25 +00:00
if ( ! temp_polygon . count ( ) ) temp_polygon < < event_pos ;
temp_polygon < < event_pos ;
2007-06-30 17:41:07 +00:00
current_polygon - > setPolygon ( temp_polygon ) ;
break ;
2007-09-21 11:48:37 +00:00
case Normal :
2007-06-30 17:41:07 +00:00
default :
QGraphicsScene : : mousePressEvent ( e ) ;
}
} else QGraphicsScene : : mousePressEvent ( e ) ;
}
2007-12-05 21:16:01 +00:00
/**
Gere les relachements de boutons de la souris
@ param e objet decrivant l ' evenement
*/
2007-08-25 03:43:05 +00:00
void ElementScene : : mouseReleaseEvent ( QGraphicsSceneMouseEvent * e ) {
2009-04-03 19:30:25 +00:00
QPointF event_pos = e - > scenePos ( ) ;
if ( mustSnapToGrid ( e ) ) snapToGrid ( event_pos ) ;
2007-06-30 17:41:07 +00:00
PartTerminal * terminal ;
PartText * text ;
2007-08-18 04:42:39 +00:00
PartTextField * textfield ;
2007-06-30 17:41:07 +00:00
if ( behavior ! = Polygon & & current_polygon ! = NULL ) current_polygon = NULL ;
2009-04-03 19:30:25 +00:00
if ( behavior = = PasteArea ) {
defined_paste_area_ = paste_area_ - > rect ( ) ;
removeItem ( paste_area_ ) ;
emit ( pasteAreaDefined ( defined_paste_area_ ) ) ;
behavior = Normal ;
return ;
}
2007-06-30 17:41:07 +00:00
if ( e - > button ( ) & Qt : : LeftButton ) {
switch ( behavior ) {
case Line :
2007-12-15 21:57:00 +00:00
if ( qgiManager ( ) . manages ( current_line ) ) break ;
2007-08-23 15:33:55 +00:00
undo_stack . push ( new AddPartCommand ( tr ( " ligne " ) , this , current_line ) ) ;
2007-11-07 20:23:24 +00:00
emit ( partsAdded ( ) ) ;
2009-04-03 19:30:25 +00:00
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 ) ;
2007-06-30 17:41:07 +00:00
break ;
case Ellipse :
2007-12-15 21:57:00 +00:00
if ( qgiManager ( ) . manages ( current_ellipse ) ) break ;
2007-06-30 17:41:07 +00:00
current_ellipse - > setRect ( current_ellipse - > rect ( ) . normalized ( ) ) ;
2007-08-23 15:33:55 +00:00
undo_stack . push ( new AddPartCommand ( tr ( " ellipse " ) , this , current_ellipse ) ) ;
2007-11-07 20:23:24 +00:00
emit ( partsAdded ( ) ) ;
2009-04-03 19:30:25 +00:00
endCurrentBehavior ( e ) ;
2007-06-30 17:41:07 +00:00
break ;
2007-07-10 22:54:22 +00:00
case Arc :
2007-12-15 21:57:00 +00:00
if ( qgiManager ( ) . manages ( current_arc ) ) break ;
2007-07-10 22:54:22 +00:00
current_arc - > setRect ( current_arc - > rect ( ) . normalized ( ) ) ;
2007-08-23 15:33:55 +00:00
undo_stack . push ( new AddPartCommand ( tr ( " arc " ) , this , current_arc ) ) ;
2007-11-07 20:23:24 +00:00
emit ( partsAdded ( ) ) ;
2009-04-03 19:30:25 +00:00
endCurrentBehavior ( e ) ;
2007-07-10 22:54:22 +00:00
break ;
2007-06-30 17:41:07 +00:00
case Terminal :
2007-08-25 03:43:05 +00:00
terminal = new PartTerminal ( element_editor , 0 , this ) ;
2009-04-03 19:30:25 +00:00
terminal - > setPos ( event_pos ) ;
2007-08-23 15:33:55 +00:00
undo_stack . push ( new AddPartCommand ( tr ( " borne " ) , this , terminal ) ) ;
2007-11-07 20:23:24 +00:00
emit ( partsAdded ( ) ) ;
2009-04-03 19:30:25 +00:00
endCurrentBehavior ( e ) ;
2007-06-30 17:41:07 +00:00
break ;
case Text :
2007-08-25 03:43:05 +00:00
text = new PartText ( element_editor , 0 , this ) ;
2009-04-03 19:30:25 +00:00
text - > setPos ( event_pos ) ;
2007-08-23 15:33:55 +00:00
undo_stack . push ( new AddPartCommand ( tr ( " texte " ) , this , text ) ) ;
2007-11-07 20:23:24 +00:00
emit ( partsAdded ( ) ) ;
2009-04-03 19:30:25 +00:00
endCurrentBehavior ( e ) ;
2007-06-30 17:41:07 +00:00
break ;
2007-08-18 04:42:39 +00:00
case TextField :
2007-08-25 03:43:05 +00:00
textfield = new PartTextField ( element_editor , 0 , this ) ;
2009-04-03 19:30:25 +00:00
textfield - > setPos ( event_pos ) ;
2007-08-23 15:33:55 +00:00
undo_stack . push ( new AddPartCommand ( tr ( " champ de texte " ) , this , textfield ) ) ;
2007-11-07 20:23:24 +00:00
emit ( partsAdded ( ) ) ;
2009-04-03 19:30:25 +00:00
endCurrentBehavior ( e ) ;
2007-08-18 04:42:39 +00:00
break ;
2007-08-23 15:33:55 +00:00
case Normal :
2007-06-30 17:41:07 +00:00
default :
2007-08-23 15:33:55 +00:00
// detecte les deplacements de parties
2009-04-03 19:30:25 +00:00
QGraphicsScene : : mouseReleaseEvent ( e ) ;
moving_parts_ = false ;
2007-06-30 17:41:07 +00:00
}
} else if ( e - > button ( ) & Qt : : RightButton ) {
2008-01-20 20:28:52 +00:00
if ( behavior = = Polygon & & current_polygon ! = NULL ) {
2007-08-23 15:33:55 +00:00
undo_stack . push ( new AddPartCommand ( tr ( " polygone " ) , this , current_polygon ) ) ;
2007-06-30 17:41:07 +00:00
current_polygon = NULL ;
2007-11-07 20:23:24 +00:00
emit ( partsAdded ( ) ) ;
2009-04-03 19:30:25 +00:00
endCurrentBehavior ( e ) ;
2007-06-30 17:41:07 +00:00
} else QGraphicsScene : : mouseReleaseEvent ( e ) ;
} else QGraphicsScene : : mouseReleaseEvent ( e ) ;
}
/**
2007-10-21 16:10:21 +00:00
Dessine l ' arriere - plan de l ' editeur , cad l ' indicateur de hotspot .
2007-06-30 17:41:07 +00:00
@ param p Le QPainter a utiliser pour dessiner
2009-11-22 16:12:22 +00:00
@ param rect Le rectangle de la zone a dessiner
2007-06-30 17:41:07 +00:00
*/
2009-11-22 16:12:22 +00:00
void ElementScene : : drawForeground ( QPainter * p , const QRectF & rect ) {
Q_UNUSED ( rect ) ;
2007-06-30 17:41:07 +00:00
p - > save ( ) ;
// desactive tout antialiasing, sauf pour le texte
p - > setRenderHint ( QPainter : : Antialiasing , false ) ;
p - > setRenderHint ( QPainter : : TextAntialiasing , true ) ;
p - > setRenderHint ( QPainter : : SmoothPixmapTransform , false ) ;
p - > setPen ( Qt : : red ) ;
p - > setBrush ( Qt : : NoBrush ) ;
2013-08-05 13:20:57 +00:00
p - > drawLine ( - 20 , 0 , 20 , 0 ) ;
p - > drawLine ( 0 , - 20 , 0 , 20 ) ;
2007-06-30 17:41:07 +00:00
p - > restore ( ) ;
}
2009-04-03 19:30:25 +00:00
/**
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 .
2009-11-22 16:12:22 +00:00
@ param event objet decrivant l ' evenement souris
2009-04-03 19:30:25 +00:00
*/
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 ) ;
}
/**
2009-11-22 16:12:22 +00:00
@ param x_g Taille horizontale de la grille
@ param y_g Taille verticale de la grille
2009-04-03 19:30:25 +00:00
*/
void ElementScene : : setGrid ( int x_g , int y_g ) {
x_grid = x_g ? x_g : 1 ;
y_grid = y_g ? y_g : 1 ;
}
2007-12-05 21:16:01 +00:00
/**
Exporte l ' element en XML
2009-11-22 16:12:22 +00:00
@ param all_parts Booleen ( a vrai par defaut ) indiquant si le XML genere doit
2009-04-03 19:30:25 +00:00
representer tout l ' element ou seulement les elements selectionnes
2007-12-05 21:16:01 +00:00
@ return un document XML decrivant l ' element
*/
2009-04-03 19:30:25 +00:00
const QDomDocument ElementScene : : toXml ( bool all_parts ) const {
2013-07-28 00:23:10 +00:00
//define the size of the element by the upper multiple of 10
QRectF size = elementSceneGeometricRect ( ) ;
2013-08-01 23:17:39 +00:00
int upwidth = ( ( qRound ( size . width ( ) ) / 10 ) * 10 ) + 10 ;
if ( ( qRound ( size . width ( ) ) % 10 ) > 6 ) upwidth + = 10 ;
2013-07-28 00:23:10 +00:00
2013-08-01 23:17:39 +00:00
int upheight = ( ( qRound ( size . height ( ) ) / 10 ) * 10 ) + 10 ;
if ( ( qRound ( size . height ( ) ) % 10 ) > 6 ) upheight + = 10 ;
2013-07-28 00:23:10 +00:00
2013-08-01 23:17:39 +00:00
//the margin between the real size of the element and the rectangle that delimits
int xmargin = qRound ( upwidth - size . width ( ) ) ;
int ymargin = qRound ( upheight - size . height ( ) ) ;
// document XML
QDomDocument xml_document ;
2007-06-30 17:41:07 +00:00
// racine du document XML
QDomElement root = xml_document . createElement ( " definition " ) ;
root . setAttribute ( " type " , " element " ) ;
2013-08-01 23:17:39 +00:00
root . setAttribute ( " width " , QString ( " %1 " ) . arg ( upwidth ) ) ;
root . setAttribute ( " height " , QString ( " %1 " ) . arg ( upheight ) ) ;
root . setAttribute ( " hotspot_x " , QString ( " %1 " ) . arg ( - ( qRound ( size . x ( ) - ( xmargin / 2 ) ) ) ) ) ;
root . setAttribute ( " hotspot_y " , QString ( " %1 " ) . arg ( - ( qRound ( size . y ( ) - ( ymargin / 2 ) ) ) ) ) ;
2007-06-30 17:41:07 +00:00
root . setAttribute ( " orientation " , ori . toString ( ) ) ;
2007-10-04 17:32:41 +00:00
root . setAttribute ( " version " , QET : : version ) ;
2007-12-09 10:30:35 +00:00
if ( internal_connections ) root . setAttribute ( " ic " , " true " ) ;
2007-06-30 17:41:07 +00:00
// noms de l'element
root . appendChild ( _names . toXml ( xml_document ) ) ;
2010-02-14 16:28:45 +00:00
// informations complementaires de l'element
QDomElement informations_element = xml_document . createElement ( " informations " ) ;
root . appendChild ( informations_element ) ;
informations_element . appendChild ( xml_document . createTextNode ( informations ( ) ) ) ;
2007-06-30 17:41:07 +00:00
QDomElement description = xml_document . createElement ( " description " ) ;
// description de l'element
2013-02-08 22:05:20 +00:00
foreach ( QGraphicsItem * qgi , zItems ( ) ) {
2009-04-03 19:30:25 +00:00
// si l'export ne concerne que la selection, on ignore les parties non selectionnees
if ( ! all_parts & & ! qgi - > isSelected ( ) ) continue ;
2007-06-30 17:41:07 +00:00
if ( CustomElementPart * ce = dynamic_cast < CustomElementPart * > ( qgi ) ) {
2007-12-15 21:57:00 +00:00
if ( ce - > isUseless ( ) ) continue ;
2007-06-30 17:41:07 +00:00
description . appendChild ( ce - > toXml ( xml_document ) ) ;
}
}
root . appendChild ( description ) ;
xml_document . appendChild ( root ) ;
return ( xml_document ) ;
}
2007-12-05 21:16:01 +00:00
/**
2009-04-03 19:30:25 +00:00
@ param xml_document un document XML decrivant un element
@ return le boundingRect du contenu de l ' element
2007-12-05 21:16:01 +00:00
*/
2009-04-03 19:30:25 +00:00
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 ) ;
2007-06-30 17:41:07 +00:00
2009-04-03 19:30:25 +00:00
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
) {
2007-06-30 17:41:07 +00:00
QString error_message ;
bool state = true ;
2009-04-03 19:30:25 +00:00
// prend en compte les informations de l'element
if ( consider_informations ) {
state = applyInformations ( xml_document , & error_message ) ;
2007-06-30 17:41:07 +00:00
}
2009-04-03 19:30:25 +00:00
// parcours des enfants de la definition : parties de l'element
2007-06-30 17:41:07 +00:00
if ( state ) {
2009-04-03 19:30:25 +00:00
ElementContent loaded_content = loadContent ( xml_document , & error_message ) ;
if ( position ! = QPointF ( ) ) {
addContentAtPos ( loaded_content , position , & error_message ) ;
2007-06-30 17:41:07 +00:00
} else {
2009-04-03 19:30:25 +00:00
addContent ( loaded_content , & error_message ) ;
2007-06-30 17:41:07 +00:00
}
2007-12-09 10:30:35 +00:00
2009-04-03 19:30:25 +00:00
// renvoie le contenu ajoute a l'element
if ( content_ptr ) {
* content_ptr = loaded_content ;
2007-06-30 17:41:07 +00:00
}
}
}
2013-07-28 00:23:10 +00:00
/**
@ return the minimum , margin - less rectangle the element can fit into , in scene
coordinates . It is different from itemsBoundingRect ( ) because it is not supposed
to imply any margin .
*/
QRectF ElementScene : : elementSceneGeometricRect ( ) const {
QRectF esgr ;
foreach ( QGraphicsItem * qgi , items ( ) ) {
if ( qgi - > type ( ) = = ElementPrimitiveDecorator : : Type ) continue ;
if ( qgi - > type ( ) = = QGraphicsRectItem : : Type ) continue ;
if ( CustomElementPart * cep = dynamic_cast < CustomElementPart * > ( qgi ) ) {
esgr | = cep - > sceneGeometricRect ( ) ;
}
}
return ( esgr ) ;
}
2009-06-01 02:05:20 +00:00
/**
@ return true si l ' element comporte au moins une borne , false s ' il n ' en a
aucune .
*/
bool ElementScene : : containsTerminals ( ) const {
foreach ( QGraphicsItem * qgi , items ( ) ) {
if ( qgraphicsitem_cast < PartTerminal * > ( qgi ) ) {
return ( true ) ;
}
}
return ( false ) ;
}
2007-12-05 21:16:01 +00:00
/**
@ return la pile d ' annulations de cet editeur d ' element
*/
2007-08-25 03:43:05 +00:00
QUndoStack & ElementScene : : undoStack ( ) {
2007-08-23 15:33:55 +00:00
return ( undo_stack ) ;
}
2007-12-05 21:16:01 +00:00
/**
@ return le gestionnaire de QGraphicsItem de cet editeur d ' element
*/
2007-08-25 03:43:05 +00:00
QGIManager & ElementScene : : qgiManager ( ) {
2007-08-23 15:33:55 +00:00
return ( qgi_manager ) ;
}
2009-04-03 19:30:25 +00:00
/**
@ 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 ( ) {
}
2007-12-05 21:16:01 +00:00
/**
2009-04-18 18:08:54 +00:00
Selectionne une liste de parties
@ param content liste des parties a selectionner
2007-12-05 21:16:01 +00:00
*/
2009-04-18 18:08:54 +00:00
void ElementScene : : slot_select ( const ElementContent & content ) {
2009-04-18 14:21:08 +00:00
blockSignals ( true ) ;
2010-02-28 16:13:45 +00:00
clearSelection ( ) ;
2009-04-18 18:08:54 +00:00
foreach ( QGraphicsItem * qgi , content ) qgi - > setSelected ( true ) ;
2009-04-18 14:21:08 +00:00
blockSignals ( false ) ;
emit ( selectionChanged ( ) ) ;
2007-06-30 17:41:07 +00:00
}
2009-04-18 18:08:54 +00:00
/**
Selectionne tout
*/
void ElementScene : : slot_selectAll ( ) {
slot_select ( items ( ) ) ;
}
2007-12-05 21:16:01 +00:00
/**
Deselectionne tout
*/
2007-08-25 03:43:05 +00:00
void ElementScene : : slot_deselectAll ( ) {
2010-02-28 16:13:45 +00:00
slot_select ( ElementContent ( ) ) ;
2007-06-30 17:41:07 +00:00
}
2007-12-05 21:16:01 +00:00
/**
Inverse la selection
*/
2007-08-25 03:43:05 +00:00
void ElementScene : : slot_invertSelection ( ) {
2009-04-18 14:21:08 +00:00
blockSignals ( true ) ;
2007-06-30 17:41:07 +00:00
foreach ( QGraphicsItem * qgi , items ( ) ) qgi - > setSelected ( ! qgi - > isSelected ( ) ) ;
2009-04-18 14:21:08 +00:00
blockSignals ( false ) ;
emit ( selectionChanged ( ) ) ;
2007-06-30 17:41:07 +00:00
}
2007-12-05 21:16:01 +00:00
/**
Supprime les elements selectionnes
*/
2007-08-25 03:43:05 +00:00
void ElementScene : : slot_delete ( ) {
2007-06-30 17:41:07 +00:00
// verifie qu'il y a qqc de selectionne
QList < QGraphicsItem * > selected_items = selectedItems ( ) ;
if ( selected_items . isEmpty ( ) ) return ;
// efface tout ce qui est selectionne
2007-08-23 15:33:55 +00:00
undo_stack . push ( new DeletePartsCommand ( this , selected_items ) ) ;
2013-02-08 22:05:15 +00:00
// removing items does not trigger QGraphicsScene::selectionChanged()
2007-11-07 20:23:24 +00:00
emit ( partsRemoved ( ) ) ;
2013-02-08 22:05:15 +00:00
emit ( selectionChanged ( ) ) ;
2007-06-30 17:41:07 +00:00
}
2007-12-05 21:16:01 +00:00
/**
Lance un dialogue pour editer les noms de cete element
*/
2007-08-25 03:43:05 +00:00
void ElementScene : : slot_editOrientations ( ) {
2010-02-28 16:13:45 +00:00
bool is_read_only = element_editor & & element_editor - > isReadOnly ( ) ;
2007-06-30 17:41:07 +00:00
// cree un dialogue
2008-08-17 20:41:37 +00:00
QDialog dialog_ori ( element_editor ) ;
2007-06-30 17:41:07 +00:00
dialog_ori . setModal ( true ) ;
2009-08-09 16:43:03 +00:00
# ifdef Q_WS_MAC
dialog_ori . setWindowFlags ( Qt : : Sheet ) ;
# endif
2007-12-19 21:44:43 +00:00
dialog_ori . setMinimumSize ( 400 , 260 ) ;
2009-04-03 19:30:25 +00:00
dialog_ori . setWindowTitle ( tr ( " \311 diter les orientations " , " window title " ) ) ;
2007-06-30 17:41:07 +00:00
QVBoxLayout * dialog_layout = new QVBoxLayout ( & dialog_ori ) ;
// ajoute un champ explicatif au dialogue
QLabel * information_label = new QLabel ( tr ( " L'orientation par d \351 faut est l'orientation dans laquelle s'effectue la cr \351 ation de l' \351 l \351 ment. " ) ) ;
information_label - > setAlignment ( Qt : : AlignJustify | Qt : : AlignVCenter ) ;
information_label - > setWordWrap ( true ) ;
dialog_layout - > addWidget ( information_label ) ;
// ajoute un OrientationSetWidget au dialogue
OrientationSetWidget * ori_widget = new OrientationSetWidget ( ) ;
ori_widget - > setOrientationSet ( ori ) ;
2010-02-28 16:13:45 +00:00
ori_widget - > setReadOnly ( is_read_only ) ;
2007-06-30 17:41:07 +00:00
dialog_layout - > addWidget ( ori_widget ) ;
2007-12-09 10:54:59 +00:00
// ajoute une case a cocher pour les connexions internes
QCheckBox * ic_checkbox = new QCheckBox ( tr ( " Autoriser les connexions internes " ) ) ;
ic_checkbox - > setChecked ( internal_connections ) ;
2010-02-28 16:13:45 +00:00
ic_checkbox - > setDisabled ( is_read_only ) ;
2007-12-09 10:54:59 +00:00
dialog_layout - > addWidget ( ic_checkbox ) ;
2007-12-19 21:44:43 +00:00
dialog_layout - > addStretch ( ) ;
2007-06-30 17:41:07 +00:00
// ajoute deux boutons au dialogue
2010-02-28 16:13:45 +00:00
QDialogButtonBox * dialog_buttons = new QDialogButtonBox ( is_read_only ? QDialogButtonBox : : Ok : QDialogButtonBox : : Ok | QDialogButtonBox : : Cancel ) ;
2007-06-30 17:41:07 +00:00
dialog_layout - > addWidget ( dialog_buttons ) ;
connect ( dialog_buttons , SIGNAL ( accepted ( ) ) , & dialog_ori , SLOT ( accept ( ) ) ) ;
connect ( dialog_buttons , SIGNAL ( rejected ( ) ) , & dialog_ori , SLOT ( reject ( ) ) ) ;
// lance le dialogue
2010-02-28 16:13:45 +00:00
if ( dialog_ori . exec ( ) = = QDialog : : Accepted & & ! is_read_only ) {
2007-09-10 22:11:47 +00:00
OrientationSet new_ori = ori_widget - > orientationSet ( ) ;
if ( new_ori ! = ori ) {
undoStack ( ) . push ( new ChangeOrientationsCommand ( this , ori , new_ori ) ) ;
}
2007-12-09 10:54:59 +00:00
if ( ic_checkbox - > isChecked ( ) ! = internal_connections ) {
undoStack ( ) . push ( new AllowInternalConnectionsCommand ( this , ic_checkbox - > isChecked ( ) ) ) ;
}
2007-09-10 22:11:47 +00:00
}
2007-06-30 17:41:07 +00:00
}
2010-02-14 16:28:45 +00:00
/**
Lance un dialogue pour editer les informations complementaires de cet
element . Concretement , ce champ libre est destine a accueillir des informations
sur l ' auteur de l ' element , sa licence , etc .
*/
void ElementScene : : slot_editAuthorInformations ( ) {
2010-02-28 16:13:45 +00:00
bool is_read_only = element_editor & & element_editor - > isReadOnly ( ) ;
2010-02-14 16:28:45 +00:00
// cree un dialogue
QDialog dialog_author ( element_editor ) ;
dialog_author . setModal ( true ) ;
# ifdef Q_WS_MAC
dialog_author . setWindowFlags ( Qt : : Sheet ) ;
# endif
dialog_author . setMinimumSize ( 400 , 260 ) ;
dialog_author . setWindowTitle ( tr ( " \311 diter les informations sur l'auteur " , " window title " ) ) ;
QVBoxLayout * dialog_layout = new QVBoxLayout ( & dialog_author ) ;
// ajoute un champ explicatif au dialogue
QLabel * information_label = new QLabel ( tr ( " Vous pouvez utiliser ce champ libre pour mentionner les auteurs de l' \351 l \351 ment, sa licence, ou tout autre renseignement que vous jugerez utile. " ) ) ;
information_label - > setAlignment ( Qt : : AlignJustify | Qt : : AlignVCenter ) ;
information_label - > setWordWrap ( true ) ;
dialog_layout - > addWidget ( information_label ) ;
// ajoute un QTextEdit au dialogue
QTextEdit * text_field = new QTextEdit ( ) ;
text_field - > setAcceptRichText ( false ) ;
text_field - > setPlainText ( informations ( ) ) ;
2010-02-28 16:13:45 +00:00
text_field - > setReadOnly ( is_read_only ) ;
2010-02-14 16:28:45 +00:00
dialog_layout - > addWidget ( text_field ) ;
// ajoute deux boutons au dialogue
2010-02-28 16:13:45 +00:00
QDialogButtonBox * dialog_buttons = new QDialogButtonBox ( is_read_only ? QDialogButtonBox : : Ok : QDialogButtonBox : : Ok | QDialogButtonBox : : Cancel ) ;
2010-02-14 16:28:45 +00:00
dialog_layout - > addWidget ( dialog_buttons ) ;
connect ( dialog_buttons , SIGNAL ( accepted ( ) ) , & dialog_author , SLOT ( accept ( ) ) ) ;
connect ( dialog_buttons , SIGNAL ( rejected ( ) ) , & dialog_author , SLOT ( reject ( ) ) ) ;
// lance le dialogue
2010-02-28 16:13:45 +00:00
if ( dialog_author . exec ( ) = = QDialog : : Accepted & & ! is_read_only ) {
2012-04-09 01:03:11 +00:00
QString new_infos = text_field - > toPlainText ( ) . remove ( QChar ( 13 ) ) ; // CR-less text
2010-02-14 16:28:45 +00:00
if ( new_infos ! = informations ( ) ) {
undoStack ( ) . push ( new ChangeInformationsCommand ( this , informations ( ) , new_infos ) ) ;
}
}
}
2007-12-05 21:16:01 +00:00
/**
Lance un dialogue pour editer les noms de cet element
*/
2007-08-25 03:43:05 +00:00
void ElementScene : : slot_editNames ( ) {
2010-02-28 16:13:45 +00:00
bool is_read_only = element_editor & & element_editor - > isReadOnly ( ) ;
2007-06-30 17:41:07 +00:00
// cree un dialogue
2008-08-17 20:41:37 +00:00
QDialog dialog ( element_editor ) ;
2009-08-09 16:43:03 +00:00
# ifdef Q_WS_MAC
dialog . setWindowFlags ( Qt : : Sheet ) ;
# endif
2007-06-30 17:41:07 +00:00
dialog . setModal ( true ) ;
2007-12-19 21:44:43 +00:00
dialog . setMinimumSize ( 400 , 330 ) ;
2009-04-03 19:30:25 +00:00
dialog . setWindowTitle ( tr ( " \311 diter les noms " , " window title " ) ) ;
2007-06-30 17:41:07 +00:00
QVBoxLayout * dialog_layout = new QVBoxLayout ( & dialog ) ;
// ajoute un champ explicatif au dialogue
QLabel * information_label = new QLabel ( tr ( " Vous pouvez sp \351 cifier le nom de l' \351 l \351 ment dans plusieurs langues. " ) ) ;
information_label - > setAlignment ( Qt : : AlignJustify | Qt : : AlignVCenter ) ;
information_label - > setWordWrap ( true ) ;
dialog_layout - > addWidget ( information_label ) ;
// ajoute un NamesListWidget au dialogue
NamesListWidget * names_widget = new NamesListWidget ( ) ;
names_widget - > setNames ( _names ) ;
2010-02-28 16:13:45 +00:00
names_widget - > setReadOnly ( is_read_only ) ;
2007-06-30 17:41:07 +00:00
dialog_layout - > addWidget ( names_widget ) ;
// ajoute deux boutons au dialogue
2010-02-28 16:13:45 +00:00
QDialogButtonBox * dialog_buttons = new QDialogButtonBox ( is_read_only ? QDialogButtonBox : : Ok : QDialogButtonBox : : Ok | QDialogButtonBox : : Cancel ) ;
2007-06-30 17:41:07 +00:00
dialog_layout - > addWidget ( dialog_buttons ) ;
connect ( dialog_buttons , SIGNAL ( accepted ( ) ) , names_widget , SLOT ( check ( ) ) ) ;
connect ( names_widget , SIGNAL ( inputChecked ( ) ) , & dialog , SLOT ( accept ( ) ) ) ;
connect ( dialog_buttons , SIGNAL ( rejected ( ) ) , & dialog , SLOT ( reject ( ) ) ) ;
// lance le dialogue
2010-02-28 16:13:45 +00:00
if ( dialog . exec ( ) = = QDialog : : Accepted & & ! is_read_only ) {
2007-09-10 21:50:17 +00:00
NamesList new_names ( names_widget - > names ( ) ) ;
if ( new_names ! = _names ) undoStack ( ) . push ( new ChangeNamesCommand ( this , _names , new_names ) ) ;
}
2007-06-30 17:41:07 +00:00
}
2007-10-07 18:52:01 +00:00
/**
Amene les elements selectionnes au premier plan
*/
void ElementScene : : slot_bringForward ( ) {
undoStack ( ) . push ( new ChangeZValueCommand ( this , ChangeZValueCommand : : BringForward ) ) ;
2007-11-07 20:23:24 +00:00
emit ( partsZValueChanged ( ) ) ;
2007-10-07 18:52:01 +00:00
}
/**
Remonte les elements selectionnes d ' un plan
*/
void ElementScene : : slot_raise ( ) {
undoStack ( ) . push ( new ChangeZValueCommand ( this , ChangeZValueCommand : : Raise ) ) ;
2007-11-07 20:23:24 +00:00
emit ( partsZValueChanged ( ) ) ;
2007-10-07 18:52:01 +00:00
}
/**
Descend les elements selectionnes d ' un plan
*/
void ElementScene : : slot_lower ( ) {
undoStack ( ) . push ( new ChangeZValueCommand ( this , ChangeZValueCommand : : Lower ) ) ;
2007-11-07 20:23:24 +00:00
emit ( partsZValueChanged ( ) ) ;
2007-10-07 18:52:01 +00:00
}
/**
Envoie les elements selectionnes au fond
*/
void ElementScene : : slot_sendBackward ( ) {
undoStack ( ) . push ( new ChangeZValueCommand ( this , ChangeZValueCommand : : SendBackward ) ) ;
2007-11-07 20:23:24 +00:00
emit ( partsZValueChanged ( ) ) ;
2007-10-07 18:52:01 +00:00
}
2013-02-08 22:05:15 +00:00
/**
@ return the list of primitives currently present on the scene .
*/
QList < CustomElementPart * > ElementScene : : primitives ( ) const {
QList < CustomElementPart * > primitives_list ;
foreach ( QGraphicsItem * item , items ( ) ) {
if ( CustomElementPart * primitive = dynamic_cast < CustomElementPart * > ( item ) ) {
primitives_list < < primitive ;
}
}
return ( primitives_list ) ;
}
2007-10-07 18:52:01 +00:00
/**
@ param include_terminals true pour inclure les bornes , false sinon
@ return les parties de l ' element ordonnes par zValue croissante
*/
2013-02-08 22:05:20 +00:00
QList < QGraphicsItem * > ElementScene : : zItems ( ItemOptions options ) const {
// handle dummy request, i.e. when neither Selected nor NonSelected are set
if ( ! ( options & ElementScene : : Selected ) & & ! ( options & ElementScene : : NonSelected ) ) {
return ( QList < QGraphicsItem * > ( ) ) ;
}
// retrieve all items
2007-10-07 18:52:01 +00:00
QList < QGraphicsItem * > all_items_list ( items ( ) ) ;
2013-02-08 22:05:20 +00:00
QMutableListIterator < QGraphicsItem * > i ( all_items_list ) ;
// remove unrequired items
if ( ( options & ElementScene : : SelectedOrNot ) ! = ElementScene : : SelectedOrNot ) {
bool keep_selected = options & ElementScene : : Selected ;
while ( i . hasNext ( ) ) {
if ( i . next ( ) - > isSelected ( ) ! = keep_selected ) {
i . remove ( ) ;
}
}
}
2007-10-07 18:52:01 +00:00
QList < QGraphicsItem * > terminals ;
2013-02-08 22:05:20 +00:00
QList < QGraphicsItem * > helpers ;
for ( i . toFront ( ) ; i . hasNext ( ) ; ) {
i . next ( ) ;
QGraphicsItem * qgi = i . value ( ) ;
2013-02-08 22:05:15 +00:00
if (
qgi - > type ( ) = = ElementPrimitiveDecorator : : Type | |
qgi - > type ( ) = = QGraphicsRectItem : : Type
) {
2013-02-08 22:05:20 +00:00
i . remove ( ) ;
helpers < < qgi ;
2013-02-08 22:05:15 +00:00
}
else if ( qgraphicsitem_cast < PartTerminal * > ( qgi ) ) {
2013-02-08 22:05:20 +00:00
i . remove ( ) ;
2007-10-07 18:52:01 +00:00
terminals < < qgi ;
}
}
// ordonne les parties par leur zValue
2013-02-08 22:05:20 +00:00
if ( options & SortByZValue ) {
qSort ( all_items_list . begin ( ) , all_items_list . end ( ) , ElementScene : : zValueLessThan ) ;
}
2007-10-07 18:52:01 +00:00
// rajoute eventuellement les bornes
2013-02-08 22:05:20 +00:00
if ( options & ElementScene : : IncludeTerminals ) {
all_items_list + = terminals ;
}
if ( options & ElementScene : : IncludeHelperItems ) {
all_items_list + = helpers ;
}
2007-10-07 18:52:01 +00:00
return ( all_items_list ) ;
}
2007-12-09 12:00:11 +00:00
2009-04-03 19:30:25 +00:00
/**
@ return les parties graphiques selectionnees
*/
ElementContent ElementScene : : selectedContent ( ) const {
ElementContent content ;
2013-02-08 22:05:20 +00:00
foreach ( QGraphicsItem * qgi , zItems ( ) ) {
2009-04-03 19:30:25 +00:00
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 ;
}
2007-12-09 12:00:11 +00:00
/**
Supprime les parties de l ' element et les objets d ' annulations .
Les autres caracteristiques sont conservees .
*/
void ElementScene : : reset ( ) {
// supprime les objets d'annulation
undoStack ( ) . clear ( ) ;
2013-07-28 22:48:36 +00:00
2007-12-09 12:00:11 +00:00
// enleve les elements de la scene
2013-07-28 22:48:36 +00:00
foreach ( QGraphicsItem * qgi , items ( ) ) {
2013-07-28 21:55:02 +00:00
removeItem ( qgi ) ;
2013-07-28 22:48:36 +00:00
qgiManager ( ) . release ( qgi ) ;
2007-12-09 12:00:11 +00:00
}
2013-07-28 22:48:36 +00:00
decorator_ = 0 ;
2007-12-09 12:00:11 +00:00
}
2009-04-03 19:30:25 +00:00
/**
@ param content Contenu ( = parties ) d ' un element
@ return le boundingRect de ces parties , exprime dans les coordonnes de la
scene
*/
2013-02-08 22:05:15 +00:00
QRectF ElementScene : : elementContentBoundingRect ( const ElementContent & content ) const {
2009-04-03 19:30:25 +00:00
QRectF bounding_rect ;
foreach ( QGraphicsItem * qgi , content ) {
2013-02-08 22:05:15 +00:00
// skip non-primitives QGraphicsItems (paste area, selection decorator)
if ( qgi - > type ( ) = = ElementPrimitiveDecorator : : Type ) continue ;
if ( qgi - > type ( ) = = QGraphicsRectItem : : Type ) continue ;
2009-04-03 19:30:25 +00:00
bounding_rect | = qgi - > sceneBoundingRect ( ) ;
}
return ( bounding_rect ) ;
}
/**
Applique les informations ( dimensions , hostpot , orientations , connexions
2010-02-14 16:28:45 +00:00
internes , noms et informations complementaires ) contenu dans un document XML .
2009-04-03 19:30:25 +00:00
@ 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 \351 finition d' \351 l \351 ment. " , " error message " ) ;
}
return ( false ) ;
}
2013-08-05 13:20:57 +00:00
2009-04-03 19:30:25 +00:00
// 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 ) ;
2010-02-14 16:28:45 +00:00
// extrait les informations complementaires
setInformations ( QString ( ) ) ;
for ( QDomNode node = root . firstChild ( ) ; ! node . isNull ( ) ; node = node . nextSibling ( ) ) {
QDomElement elmt = node . toElement ( ) ;
if ( elmt . isNull ( ) ) continue ;
if ( elmt . tagName ( ) = = " informations " ) {
setInformations ( elmt . text ( ) ) ;
break ;
}
}
2009-04-03 19:30:25 +00:00
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 \351 finition d' \351 l \351 ment. " , " 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 ) ;
2013-02-11 21:45:51 +00:00
else if ( qde . tagName ( ) = = " circle " ) cep = new PartEllipse ( element_editor , 0 , 0 ) ;
2009-04-03 19:30:25 +00:00
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 ) ) {
2012-05-11 21:27:31 +00:00
if ( ! qgi - > zValue ( ) ) qgi - > setZValue ( z + + ) ;
2009-04-03 19:30:25 +00:00
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
*/
2009-11-22 16:12:22 +00:00
ElementContent ElementScene : : addContent ( const ElementContent & content , QString * error_message ) {
Q_UNUSED ( error_message ) ;
2009-04-03 19:30:25 +00:00
foreach ( QGraphicsItem * part , content ) {
2013-02-08 22:05:15 +00:00
addPrimitive ( part ) ;
2009-04-03 19:30:25 +00:00
}
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
*/
2009-11-22 16:12:22 +00:00
ElementContent ElementScene : : addContentAtPos ( const ElementContent & content , const QPointF & pos , QString * error_message ) {
Q_UNUSED ( error_message ) ;
2009-04-03 19:30:25 +00:00
// 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 ) ;
2013-02-08 22:05:15 +00:00
addPrimitive ( part ) ;
2009-04-03 19:30:25 +00:00
}
return ( content ) ;
}
2013-02-08 22:05:15 +00:00
/**
Add a primitive to the scene by wrapping it within an
ElementPrimitiveDecorator group .
*/
void ElementScene : : addPrimitive ( QGraphicsItem * primitive ) {
if ( ! primitive ) return ;
addItem ( primitive ) ;
}
2009-04-03 19:30:25 +00:00
/**
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 ) ) ;
}
2012-05-11 21:38:50 +00:00
/**
@ return true if \ a item1 ' s zValue ( ) is less than \ a item2 ' s .
*/
bool ElementScene : : zValueLessThan ( QGraphicsItem * item1 , QGraphicsItem * item2 ) {
return ( item1 - > zValue ( ) < item2 - > zValue ( ) ) ;
}
2013-02-08 22:05:15 +00:00
/**
Ensure the decorator is adequately shown , hidden or updated so it always
represents the current selection .
*/
void ElementScene : : managePrimitivesGroups ( ) {
2013-02-08 22:05:20 +00:00
// this function is not supposed to be reentrant
2013-02-08 22:05:15 +00:00
if ( ! decorator_lock_ - > tryLock ( ) ) return ;
if ( ! decorator_ ) {
decorator_ = new ElementPrimitiveDecorator ( ) ;
connect ( decorator_ , SIGNAL ( actionFinished ( ElementEditionCommand * ) ) , this , SLOT ( stackAction ( ElementEditionCommand * ) ) ) ;
addItem ( decorator_ ) ;
decorator_ - > hide ( ) ;
}
// should we hide the decorator?
2013-02-08 22:05:20 +00:00
QList < QGraphicsItem * > selected_items = zItems ( ElementScene : : Selected | ElementScene : : IncludeTerminals ) ;
2013-02-08 22:05:15 +00:00
if ( ! selected_items . count ( ) ) {
decorator_ - > hide ( ) ;
} else {
decorator_ - > setZValue ( 1000000 ) ;
decorator_ - > setPos ( 0 , 0 ) ;
decorator_ - > setItems ( selected_items ) ;
}
decorator_lock_ - > unlock ( ) ;
}
/**
Push the provided \ a command on the undo stack .
*/
void ElementScene : : stackAction ( ElementEditionCommand * command ) {
if ( command - > elementScene ( ) ) {
if ( command - > elementScene ( ) ! = this ) return ;
} else {
command - > setElementScene ( this ) ;
}
if ( ! command - > elementView ( ) ) {
foreach ( QGraphicsView * view , views ( ) ) {
if ( ElementView * element_view = dynamic_cast < ElementView * > ( view ) ) {
command - > setElementView ( element_view ) ;
break ;
}
}
}
undoStack ( ) . push ( command ) ;
}