2007-12-01 10:47:15 +00:00
/*
2017-01-20 10:55:49 +00:00
Copyright 2006 - 2017 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-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"
2014-06-03 20:21:19 +00:00
# include "ui/elementpropertieseditorwidget.h"
2014-11-04 22:08:42 +00:00
# include "eseventinterface.h"
2017-08-02 15:26:14 +00:00
# include "QetGraphicsItemModeler/qetgraphicshandleritem.h"
2017-09-25 17:44:02 +00:00
# include "partdynamictextfield.h"
2018-03-20 10:59:39 +00:00
# include "QPropertyUndoCommand/qpropertyundocommand.h"
2014-11-04 22:08:42 +00:00
2017-08-02 15:26:14 +00:00
# include <algorithm>
2014-11-04 22:08:42 +00:00
# include <QKeyEvent>
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 ) ,
2014-10-19 11:25:03 +00:00
m_elmt_type ( " simple " ) ,
2017-07-31 17:41:48 +00:00
m_qgi_manager ( this ) ,
m_element_editor ( editor )
2007-06-30 17:41:07 +00:00
{
2017-10-09 16:05:19 +00:00
setItemIndexMethod ( QGraphicsScene : : NoIndex ) ;
//Set to no index, because they can be the source of the crash with conductor and shape ghost.
//https://forum.qt.io/topic/71316/qgraphicsscenefinditembsptreevisitor-visit-crashes-due-to-an-obsolete-paintevent-after-qgraphicsscene-removeitem
//https://stackoverflow.com/questions/38458830/crash-after-qgraphicssceneremoveitem-with-custom-item-class
//http://www.qtcentre.org/archive/index.php/t-33730.html
//http://tech-artists.org/t/qt-properly-removing-qgraphicitems/3063
2017-07-31 17:41:48 +00:00
m_behavior = Normal ;
2010-02-28 16:13:45 +00:00
setItemIndexMethod ( NoIndex ) ;
2009-04-03 19:30:25 +00:00
setGrid ( 1 , 1 ) ;
initPasteArea ( ) ;
2017-07-31 17:41:48 +00:00
m_undo_stack . setClean ( ) ;
2017-01-02 18:15:18 +00:00
m_decorator_lock = new QMutex ( QMutex : : NonRecursive ) ;
2017-07-31 17:41:48 +00:00
connect ( & m_undo_stack , SIGNAL ( indexChanged ( int ) ) , this , SLOT ( managePrimitivesGroups ( ) ) ) ;
2013-02-08 22:05:15 +00:00
connect ( this , SIGNAL ( selectionChanged ( ) ) , this , SLOT ( managePrimitivesGroups ( ) ) ) ;
2007-06-30 17:41:07 +00:00
}
2017-01-02 18:15:18 +00:00
/**
* @ brief ElementScene : : ~ ElementScene
*/
ElementScene : : ~ ElementScene ( )
{
//Disconnect to avoid crash, see bug report N° 122.
2017-07-31 17:41:48 +00:00
disconnect ( & m_undo_stack , SIGNAL ( indexChanged ( int ) ) , this , SLOT ( managePrimitivesGroups ( ) ) ) ;
2017-01-02 18:15:18 +00:00
delete m_decorator_lock ;
if ( m_event_interface )
delete m_event_interface ;
if ( m_decorator )
delete m_decorator ;
2007-06-30 17:41:07 +00:00
}
2007-12-05 21:16:01 +00:00
/**
2014-11-10 21:47:28 +00:00
* @ brief ElementScene : : mouseMoveEvent
* @ param e
*/
2007-08-25 03:43:05 +00:00
void ElementScene : : mouseMoveEvent ( QGraphicsSceneMouseEvent * e ) {
2014-11-04 22:08:42 +00:00
if ( m_event_interface ) {
if ( m_event_interface - > mouseMoveEvent ( e ) ) {
if ( m_event_interface - > isFinish ( ) ) {
delete m_event_interface ; m_event_interface = nullptr ;
2015-04-18 10:30:05 +00:00
emit ( partsAdded ( ) ) ;
2014-11-04 22:08:42 +00:00
}
return ;
}
}
2009-04-03 19:30:25 +00:00
QPointF event_pos = e - > scenePos ( ) ;
2015-05-25 15:15:02 +00:00
if ( ! ( e - > modifiers ( ) & Qt : : ControlModifier ) )
2014-11-11 12:02:08 +00:00
event_pos = snapToGrid ( event_pos ) ;
2009-04-03 19:30:25 +00:00
2017-07-31 17:41:48 +00:00
if ( m_behavior = = PasteArea ) {
QRectF current_rect ( m_paste_area - > rect ( ) ) ;
2009-04-03 19:30:25 +00:00
current_rect . moveCenter ( event_pos ) ;
2017-07-31 17:41:48 +00:00
m_paste_area - > setRect ( current_rect ) ;
2009-04-03 19:30:25 +00:00
return ;
}
2014-11-09 21:58:46 +00:00
QGraphicsScene : : mouseMoveEvent ( e ) ;
2007-06-30 17:41:07 +00:00
}
2007-12-05 21:16:01 +00:00
/**
2014-11-10 21:47:28 +00:00
* @ brief ElementScene : : mousePressEvent
* @ param e
*/
2007-08-25 03:43:05 +00:00
void ElementScene : : mousePressEvent ( QGraphicsSceneMouseEvent * e ) {
2014-11-04 22:08:42 +00:00
if ( m_event_interface ) {
if ( m_event_interface - > mousePressEvent ( e ) ) {
if ( m_event_interface - > isFinish ( ) ) {
delete m_event_interface ; m_event_interface = nullptr ;
2015-04-18 10:30:05 +00:00
emit ( partsAdded ( ) ) ;
2014-11-04 22:08:42 +00:00
}
return ;
}
}
2014-11-09 21:58:46 +00:00
QGraphicsScene : : mousePressEvent ( e ) ;
2007-06-30 17:41:07 +00:00
}
2007-12-05 21:16:01 +00:00
/**
2014-11-10 21:47:28 +00:00
* @ brief ElementScene : : mouseReleaseEvent
* @ param e
*/
2007-08-25 03:43:05 +00:00
void ElementScene : : mouseReleaseEvent ( QGraphicsSceneMouseEvent * e ) {
2014-11-04 22:08:42 +00:00
if ( m_event_interface ) {
if ( m_event_interface - > mouseReleaseEvent ( e ) ) {
if ( m_event_interface - > isFinish ( ) ) {
delete m_event_interface ; m_event_interface = nullptr ;
2015-04-18 10:30:05 +00:00
emit ( partsAdded ( ) ) ;
2014-11-04 22:08:42 +00:00
}
return ;
}
}
2009-04-03 19:30:25 +00:00
2017-07-31 17:41:48 +00:00
if ( m_behavior = = PasteArea ) {
m_defined_paste_area = m_paste_area - > rect ( ) ;
removeItem ( m_paste_area ) ;
emit ( pasteAreaDefined ( m_defined_paste_area ) ) ;
m_behavior = Normal ;
2009-04-03 19:30:25 +00:00
return ;
}
2014-11-10 21:47:28 +00:00
QGraphicsScene : : mouseReleaseEvent ( e ) ;
2014-11-08 11:14:56 +00:00
}
2014-11-10 21:47:28 +00:00
/**
* @ brief ElementScene : : mouseDoubleClickEvent
* @ param event
*/
2014-11-08 11:14:56 +00:00
void ElementScene : : mouseDoubleClickEvent ( QGraphicsSceneMouseEvent * event ) {
if ( m_event_interface ) {
if ( m_event_interface - > mouseDoubleClickEvent ( event ) ) {
if ( m_event_interface - > isFinish ( ) ) {
delete m_event_interface ; m_event_interface = nullptr ;
2015-04-18 10:30:05 +00:00
emit ( partsAdded ( ) ) ;
2014-11-08 11:14:56 +00:00
}
return ;
}
}
QGraphicsScene : : mouseDoubleClickEvent ( event ) ;
2007-06-30 17:41:07 +00:00
}
2014-11-04 22:08:42 +00:00
/**
* @ brief ElementScene : : keyPressEvent
* manage key press event
* @ param event
*/
2018-03-20 10:59:39 +00:00
void ElementScene : : keyPressEvent ( QKeyEvent * event )
{
if ( m_event_interface )
{
if ( m_event_interface - > keyPressEvent ( event ) )
{
if ( m_event_interface - > isFinish ( ) )
{
2014-11-04 22:08:42 +00:00
delete m_event_interface ; m_event_interface = nullptr ;
2015-04-18 10:30:05 +00:00
emit ( partsAdded ( ) ) ;
2014-11-04 22:08:42 +00:00
}
return ;
}
}
2018-03-20 10:59:39 +00:00
if ( selectedItems ( ) . size ( ) = = 1 )
2018-04-19 09:22:08 +00:00
{
if ( selectedItems ( ) . first ( ) - > type ( ) = = PartText : : Type )
{
PartText * t = static_cast < PartText * > ( selectedItems ( ) . first ( ) ) ;
if ( t - > textInteractionFlags ( ) & Qt : : TextEditorInteraction )
{
QGraphicsScene : : keyPressEvent ( event ) ;
return ;
}
}
2018-03-20 10:59:39 +00:00
QGraphicsObject * qgo = selectedItems ( ) . first ( ) - > toGraphicsObject ( ) ;
if ( qgo )
{
QPointF original_pos = qgo - > pos ( ) ;
QPointF p = qgo - > pos ( ) ;
int k = event - > key ( ) ;
if ( k = = Qt : : Key_Right )
p . rx ( ) + = 1 ;
else if ( k = = Qt : : Key_Left )
p . rx ( ) - = 1 ;
else if ( k = = Qt : : Key_Up )
p . ry ( ) - = 1 ;
else if ( k = = Qt : : Key_Down )
p . ry ( ) + = 1 ;
qgo - > setPos ( p ) ;
QPropertyUndoCommand * undo = new QPropertyUndoCommand ( qgo , " pos " , QVariant ( original_pos ) , QVariant ( p ) ) ;
undo - > setText ( tr ( " Déplacer une primitive " ) ) ;
undo - > enableAnimation ( ) ;
undoStack ( ) . push ( undo ) ;
event - > accept ( ) ;
return ;
}
}
2014-11-04 22:08:42 +00:00
QGraphicsScene : : keyPressEvent ( event ) ;
}
2015-04-18 11:02:10 +00:00
/**
* @ brief ElementScene : : contextMenuEvent
* Display the context menu event , only if behavior are Normal
* @ param event
*/
void ElementScene : : contextMenuEvent ( QGraphicsSceneContextMenuEvent * event )
{
2018-06-30 21:41:27 +00:00
QGraphicsScene : : contextMenuEvent ( event ) ;
if ( event - > isAccepted ( ) )
return ;
2017-07-31 17:41:48 +00:00
if ( m_behavior = = ElementScene : : Normal )
m_element_editor - > contextMenu ( event - > screenPos ( ) ) ;
2015-04-18 11:02:10 +00:00
}
2007-06-30 17:41:07 +00:00
/**
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 ) ;
2015-03-02 20:14:56 +00:00
QPen pen ( Qt : : red ) ;
pen . setCosmetic ( true ) ;
p - > setPen ( pen ) ;
2007-06-30 17:41:07 +00:00
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 ( ) ;
}
2014-11-04 22:08:42 +00:00
/**
2014-11-06 09:44:20 +00:00
* @ brief ElementScene : : setEventInterface
2014-11-04 22:08:42 +00:00
* Set a new event interface
* @ param interface
*/
2017-07-31 17:41:48 +00:00
void ElementScene : : setEventInterface ( ESEventInterface * event_interface )
{
if ( m_event_interface )
{
2014-11-10 22:57:32 +00:00
delete m_event_interface ;
//We must to re-init because previous interface
//Reset his own init when deleted
2015-03-02 20:14:56 +00:00
event_interface - > init ( ) ;
2014-11-10 22:57:32 +00:00
}
2015-03-02 20:14:56 +00:00
m_event_interface = event_interface ;
2014-11-04 22:08:42 +00:00
}
2017-07-31 17:41:48 +00:00
/**
* @ brief ElementScene : : clearEventInterface
* Clear the current event interface
*/
void ElementScene : : clearEventInterface ( )
{
if ( m_event_interface )
{
delete m_event_interface ;
m_event_interface = nullptr ;
}
}
2015-04-18 11:02:10 +00:00
/**
* @ brief ElementScene : : setBehavior
* Modifie the current behavior of this scene
* @ param b
*/
2018-06-30 21:41:27 +00:00
void ElementScene : : setBehavior ( ElementScene : : Behavior b ) {
2017-07-31 17:41:48 +00:00
m_behavior = b ;
2015-04-18 11:02:10 +00:00
}
2018-06-30 21:41:27 +00:00
ElementScene : : Behavior ElementScene : : behavior ( ) const {
return m_behavior ;
}
2009-04-03 19:30:25 +00:00
/**
@ return la taille horizontale de la grille
*/
int ElementScene : : xGrid ( ) const {
2017-07-31 17:41:48 +00:00
return ( m_x_grid ) ;
2009-04-03 19:30:25 +00:00
}
/**
@ return la taille verticale de la grille
*/
int ElementScene : : yGrid ( ) const {
2017-07-31 17:41:48 +00:00
return ( m_y_grid ) ;
2009-04-03 19:30:25 +00:00
}
/**
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 ) {
2017-07-31 17:41:48 +00:00
m_x_grid = x_g ? x_g : 1 ;
m_y_grid = y_g ? y_g : 1 ;
2009-04-03 19:30:25 +00:00
}
2007-12-05 21:16:01 +00:00
/**
2015-06-28 16:30:13 +00:00
* @ brief ElementScene : : toXml
* Export this element as a xml file
* @ param all_parts ( true by default ) if true , export the entire element in xml ,
* if false , only export the selected parts .
* @ return an xml document that describe the element .
*/
const QDomDocument ElementScene : : toXml ( bool all_parts )
{
2013-07-28 00:23:10 +00:00
QRectF size = elementSceneGeometricRect ( ) ;
2015-06-28 16:30:13 +00:00
//if the element doesn't contains the origin point of the scene
//we move the element to the origin for solve this default before saving
if ( ! size . contains ( 0 , 0 ) & & all_parts )
{
2013-09-21 13:09:23 +00:00
centerElementToOrigine ( ) ;
2015-06-28 16:30:13 +00:00
//recalcul the size after movement
2013-09-21 13:09:23 +00:00
size = elementSceneGeometricRect ( ) ;
}
2015-06-28 16:30:13 +00:00
//define the size of the element by the upper multiple of 10
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
2015-06-28 16:30:13 +00:00
//the margin between the real size of the element and the rectangle that delimits
2013-08-01 23:17:39 +00:00
int xmargin = qRound ( upwidth - size . width ( ) ) ;
int ymargin = qRound ( upheight - size . height ( ) ) ;
2015-06-28 16:30:13 +00:00
// document XML
2013-08-01 23:17:39 +00:00
QDomDocument xml_document ;
2015-06-28 16:30:13 +00:00
//Root of xml document
2007-06-30 17:41:07 +00:00
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 ) ) ) ) ) ;
2013-11-14 10:11:22 +00:00
root . setAttribute ( " orientation " , " dyyy " ) ; //we keep the orientation for compatibility with previous version of qet
2007-10-04 17:32:41 +00:00
root . setAttribute ( " version " , QET : : version ) ;
2014-06-03 20:21:19 +00:00
root . setAttribute ( " link_type " , m_elmt_type ) ;
2015-06-28 16:30:13 +00:00
//Uuid used to compare two elements
QDomElement uuid = xml_document . createElement ( " uuid " ) ;
uuid . setAttribute ( " uuid " , QUuid : : createUuid ( ) . toString ( ) ) ;
root . appendChild ( uuid ) ;
2007-06-30 17:41:07 +00:00
2015-06-28 16:30:13 +00:00
//names of element
2017-07-31 17:41:48 +00:00
root . appendChild ( m_names_list . toXml ( xml_document ) ) ;
2014-06-03 20:21:19 +00:00
2015-06-28 16:30:13 +00:00
if ( m_elmt_type = = " slave " | | m_elmt_type = = " master " )
{
2014-06-03 20:21:19 +00:00
QDomElement kindInfo = xml_document . createElement ( " kindInformations " ) ;
m_elmt_kindInfo . toXml ( kindInfo , " kindInformation " ) ;
root . appendChild ( kindInfo ) ;
}
2007-06-30 17:41:07 +00:00
2017-10-01 15:25:34 +00:00
if ( m_elmt_type = = " simple " | | m_elmt_type = = " master " | | m_elmt_type = = " terminal " )
{
QDomElement element_info = xml_document . createElement ( " elementInformations " ) ;
m_elmt_information . toXml ( element_info , " elementInformation " ) ;
root . appendChild ( element_info ) ;
}
2015-06-28 16:30:13 +00:00
//complementary information about the element
2010-02-14 16:28:45 +00:00
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 " ) ;
2015-06-28 16:30:13 +00:00
//the graphic description of the element
2017-02-05 16:18:50 +00:00
foreach ( QGraphicsItem * qgi , zItems ( ) )
2015-06-28 16:30:13 +00:00
{
//If the export concerns only the selection, the not selected part is ignored
2009-04-03 19:30:25 +00:00
if ( ! all_parts & & ! qgi - > isSelected ( ) ) continue ;
2015-06-28 16:30:13 +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
*/
2017-09-25 17:44:02 +00:00
void ElementScene : : fromXml ( const QDomDocument & xml_document , const QPointF & position , bool consider_informations , ElementContent * content_ptr )
{
2007-06-30 17:41:07 +00:00
bool state = true ;
2017-09-25 17:44:02 +00:00
//Consider the informations of the element
2009-04-03 19:30:25 +00:00
if ( consider_informations ) {
2017-09-25 17:44:02 +00:00
state = applyInformations ( xml_document ) ;
2007-06-30 17:41:07 +00:00
}
2017-09-25 17:44:02 +00:00
if ( state )
{
ElementContent loaded_content = loadContent ( xml_document ) ;
if ( position ! = QPointF ( ) )
addContentAtPos ( loaded_content , position ) ;
else
addContent ( loaded_content ) ;
2007-12-09 10:30:35 +00:00
2017-09-25 17:44:02 +00:00
if ( content_ptr )
2009-04-03 19:30:25 +00:00
* 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 ;
2017-02-05 16:18:50 +00:00
foreach ( QGraphicsItem * qgi , items ( ) ) {
2017-09-25 17:44:02 +00:00
if ( qgi - > type ( ) = = ElementPrimitiveDecorator : : Type ) continue ;
if ( qgi - > type ( ) = = QGraphicsRectItem : : Type ) continue ;
if ( qgi - > type ( ) = = PartDynamicTextField : : Type ) continue ;
2013-07-28 00:23:10 +00:00
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 {
2017-02-05 16:18:50 +00:00
foreach ( QGraphicsItem * qgi , items ( ) ) {
2009-06-01 02:05:20 +00:00
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 ( ) {
2017-07-31 17:41:48 +00:00
return ( m_undo_stack ) ;
2007-08-23 15:33:55 +00:00
}
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 ( ) {
2017-07-31 17:41:48 +00:00
return ( m_qgi_manager ) ;
2007-08-23 15:33:55 +00:00
}
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 ) {
2017-07-31 17:41:48 +00:00
return ( clipboard_content = = m_last_copied ) ;
2009-04-03 19:30:25 +00:00
}
/**
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
2017-07-31 17:41:48 +00:00
m_last_copied = clipboard_content ;
2009-04-03 19:30:25 +00:00
}
2014-11-04 22:08:42 +00:00
QETElementEditor * ElementScene : : editor ( ) const {
2017-07-31 17:41:48 +00:00
return m_element_editor ;
2014-11-04 22:08:42 +00:00
}
2018-07-19 14:14:31 +00:00
void ElementScene : : setElementInfo ( const DiagramContext & dc )
2018-03-11 12:59:53 +00:00
{
if ( m_elmt_information ! = dc )
{
m_elmt_information = dc ;
emit elementInfoChanged ( ) ;
}
}
2007-12-05 21:16:01 +00:00
/**
2017-08-02 15:26:14 +00:00
* @ brief ElementScene : : slot_select
* Select the item in content , every others items in the scene are deselected
* @ param content
*/
void ElementScene : : slot_select ( const ElementContent & content )
{
2009-04-18 14:21:08 +00:00
blockSignals ( true ) ;
2017-08-02 15:26:14 +00:00
//Befor clear selection, we must to remove the handlers items in @content,
//because if in @content there are a selected item, but also its handlers items,
//When item is deselected, the item delete its handlers items,
//then handlers in content doesn't exist anymore and cause segfault
QList < QGraphicsItem * > items_list ;
for ( QGraphicsItem * qgi : content )
{
if ( qgi - > type ( ) ! = QetGraphicsHandlerItem : : Type )
items_list < < qgi ;
}
2010-02-28 16:13:45 +00:00
clearSelection ( ) ;
2017-08-02 15:26:14 +00:00
foreach ( QGraphicsItem * qgi , items_list )
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
/**
2017-08-02 15:26:14 +00:00
* @ brief ElementScene : : slot_selectAll
* Select all items
*/
2009-04-18 18:08:54 +00:00
void ElementScene : : slot_selectAll ( ) {
slot_select ( items ( ) ) ;
}
2007-12-05 21:16:01 +00:00
/**
2017-08-02 15:26:14 +00:00
* @ brief ElementScene : : slot_deselectAll
* deselect all item
*/
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 ) ;
2017-02-05 16:18:50 +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
2017-07-31 17:41:48 +00:00
m_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
}
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 ( ) {
2017-07-31 17:41:48 +00:00
bool is_read_only = m_element_editor & & m_element_editor - > isReadOnly ( ) ;
2010-02-14 16:28:45 +00:00
// cree un dialogue
2017-07-31 17:41:48 +00:00
QDialog dialog_author ( m_element_editor ) ;
2010-02-14 16:28:45 +00:00
dialog_author . setModal ( true ) ;
2015-03-02 20:14:56 +00:00
# ifdef Q_OS_MAC
2010-02-14 16:28:45 +00:00
dialog_author . setWindowFlags ( Qt : : Sheet ) ;
# endif
dialog_author . setMinimumSize ( 400 , 260 ) ;
2015-03-02 20:14:56 +00:00
dialog_author . setWindowTitle ( tr ( " Éditer les informations sur l'auteur " , " window title " ) ) ;
2010-02-14 16:28:45 +00:00
QVBoxLayout * dialog_layout = new QVBoxLayout ( & dialog_author ) ;
// ajoute un champ explicatif au dialogue
2015-03-02 20:14:56 +00:00
QLabel * information_label = new QLabel ( tr ( " Vous pouvez utiliser ce champ libre pour mentionner les auteurs de l'élément, sa licence, ou tout autre renseignement que vous jugerez utile. " ) ) ;
2010-02-14 16:28:45 +00:00
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 ) ) ;
}
}
}
2014-06-03 20:21:19 +00:00
/**
* @ brief ElementScene : : slot_editProperties
* Open dialog to edit the element properties
*/
2017-10-01 15:25:34 +00:00
void ElementScene : : slot_editProperties ( )
{
2014-06-20 20:10:09 +00:00
QString type = m_elmt_type ;
2017-10-01 15:25:34 +00:00
DiagramContext kind_info = m_elmt_kindInfo ;
DiagramContext elmt_info = m_elmt_information ;
ElementPropertiesEditorWidget epew ( type , kind_info , elmt_info ) ;
2014-06-03 20:21:19 +00:00
epew . exec ( ) ;
2017-10-01 15:25:34 +00:00
if ( type ! = m_elmt_type | |
kind_info ! = m_elmt_kindInfo | |
elmt_info ! = m_elmt_information )
undoStack ( ) . push ( new ChangePropertiesCommand ( this , type , kind_info , elmt_info ) ) ;
2014-06-03 20:21:19 +00:00
}
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 ( ) {
2017-07-31 17:41:48 +00:00
bool is_read_only = m_element_editor & & m_element_editor - > isReadOnly ( ) ;
2007-06-30 17:41:07 +00:00
// cree un dialogue
2017-07-31 17:41:48 +00:00
QDialog dialog ( m_element_editor ) ;
2015-03-02 20:14:56 +00:00
# ifdef Q_OS_MAC
2009-08-09 16:43:03 +00:00
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 ) ;
2015-03-02 20:14:56 +00:00
dialog . setWindowTitle ( tr ( " É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
2015-03-02 20:14:56 +00:00
QLabel * information_label = new QLabel ( tr ( " Vous pouvez spécifier le nom de l'élément dans plusieurs langues. " ) ) ;
2007-06-30 17:41:07 +00:00
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 ( ) ;
2017-07-31 17:41:48 +00:00
names_widget - > setNames ( m_names_list ) ;
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 ( ) ) ;
2017-07-31 17:41:48 +00:00
if ( new_names ! = m_names_list ) undoStack ( ) . push ( new ChangeNamesCommand ( this , m_names_list , new_names ) ) ;
2007-09-10 21:50:17 +00:00
}
2007-06-30 17:41:07 +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 ;
2017-02-05 16:18:50 +00:00
foreach ( QGraphicsItem * item , items ( ) ) {
2013-02-08 22:05:15 +00:00
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 | |
2017-08-24 14:48:58 +00:00
qgi - > type ( ) = = QGraphicsRectItem : : Type | |
qgi - > type ( ) = = QetGraphicsHandlerItem : : Type
2013-02-08 22:05:15 +00:00
) {
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 ) {
2017-02-03 13:48:42 +00:00
std : : sort ( all_items_list . begin ( ) , all_items_list . end ( ) , ElementScene : : zValueLessThan ) ;
2013-02-08 22:05:20 +00:00
}
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 ;
2017-02-05 16:18:50 +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
2017-07-31 17:41:48 +00:00
m_paste_area - > setRect ( to_paste ) ;
addItem ( m_paste_area ) ;
2009-04-03 19:30:25 +00:00
// on passe la scene en mode "recherche de zone pour copier/coller"
2017-07-31 17:41:48 +00:00
m_behavior = PasteArea ;
2009-04-03 19:30:25 +00:00
}
2007-12-09 12:00:11 +00:00
/**
2016-10-11 18:34:02 +00:00
* @ brief ElementScene : : reset
* Remove all QGraphicsItems in the scene and clear the undo stack .
*/
2017-01-02 18:15:18 +00:00
void ElementScene : : reset ( )
{
2016-10-11 18:34:02 +00:00
clearSelection ( ) ;
2007-12-09 12:00:11 +00:00
undoStack ( ) . clear ( ) ;
2013-07-28 22:48:36 +00:00
2017-08-02 15:26:14 +00:00
//We don't add handlers, because it's the role of the primitive or decorator to remove it.
QList < QGraphicsItem * > items_list ;
for ( QGraphicsItem * qgi : items ( ) )
{
if ( qgi - > type ( ) ! = QetGraphicsHandlerItem : : Type )
items_list < < qgi ;
}
for ( QGraphicsItem * qgi : items_list )
2017-01-02 18:15:18 +00:00
{
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
}
2017-01-02 18:15:18 +00:00
delete m_decorator ;
m_decorator = nullptr ;
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 ;
2017-02-05 16:18:50 +00:00
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
@ return true si la lecture et l ' application des informations s ' est bien
passee , false sinon .
*/
2017-09-25 17:44:02 +00:00
bool ElementScene : : applyInformations ( const QDomDocument & xml_document )
{
// Root must be an element definition
2009-04-03 19:30:25 +00:00
QDomElement root = xml_document . documentElement ( ) ;
2017-09-25 17:44:02 +00:00
if ( root . tagName ( ) ! = " definition " | | root . attribute ( " type " ) ! = " element " )
2009-04-03 19:30:25 +00:00
return ( false ) ;
2013-11-14 10:11:22 +00:00
2017-10-01 15:25:34 +00:00
//Extract info about element type
2014-06-03 20:21:19 +00:00
m_elmt_type = root . attribute ( " link_type " , " simple " ) ;
m_elmt_kindInfo . fromXml ( root . firstChildElement ( " kindInformations " ) , " kindInformation " ) ;
2017-10-01 15:25:34 +00:00
//Extract info of element
m_elmt_information . fromXml ( root . firstChildElement ( " elementInformations " ) , " elementInformation " ) ;
2014-06-03 20:21:19 +00:00
//Extract names of xml definition
2017-07-31 17:41:48 +00:00
m_names_list . fromXml ( root ) ;
2009-04-03 19:30:25 +00:00
2014-06-03 20:21:19 +00:00
//extract additional informations
2010-02-14 16:28:45 +00:00
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
*/
2017-09-25 17:44:02 +00:00
/**
* @ brief ElementScene : : loadContent
* @ param xml_document : xml dom document to analyze
* @ return
*/
/**
* @ brief ElementScene : : loadContent
* Create and load the content describe in the xml document .
* @ param xml_document
* @ return the loaded content
*/
ElementContent ElementScene : : loadContent ( const QDomDocument & xml_document )
{
2009-04-03 19:30:25 +00:00
ElementContent loaded_parts ;
2017-09-25 17:44:02 +00:00
//The root is supposed to be an element definition
2009-04-03 19:30:25 +00:00
QDomElement root = xml_document . documentElement ( ) ;
2017-09-25 17:44:02 +00:00
if ( root . tagName ( ) ! = " definition " | | root . attribute ( " type " ) ! = " element " )
2009-04-03 19:30:25 +00:00
return ( loaded_parts ) ;
2017-09-25 17:44:02 +00:00
//Load the graphic description of the element
for ( QDomNode node = root . firstChild ( ) ; ! node . isNull ( ) ; node = node . nextSibling ( ) )
{
2009-04-03 19:30:25 +00:00
QDomElement elmts = node . toElement ( ) ;
2017-09-25 17:44:02 +00:00
if ( elmts . isNull ( ) )
continue ;
if ( elmts . tagName ( ) = = " description " )
{
2009-04-03 19:30:25 +00:00
int z = 1 ;
2017-09-25 17:44:02 +00:00
for ( QDomNode n = node . firstChild ( ) ; ! n . isNull ( ) ; n = n . nextSibling ( ) )
{
2009-04-03 19:30:25 +00:00
QDomElement qde = n . toElement ( ) ;
2017-09-25 17:44:02 +00:00
if ( qde . isNull ( ) )
continue ;
CustomElementPart * cep = nullptr ;
2017-09-27 15:31:57 +00:00
PartDynamicTextField * pdtf = nullptr ;
2017-09-25 17:44:02 +00:00
2017-07-31 17:41:48 +00:00
if ( qde . tagName ( ) = = " line " ) cep = new PartLine ( m_element_editor ) ;
else if ( qde . tagName ( ) = = " rect " ) cep = new PartRectangle ( m_element_editor ) ;
else if ( qde . tagName ( ) = = " ellipse " ) cep = new PartEllipse ( m_element_editor ) ;
else if ( qde . tagName ( ) = = " circle " ) cep = new PartEllipse ( m_element_editor ) ;
else if ( qde . tagName ( ) = = " polygon " ) cep = new PartPolygon ( m_element_editor ) ;
else if ( qde . tagName ( ) = = " terminal " ) cep = new PartTerminal ( m_element_editor ) ;
else if ( qde . tagName ( ) = = " text " ) cep = new PartText ( m_element_editor ) ;
else if ( qde . tagName ( ) = = " arc " ) cep = new PartArc ( m_element_editor ) ;
2017-09-25 17:44:02 +00:00
else if ( qde . tagName ( ) = = " dynamic_text " ) cep = new PartDynamicTextField ( m_element_editor ) ;
2017-09-27 15:31:57 +00:00
//For the input (aka the old text field) we try to convert it to the new partDynamicTextField
2018-03-11 14:44:21 +00:00
else if ( qde . tagName ( ) = = " input " ) cep = pdtf = new PartDynamicTextField ( m_element_editor ) ;
2009-04-03 19:30:25 +00:00
else continue ;
2017-09-25 17:44:02 +00:00
if ( QGraphicsItem * qgi = dynamic_cast < QGraphicsItem * > ( cep ) )
{
if ( ! qgi - > zValue ( ) )
qgi - > setZValue ( z + + ) ;
loaded_parts < < qgi ;
2017-09-27 15:31:57 +00:00
2018-03-11 14:44:21 +00:00
if ( pdtf )
2017-09-27 15:31:57 +00:00
pdtf - > fromTextFieldXml ( qde ) ;
else
cep - > fromXml ( qde ) ;
2009-04-03 19:30:25 +00:00
}
2017-09-25 17:44:02 +00:00
else
delete cep ;
2009-04-03 19:30:25 +00:00
}
}
}
return ( loaded_parts ) ;
}
/**
Ajoute le contenu content a cet element
@ param content contenu ( = liste de parties ) a charger
@ return Le contenu ajoute
*/
2017-09-25 17:44:02 +00:00
ElementContent ElementScene : : addContent ( const ElementContent & content ) {
2017-02-05 16:18:50 +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
@ return Le contenu ajoute
*/
2017-09-25 17:44:02 +00:00
ElementContent ElementScene : : addContentAtPos ( const ElementContent & content , const QPointF & pos ) {
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
2017-02-05 16:18:50 +00:00
foreach ( QGraphicsItem * part , content ) {
2009-04-03 19:30:25 +00:00
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 ( ) {
2017-07-31 17:41:48 +00:00
m_paste_area = new QGraphicsRectItem ( ) ;
m_paste_area - > setZValue ( 1000000 ) ;
2009-04-03 19:30:25 +00:00
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 ) ) ;
2017-07-31 17:41:48 +00:00
m_paste_area - > setPen ( paste_area_pen ) ;
m_paste_area - > setBrush ( paste_area_brush ) ;
2009-04-03 19:30:25 +00:00
}
/**
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 .
*/
2014-11-04 22:08:42 +00:00
QPointF ElementScene : : snapToGrid ( QPointF point ) {
2017-07-31 17:41:48 +00:00
point . rx ( ) = qRound ( point . x ( ) / m_x_grid ) * m_x_grid ;
point . ry ( ) = qRound ( point . y ( ) / m_y_grid ) * m_y_grid ;
2014-11-04 22:08:42 +00:00
return point ;
2009-04-03 19:30:25 +00:00
}
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
2013-09-21 13:09:23 +00:00
/**
* @ brief ElementScene : : centerElementToOrigine
* try to center better is possible the element to the scene
* ( the calcul isn ' t optimal but work good )
*/
void ElementScene : : centerElementToOrigine ( ) {
QRectF size = elementSceneGeometricRect ( ) ;
int center_x = qRound ( size . center ( ) . x ( ) ) ;
int center_y = qRound ( size . center ( ) . y ( ) ) ;
//define the movement of translation
2015-03-02 20:14:56 +00:00
int move_x = center_x - ( center_x % 10 ) ;
2013-09-21 13:09:23 +00:00
if ( center_x < 0 ) move_x - = 10 ;
2015-03-02 20:14:56 +00:00
int move_y = center_y - ( center_y % 10 ) ;
2013-09-21 13:09:23 +00:00
if ( center_y < 0 ) move_y - = 10 ;
//move each primitive by @move
2017-02-05 16:18:50 +00:00
foreach ( QGraphicsItem * qgi , items ( ) ) {
2013-09-21 13:09:23 +00:00
if ( qgi - > type ( ) = = ElementPrimitiveDecorator : : Type ) continue ;
if ( qgi - > type ( ) = = QGraphicsRectItem : : Type ) continue ;
//deselect item for disable decorator
qgi - > setSelected ( false ) ;
qgi - > moveBy ( - ( move_x ) , - ( move_y ) ) ;
}
emit ( needZoomFit ( ) ) ;
}
2013-02-08 22:05:15 +00:00
/**
2017-01-02 18:15:18 +00:00
* @ brief ElementScene : : managePrimitivesGroups
* Ensure the decorator is adequately shown , hidden or updated so it always
* represents the current selection .
*/
void ElementScene : : managePrimitivesGroups ( )
{
//this function is not supposed to be reentrant
if ( ! m_decorator_lock - > tryLock ( ) )
return ;
2013-02-08 22:05:15 +00:00
2017-01-02 18:15:18 +00:00
if ( ! m_decorator )
{
m_decorator = new ElementPrimitiveDecorator ( ) ;
connect ( m_decorator , SIGNAL ( actionFinished ( ElementEditionCommand * ) ) , this , SLOT ( stackAction ( ElementEditionCommand * ) ) ) ;
addItem ( m_decorator ) ;
m_decorator - > hide ( ) ;
2013-02-08 22:05:15 +00:00
}
2015-07-20 17:45:37 +00:00
// should we hide the decorator?
2013-02-08 22:05:20 +00:00
QList < QGraphicsItem * > selected_items = zItems ( ElementScene : : Selected | ElementScene : : IncludeTerminals ) ;
2017-08-01 19:37:04 +00:00
if ( selected_items . size ( ) < = 1 )
2017-08-02 15:26:14 +00:00
{
2017-01-02 18:15:18 +00:00
m_decorator - > hide ( ) ;
2017-08-02 15:26:14 +00:00
}
2015-07-20 17:45:37 +00:00
else
{
2017-08-02 15:26:14 +00:00
for ( QGraphicsItem * qgi : selected_items )
{
//We recall set selected, then every primitive will remove there handler because there are several item selected
qgi - > setSelected ( true ) ;
}
2017-01-02 18:15:18 +00:00
m_decorator - > setZValue ( 1000000 ) ;
m_decorator - > setPos ( 0 , 0 ) ;
m_decorator - > setItems ( selected_items ) ;
2013-02-08 22:05:15 +00:00
}
2017-01-02 18:15:18 +00:00
m_decorator_lock - > unlock ( ) ;
2013-02-08 22:05:15 +00:00
}
/**
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 ( ) ) {
2017-02-05 16:18:50 +00:00
foreach ( QGraphicsView * view , views ( ) ) {
2013-02-08 22:05:15 +00:00
if ( ElementView * element_view = dynamic_cast < ElementView * > ( view ) ) {
command - > setElementView ( element_view ) ;
break ;
}
}
}
undoStack ( ) . push ( command ) ;
}