2007-12-01 10:47:15 +00:00
/*
2010-01-03 16:25:37 +00:00
Copyright 2006 - 2010 Xavier Guerrin
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"
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 "partcircle.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-18 22:59:10 +00:00
# include "hotspoteditor.h"
2007-08-23 15:33:55 +00:00
# include "editorcommands.h"
2009-04-03 19:30:25 +00:00
# include "elementcontent.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 ) ,
_width ( 3 ) ,
_height ( 7 ) ,
2007-08-23 15:33:55 +00:00
_hotspot ( 15 , 35 ) ,
2007-12-09 10:30:35 +00:00
internal_connections ( false ) ,
2007-08-25 03:43:05 +00:00
qgi_manager ( this ) ,
element_editor ( editor )
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 ( ) ;
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 ( ) {
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 ;
qreal radius ;
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 Circle :
temp_rect = current_circle - > rect ( ) ;
2009-04-03 19:30:25 +00:00
temp_point = event_pos - current_circle - > mapToScene ( temp_rect . center ( ) ) ;
2007-06-30 17:41:07 +00:00
radius = sqrt ( pow ( temp_point . x ( ) , 2 ) + pow ( temp_point . y ( ) , 2 ) ) ;
temp_rect = QRectF (
temp_rect . center ( ) - QPointF ( radius , radius ) ,
QSizeF ( 2.0 * radius , 2.0 * radius )
) ;
current_circle - > setRect ( temp_rect ) ;
break ;
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 :
2009-04-03 19:30:25 +00:00
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 ( ) ) ;
}
}
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 Circle :
2007-08-25 03:43:05 +00:00
current_circle = new PartCircle ( element_editor , 0 , this ) ;
2009-04-03 19:30:25 +00:00
current_circle - > setRect ( QRectF ( event_pos , QSizeF ( 0.0 , 0.0 ) ) ) ;
2007-10-06 19:46:44 +00:00
current_circle - > setProperty ( " antialias " , true ) ;
2007-06-30 17:41:07 +00:00
break ;
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 ) ;
2009-04-03 19:30:25 +00:00
// 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 ;
}
2007-06-30 17:41:07 +00:00
}
} 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 Circle :
2007-12-15 21:57:00 +00:00
if ( qgiManager ( ) . manages ( current_circle ) ) break ;
2007-06-30 17:41:07 +00:00
current_circle - > setRect ( current_circle - > rect ( ) . normalized ( ) ) ;
2007-08-23 15:33:55 +00:00
undo_stack . push ( new AddPartCommand ( tr ( " cercle " ) , this , current_circle ) ) ;
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 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
if ( ! selectedItems ( ) . isEmpty ( ) & & moving_parts_ ) {
2007-09-21 11:48:37 +00:00
QPointF movement = selectedItems ( ) . first ( ) - > scenePos ( ) - fsi_pos ;
2007-08-23 15:33:55 +00:00
if ( ! movement . isNull ( ) ) {
undo_stack . push ( new MovePartsCommand ( movement , this , selectedItems ( ) ) ) ;
}
}
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 ) ;
}
2009-11-29 22:20:09 +00:00
/**
Gere les enfoncements de touches du clavier
@ param e QKeyEvent decrivant l ' evenement clavier
*/
void ElementScene : : keyPressEvent ( QKeyEvent * e ) {
bool is_read_only = element_editor & & element_editor - > isReadOnly ( ) ;
if ( ! is_read_only ) {
const qreal movement_length = 1.0 ;
QPointF movement ;
switch ( e - > key ( ) ) {
case Qt : : Key_Left : movement = QPointF ( - movement_length , 0.0 ) ; break ;
case Qt : : Key_Right : movement = QPointF ( + movement_length , 0.0 ) ; break ;
case Qt : : Key_Up : movement = QPointF ( 0.0 , - movement_length ) ; break ;
case Qt : : Key_Down : movement = QPointF ( 0.0 , + movement_length ) ; break ;
}
if ( ! movement . isNull ( ) & & ! focusItem ( ) ) {
if ( ! moving_parts_ ) {
moving_parts_ = true ;
fsi_pos = movement ;
} else {
fsi_pos + = movement ;
}
foreach ( QGraphicsItem * qgi , selectedItems ( ) ) {
qgi - > setPos ( qgi - > pos ( ) + movement ) ;
}
}
}
QGraphicsScene : : keyPressEvent ( e ) ;
}
/**
Gere les relachements de touches du clavier
@ param e QKeyEvent decrivant l ' evenement clavier
*/
void ElementScene : : keyReleaseEvent ( QKeyEvent * e ) {
bool is_read_only = element_editor & & element_editor - > isReadOnly ( ) ;
if ( ! is_read_only ) {
// detecte le relachement d'une touche de direction ( = deplacement de parties)
if (
( e - > key ( ) = = Qt : : Key_Left | | e - > key ( ) = = Qt : : Key_Right | | \
e - > key ( ) = = Qt : : Key_Up | | e - > key ( ) = = Qt : : Key_Down ) & & \
moving_parts_ & & ! e - > isAutoRepeat ( )
) {
// cree un objet d'annulation pour le mouvement qui vient de se finir
undo_stack . push ( new MovePartsCommand ( fsi_pos , this , selectedItems ( ) ) ) ;
fsi_pos = QPointF ( ) ;
moving_parts_ = false ;
}
}
QGraphicsScene : : keyReleaseEvent ( e ) ;
}
2007-06-30 17:41:07 +00:00
/**
Dessine l ' arriere - plan de l ' editeur , cad la grille .
@ param p Le QPainter a utiliser pour dessiner
@ param r Le rectangle de la zone a dessiner
*/
2007-08-25 03:43:05 +00:00
void ElementScene : : drawBackground ( QPainter * p , const QRectF & r ) {
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 ) ;
// dessine un fond blanc
p - > setPen ( Qt : : NoPen ) ;
p - > setBrush ( Qt : : white ) ;
p - > drawRect ( r ) ;
// encadre la zone dessinable de l'element
QRectF drawable_area ( - _hotspot . x ( ) , - _hotspot . y ( ) , width ( ) , height ( ) ) ;
p - > setPen ( Qt : : black ) ;
p - > setBrush ( Qt : : NoBrush ) ;
p - > drawRect ( drawable_area ) ;
2009-04-03 19:30:25 +00:00
// on dessine un point de la grille sur 10
int drawn_x_grid = x_grid * 10 ;
int drawn_y_grid = y_grid * 10 ;
2007-06-30 17:41:07 +00:00
if ( r . width ( ) < 2500 & & r . height ( ) < 2500 ) {
// dessine les points de la grille
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 ( ) ) ;
2009-04-03 19:30:25 +00:00
while ( g_x % drawn_x_grid ) + + g_x ;
2007-06-30 17:41:07 +00:00
int g_y = ( int ) ceil ( r . y ( ) ) ;
2009-04-03 19:30:25 +00:00
while ( g_y % drawn_y_grid ) + + g_y ;
2007-06-30 17:41:07 +00:00
2009-04-03 19:30:25 +00:00
for ( int gx = g_x ; gx < limite_x ; gx + = drawn_x_grid ) {
for ( int gy = g_y ; gy < limite_y ; gy + = drawn_y_grid ) {
2007-06-30 17:41:07 +00:00
p - > drawPoint ( gx , gy ) ;
}
}
}
p - > restore ( ) ;
}
/**
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 ) ;
p - > drawLine ( QLineF ( 0.0 , - _hotspot . y ( ) , 0.0 , height ( ) - _hotspot . y ( ) ) ) ;
p - > drawLine ( QLineF ( - _hotspot . x ( ) , 0.0 , width ( ) - _hotspot . x ( ) , 0.0 ) ) ;
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 {
2007-06-30 17:41:07 +00:00
// document XML
QDomDocument xml_document ;
// racine du document XML
QDomElement root = xml_document . createElement ( " definition " ) ;
root . setAttribute ( " type " , " element " ) ;
root . setAttribute ( " width " , QString ( " %1 " ) . arg ( _width * 10 ) ) ;
root . setAttribute ( " height " , QString ( " %1 " ) . arg ( _height * 10 ) ) ;
root . setAttribute ( " hotspot_x " , QString ( " %1 " ) . arg ( _hotspot . x ( ) ) ) ;
root . setAttribute ( " hotspot_y " , QString ( " %1 " ) . arg ( _hotspot . y ( ) ) ) ;
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
2007-10-07 18:52:01 +00:00
foreach ( QGraphicsItem * qgi , zItems ( true ) ) {
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
}
}
}
2009-04-03 19:30:25 +00:00
/**
@ 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 ( ) ) ) ) ;
}
2007-12-05 21:16:01 +00:00
/**
@ return un rectangle englobant toutes les parties ainsi que le
" bounding rect " de l ' element
*/
2007-09-10 21:12:49 +00:00
QRectF ElementScene : : sceneContent ( ) const {
2009-04-18 14:21:08 +00:00
qreal adjustment = 5.0 ;
return ( itemsBoundingRect ( ) . unite ( borderRect ( ) ) . adjusted ( - adjustment , - adjustment , adjustment , adjustment ) ) ;
2009-04-03 19:30:25 +00:00
}
/**
@ 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 ( ) ) ) ;
2007-09-10 21:12:49 +00:00
}
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 ) ) ;
2007-11-07 20:23:24 +00:00
emit ( partsRemoved ( ) ) ;
2007-06-30 17:41:07 +00:00
}
2007-12-05 21:16:01 +00:00
/**
Lance un dialogue pour editer les dimensions et le point de saisie
( hotspot ) de l ' element .
*/
2007-08-25 03:43:05 +00:00
void ElementScene : : slot_editSizeHotSpot ( ) {
2010-02-28 16:13:45 +00:00
bool is_read_only = element_editor & & element_editor - > isReadOnly ( ) ;
2007-08-18 22:59:10 +00:00
// cree un dialogue
2008-08-17 20:41:37 +00:00
QDialog dialog_sh ( element_editor ) ;
2007-08-18 22:59:10 +00:00
dialog_sh . setModal ( true ) ;
2009-08-09 16:43:03 +00:00
# ifdef Q_WS_MAC
dialog_sh . setWindowFlags ( Qt : : Sheet ) ;
# endif
2009-04-03 19:30:25 +00:00
dialog_sh . setWindowTitle ( tr ( " \311 diter la taille et le point de saisie " , " window title " ) ) ;
2007-08-18 22:59:10 +00:00
QVBoxLayout * dialog_layout = new QVBoxLayout ( & dialog_sh ) ;
// ajoute un HotspotEditor au dialogue
HotspotEditor * hotspot_editor = new HotspotEditor ( ) ;
hotspot_editor - > setElementWidth ( static_cast < uint > ( width ( ) / 10 ) ) ;
hotspot_editor - > setElementHeight ( static_cast < uint > ( height ( ) / 10 ) ) ;
hotspot_editor - > setHotspot ( hotspot ( ) ) ;
hotspot_editor - > setOldHotspot ( hotspot ( ) ) ;
hotspot_editor - > setPartsRect ( itemsBoundingRect ( ) ) ;
hotspot_editor - > setPartsRectEnabled ( true ) ;
2010-02-28 16:13:45 +00:00
hotspot_editor - > setReadOnly ( is_read_only ) ;
2007-08-18 22:59:10 +00:00
dialog_layout - > addWidget ( hotspot_editor ) ;
// 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-08-18 22:59:10 +00:00
dialog_layout - > addWidget ( dialog_buttons ) ;
connect ( dialog_buttons , SIGNAL ( accepted ( ) ) , & dialog_sh , SLOT ( accept ( ) ) ) ;
connect ( dialog_buttons , SIGNAL ( rejected ( ) ) , & dialog_sh , SLOT ( reject ( ) ) ) ;
// lance le dialogue
2010-03-28 16:27:48 +00:00
if ( dialog_sh . exec ( ) = = QDialog : : Accepted & & ! is_read_only ) {
2010-02-28 16:13:45 +00:00
QSize new_size ( hotspot_editor - > elementSize ( ) ) ;
QSize old_size ( width ( ) , height ( ) ) ;
QPoint new_hotspot ( hotspot_editor - > hotspot ( ) ) ;
QPoint old_hotspot ( _hotspot ) ;
if ( new_size ! = old_size | | new_hotspot ! = old_hotspot ) {
undo_stack . push ( new ChangeHotspotCommand ( this , old_size , new_size , old_hotspot , new_hotspot , hotspot_editor - > offsetParts ( ) ) ) ;
}
2007-08-18 22:59:10 +00:00
}
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 ) {
2010-02-14 16:28:45 +00:00
QString new_infos = text_field - > toPlainText ( ) ;
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
}
/**
@ param include_terminals true pour inclure les bornes , false sinon
@ return les parties de l ' element ordonnes par zValue croissante
*/
QList < QGraphicsItem * > ElementScene : : zItems ( bool include_terminals ) const {
// recupere les elements
QList < QGraphicsItem * > all_items_list ( items ( ) ) ;
// enleve les bornes
QList < QGraphicsItem * > terminals ;
foreach ( QGraphicsItem * qgi , all_items_list ) {
if ( qgraphicsitem_cast < PartTerminal * > ( qgi ) ) {
all_items_list . removeAt ( all_items_list . indexOf ( qgi ) ) ;
terminals < < qgi ;
}
}
// ordonne les parties par leur zValue
QMultiMap < qreal , QGraphicsItem * > mm ;
foreach ( QGraphicsItem * qgi , all_items_list ) mm . insert ( qgi - > zValue ( ) , qgi ) ;
all_items_list . clear ( ) ;
2007-12-01 19:07:59 +00:00
QMapIterator < qreal , QGraphicsItem * > i ( mm ) ;
while ( i . hasNext ( ) ) {
i . next ( ) ;
all_items_list < < i . value ( ) ;
}
2007-10-07 18:52:01 +00:00
// rajoute eventuellement les bornes
if ( include_terminals ) all_items_list + = terminals ;
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 ;
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 ;
}
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 ( ) ;
// enleve les elements de la scene
foreach ( QGraphicsItem * qgi , items ( ) ) {
removeItem ( qgi ) ;
qgiManager ( ) . release ( qgi ) ;
}
}
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
*/
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
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 ) ;
}
// 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 ) ;
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 ) ;
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
*/
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 ) {
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
*/
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 ) ;
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 ) ) ;
}