2007-12-01 10:47:15 +00:00
/*
2008-02-06 19:40:45 +00:00
Copyright 2006 - 2008 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/>.
*/
2006-10-27 15:47:22 +00:00
# include <math.h>
2007-09-21 13:22:18 +00:00
# include "qetapp.h"
2007-10-03 17:02:39 +00:00
# include "conductor.h"
2007-01-30 22:32:21 +00:00
# include "customelement.h"
2007-01-29 00:41:12 +00:00
# include "diagram.h"
2007-02-01 01:07:26 +00:00
# include "exportdialog.h"
2007-09-26 17:14:09 +00:00
# include "diagramcommands.h"
2007-11-09 13:06:51 +00:00
# include "diagramcontent.h"
2006-10-27 15:47:22 +00:00
2007-10-10 22:35:32 +00:00
const int Diagram : : xGrid = 10 ;
const int Diagram : : yGrid = 10 ;
const qreal Diagram : : margin = 5.0 ;
2006-10-27 15:47:22 +00:00
/**
Constructeur
@ param parent Le QObject parent du schema
*/
2007-10-11 12:51:56 +00:00
Diagram : : Diagram ( QObject * parent ) :
QGraphicsScene ( parent ) ,
draw_grid ( true ) ,
use_border ( true ) ,
moved_elements_fetched ( false ) ,
qgi_manager ( this ) ,
draw_terminals ( true )
{
2006-10-27 15:47:22 +00:00
setBackgroundBrush ( Qt : : white ) ;
2007-10-03 17:02:39 +00:00
conductor_setter = new QGraphicsLineItem ( 0 , 0 ) ;
conductor_setter - > setZValue ( 1000000 ) ;
2006-10-27 15:47:22 +00:00
QPen t ;
t . setColor ( Qt : : black ) ;
t . setWidthF ( 1.5 ) ;
t . setStyle ( Qt : : DashLine ) ;
2007-10-03 17:02:39 +00:00
conductor_setter - > setPen ( t ) ;
conductor_setter - > setLine ( QLineF ( QPointF ( 0.0 , 0.0 ) , QPointF ( 0.0 , 0.0 ) ) ) ;
2007-09-05 20:42:08 +00:00
connect ( this , SIGNAL ( selectionChanged ( ) ) , this , SLOT ( slot_checkSelectionEmptinessChange ( ) ) ) ;
2007-11-14 20:27:45 +00:00
// lit les caracteristiques des conducteurs par defaut dans la configuration
defaultConductorProperties . fromSettings ( QETApp : : settings ( ) , " diagrameditor/defaultconductor " ) ;
2006-10-27 15:47:22 +00:00
}
2007-04-12 03:13:13 +00:00
/**
Destructeur
*/
Diagram : : ~ Diagram ( ) {
2007-11-04 17:37:10 +00:00
if ( conductor_setter - > scene ( ) ) removeItem ( conductor_setter ) ;
delete conductor_setter ;
2007-09-29 12:54:01 +00:00
}
2007-04-12 03:13:13 +00:00
2006-10-27 15:47:22 +00:00
/**
Dessine l ' arriere - plan du schema , cad la grille .
@ param p Le QPainter a utiliser pour dessiner
@ param r Le rectangle de la zone a dessiner
*/
2007-01-29 00:41:12 +00:00
void Diagram : : drawBackground ( QPainter * p , const QRectF & r ) {
2006-10-27 15:47:22 +00:00
p - > save ( ) ;
2007-02-01 01:07:26 +00:00
// desactive tout antialiasing, sauf pour le texte
2006-10-27 15:47:22 +00:00
p - > setRenderHint ( QPainter : : Antialiasing , false ) ;
2007-02-01 01:07:26 +00:00
p - > setRenderHint ( QPainter : : TextAntialiasing , true ) ;
2006-10-27 15:47:22 +00:00
p - > setRenderHint ( QPainter : : SmoothPixmapTransform , false ) ;
// dessine un fond blanc
p - > setPen ( Qt : : NoPen ) ;
p - > setBrush ( Qt : : white ) ;
p - > drawRect ( r ) ;
2007-09-04 18:15:41 +00:00
if ( draw_grid ) {
2006-10-27 15:47:22 +00:00
// 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 ( ) ) ;
2007-10-10 22:35:32 +00:00
while ( g_x % xGrid ) + + g_x ;
2006-10-27 15:47:22 +00:00
int g_y = ( int ) ceil ( r . y ( ) ) ;
2007-10-10 22:35:32 +00:00
while ( g_y % yGrid ) + + g_y ;
2006-10-27 15:47:22 +00:00
2007-10-10 22:35:32 +00:00
for ( int gx = g_x ; gx < limite_x ; gx + = xGrid ) {
for ( int gy = g_y ; gy < limite_y ; gy + = yGrid ) {
2006-10-27 15:47:22 +00:00
p - > drawPoint ( gx , gy ) ;
}
}
}
2007-01-28 00:53:17 +00:00
2007-10-10 22:35:32 +00:00
if ( use_border ) border_and_inset . draw ( p , margin , margin ) ;
2006-10-27 15:47:22 +00:00
p - > restore ( ) ;
}
2007-09-15 23:45:27 +00:00
/**
2007-10-10 17:50:26 +00:00
Gere les enfoncements de touches du clavier
2007-09-15 23:45:27 +00:00
@ param e QKeyEvent decrivant l ' evenement clavier
*/
void Diagram : : keyPressEvent ( QKeyEvent * e ) {
QPointF movement ;
switch ( e - > key ( ) ) {
2007-10-10 22:35:32 +00:00
case Qt : : Key_Left : movement = QPointF ( - xGrid , 0.0 ) ; break ;
case Qt : : Key_Right : movement = QPointF ( + xGrid , 0.0 ) ; break ;
case Qt : : Key_Up : movement = QPointF ( 0.0 , - yGrid ) ; break ;
case Qt : : Key_Down : movement = QPointF ( 0.0 , + yGrid ) ; break ;
2007-09-15 23:45:27 +00:00
}
2007-10-12 10:58:57 +00:00
if ( ! movement . isNull ( ) & & ! focusItem ( ) ) {
2007-10-27 13:18:17 +00:00
moveElements ( movement ) ;
2007-09-15 23:45:27 +00:00
}
QGraphicsScene : : keyPressEvent ( e ) ;
}
2007-10-10 17:50:26 +00:00
/**
Gere les relachements de touches du clavier
@ param e QKeyEvent decrivant l ' evenement clavier
*/
2007-09-15 23:45:27 +00:00
void Diagram : : keyReleaseEvent ( QKeyEvent * e ) {
2007-09-26 17:14:09 +00:00
// detecte le relachement d'une touche de direction ( = deplacement d'elements)
if (
( e - > key ( ) = = Qt : : Key_Left | | e - > key ( ) = = Qt : : Key_Right | | \
e - > key ( ) = = Qt : : Key_Up | | e - > key ( ) = = Qt : : Key_Down ) & & \
! current_movement . isNull ( ) & & ! e - > isAutoRepeat ( )
) {
2007-10-10 17:50:26 +00:00
// cree un objet d'annulation pour le mouvement qui vient de se finir
2007-11-09 13:06:51 +00:00
undoStack ( ) . push ( new MoveElementsCommand ( this , selectedContent ( ) , current_movement ) ) ;
2007-09-26 17:14:09 +00:00
invalidateMovedElements ( ) ;
current_movement = QPointF ( ) ;
}
2007-09-15 23:45:27 +00:00
QGraphicsScene : : keyReleaseEvent ( e ) ;
}
2006-11-11 18:25:42 +00:00
/**
Exporte le schema vers une image
@ return Une QImage representant le schema
*/
2007-10-05 12:06:39 +00:00
bool Diagram : : toPaintDevice ( QPaintDevice & pix , int width , int height , Qt : : AspectRatioMode aspectRatioMode ) {
2007-02-01 01:07:26 +00:00
// determine la zone source = contenu du schema + marges
QRectF source_area ;
if ( ! use_border ) {
source_area = itemsBoundingRect ( ) ;
2007-10-10 22:35:32 +00:00
source_area . translate ( - margin , - margin ) ;
source_area . setWidth ( source_area . width ( ) + 2.0 * margin ) ;
source_area . setHeight ( source_area . height ( ) + 2.0 * margin ) ;
2007-02-01 01:07:26 +00:00
} else {
source_area = QRectF (
0.0 ,
0.0 ,
2007-10-10 22:35:32 +00:00
border_and_inset . borderWidth ( ) + 2.0 * margin ,
border_and_inset . borderHeight ( ) + 2.0 * margin
2007-02-01 01:07:26 +00:00
) ;
}
2007-01-20 18:11:42 +00:00
// si les dimensions ne sont pas precisees, l'image est exportee a l'echelle 1:1
QSize image_size = ( width = = - 1 & & height = = - 1 ) ? source_area . size ( ) . toSize ( ) : QSize ( width , height ) ;
// prepare le rendu
2006-10-27 15:47:22 +00:00
QPainter p ;
2007-10-05 12:06:39 +00:00
if ( ! p . begin ( & pix ) ) return ( false ) ;
2006-10-27 15:47:22 +00:00
// rendu antialiase
p . setRenderHint ( QPainter : : Antialiasing , true ) ;
p . setRenderHint ( QPainter : : TextAntialiasing , true ) ;
p . setRenderHint ( QPainter : : SmoothPixmapTransform , true ) ;
2007-01-20 18:11:42 +00:00
// deselectionne tous les elements
QList < QGraphicsItem * > selected_elmts = selectedItems ( ) ;
foreach ( QGraphicsItem * qgi , selected_elmts ) qgi - > setSelected ( false ) ;
// effectue le rendu lui-meme
2007-10-05 12:06:39 +00:00
render ( & p , QRect ( QPoint ( 0 , 0 ) , image_size ) , source_area , aspectRatioMode ) ;
2006-10-27 15:47:22 +00:00
p . end ( ) ;
2007-01-20 18:11:42 +00:00
// restaure les elements selectionnes
foreach ( QGraphicsItem * qgi , selected_elmts ) qgi - > setSelected ( true ) ;
2007-10-05 12:06:39 +00:00
return ( true ) ;
2006-10-27 15:47:22 +00:00
}
2007-01-20 18:11:42 +00:00
/**
Permet de connaitre les dimensions qu ' aura l ' image generee par la methode toImage ( )
@ return La taille de l ' image generee par toImage ( )
*/
2007-01-29 00:41:12 +00:00
QSize Diagram : : imageSize ( ) const {
2007-02-01 01:07:26 +00:00
// determine la zone source = contenu du schema + marges
qreal image_width , image_height ;
if ( ! use_border ) {
QRectF items_rect = itemsBoundingRect ( ) ;
image_width = items_rect . width ( ) ;
image_height = items_rect . height ( ) ;
} else {
image_width = border_and_inset . borderWidth ( ) ;
image_height = border_and_inset . borderHeight ( ) ;
}
2007-01-20 18:11:42 +00:00
2007-10-10 22:35:32 +00:00
image_width + = 2.0 * margin ;
image_height + = 2.0 * margin ;
2007-01-20 18:11:42 +00:00
// renvoie la taille de la zone source
2007-02-01 01:07:26 +00:00
return ( QSizeF ( image_width , image_height ) . toSize ( ) ) ;
2007-01-20 18:11:42 +00:00
}
2006-10-27 15:47:22 +00:00
/**
Exporte tout ou partie du schema
2007-02-24 18:37:07 +00:00
@ param diagram Booleen ( a vrai par defaut ) indiquant si le XML genere doit
2006-11-11 18:25:42 +00:00
representer tout le schema ou seulement les elements selectionnes
2006-10-27 15:47:22 +00:00
@ return Un Document XML ( QDomDocument )
*/
2007-01-29 00:41:12 +00:00
QDomDocument Diagram : : toXml ( bool diagram ) {
2006-10-27 15:47:22 +00:00
// document
QDomDocument document ;
// racine de l'arbre XML
2007-03-09 19:18:55 +00:00
QDomElement racine = document . createElement ( " diagram " ) ;
2006-10-27 15:47:22 +00:00
// proprietes du schema
2007-01-29 00:41:12 +00:00
if ( diagram ) {
2007-03-09 19:18:55 +00:00
if ( ! border_and_inset . author ( ) . isNull ( ) ) racine . setAttribute ( " author " , border_and_inset . author ( ) ) ;
2007-01-28 00:53:17 +00:00
if ( ! border_and_inset . date ( ) . isNull ( ) ) racine . setAttribute ( " date " , border_and_inset . date ( ) . toString ( " yyyyMMdd " ) ) ;
2007-03-09 19:18:55 +00:00
if ( ! border_and_inset . title ( ) . isNull ( ) ) racine . setAttribute ( " title " , border_and_inset . title ( ) ) ;
2007-01-28 00:53:17 +00:00
if ( ! border_and_inset . fileName ( ) . isNull ( ) ) racine . setAttribute ( " filename " , border_and_inset . fileName ( ) ) ;
if ( ! border_and_inset . folio ( ) . isNull ( ) ) racine . setAttribute ( " folio " , border_and_inset . folio ( ) ) ;
2007-02-28 20:48:11 +00:00
racine . setAttribute ( " cols " , border_and_inset . nbColumn ( ) ) ;
racine . setAttribute ( " colsize " , border_and_inset . columnsWidth ( ) ) ;
racine . setAttribute ( " height " , border_and_inset . columnsHeight ( ) ) ;
2007-10-14 21:38:27 +00:00
// type de conducteur par defaut
QDomElement default_conductor = document . createElement ( " defaultconductor " ) ;
defaultConductorProperties . toXml ( document , default_conductor ) ;
racine . appendChild ( default_conductor ) ;
2006-10-27 15:47:22 +00:00
}
document . appendChild ( racine ) ;
// si le schema ne contient pas d'element (et donc pas de conducteurs), on retourne de suite le document XML
if ( items ( ) . isEmpty ( ) ) return ( document ) ;
2007-10-27 13:18:17 +00:00
// creation de trois listes : une qui contient les elements, une qui contient les conducteurs, une qui contient les champs de texte
QList < Element * > list_elements ;
QList < Conductor * > list_conductors ;
QList < DiagramTextItem * > list_texts ;
2006-10-27 15:47:22 +00:00
// Determine les elements a <20> XMLiser <20>
foreach ( QGraphicsItem * qgi , items ( ) ) {
if ( Element * elmt = qgraphicsitem_cast < Element * > ( qgi ) ) {
2007-10-27 13:18:17 +00:00
if ( diagram ) list_elements < < elmt ;
else if ( elmt - > isSelected ( ) ) list_elements < < elmt ;
2007-10-03 17:02:39 +00:00
} else if ( Conductor * f = qgraphicsitem_cast < Conductor * > ( qgi ) ) {
2007-10-27 13:18:17 +00:00
if ( diagram ) list_conductors < < f ;
2007-01-29 00:41:12 +00:00
// lorsqu'on n'exporte pas tout le diagram, il faut retirer les conducteurs non selectionnes
2006-10-27 15:47:22 +00:00
// et pour l'instant, les conducteurs non selectionnes sont les conducteurs dont un des elements n'est pas relie
2007-10-27 13:18:17 +00:00
else if ( f - > terminal1 - > parentItem ( ) - > isSelected ( ) & & f - > terminal2 - > parentItem ( ) - > isSelected ( ) ) list_conductors < < f ;
} else if ( DiagramTextItem * dti = qgraphicsitem_cast < DiagramTextItem * > ( qgi ) ) {
if ( ! dti - > parentItem ( ) ) {
if ( diagram ) list_texts < < dti ;
else if ( dti - > isSelected ( ) ) list_texts < < dti ;
}
2006-10-27 15:47:22 +00:00
}
}
// table de correspondance entre les adresses des bornes et leurs ids
2007-01-29 20:14:26 +00:00
QHash < Terminal * , int > table_adr_id ;
2007-02-24 18:37:07 +00:00
// enregistrement des elements
2007-10-27 13:18:17 +00:00
if ( ! list_elements . isEmpty ( ) ) {
QDomElement elements = document . createElement ( " elements " ) ;
foreach ( Element * elmt , list_elements ) {
elements . appendChild ( elmt - > toXml ( document , table_adr_id ) ) ;
}
racine . appendChild ( elements ) ;
2006-10-27 15:47:22 +00:00
}
// enregistrement des conducteurs
2007-10-27 13:18:17 +00:00
if ( ! list_conductors . isEmpty ( ) ) {
QDomElement conductors = document . createElement ( " conductors " ) ;
foreach ( Conductor * cond , list_conductors ) {
conductors . appendChild ( cond - > toXml ( document , table_adr_id ) ) ;
}
racine . appendChild ( conductors ) ;
}
// enregistrement des champs de texte
if ( ! list_texts . isEmpty ( ) ) {
QDomElement inputs = document . createElement ( " inputs " ) ;
foreach ( DiagramTextItem * dti , list_texts ) {
inputs . appendChild ( dti - > toXml ( document ) ) ;
}
racine . appendChild ( inputs ) ;
2006-10-27 15:47:22 +00:00
}
// on retourne le document XML ainsi genere
return ( document ) ;
}
/**
2007-01-29 00:41:12 +00:00
Importe le diagram decrit dans un document XML . Si une position est
2006-11-11 18:25:42 +00:00
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 .
2006-10-27 15:47:22 +00:00
@ param document Le document XML a analyser
2007-01-29 00:41:12 +00:00
@ param position La position du diagram importe
2007-09-26 12:36:31 +00:00
@ param consider_informations Si vrai , les informations complementaires
( auteur , titre , . . . ) seront prises en compte
2007-11-09 13:06:51 +00:00
@ param content_ptr si ce pointeur vers un DiagramContentn ' est pas NULL , il
sera rempli avec le contenu ajoute au schema par le fromXml
2006-10-27 15:47:22 +00:00
@ return true si l ' import a reussi , false sinon
*/
2007-11-09 13:06:51 +00:00
bool Diagram : : fromXml ( QDomDocument & document , QPointF position , bool consider_informations , DiagramContent * content_ptr ) {
2007-10-27 13:18:17 +00:00
QDomElement root = document . documentElement ( ) ;
2006-10-27 15:47:22 +00:00
// le premier element doit etre un schema
2007-10-27 13:18:17 +00:00
if ( root . tagName ( ) ! = " diagram " ) return ( false ) ;
2007-01-29 00:41:12 +00:00
2006-10-27 15:47:22 +00:00
// lecture des attributs de ce schema
2007-01-28 00:53:17 +00:00
if ( consider_informations ) {
2007-10-27 13:18:17 +00:00
border_and_inset . setAuthor ( root . attribute ( " author " ) ) ;
border_and_inset . setTitle ( root . attribute ( " title " ) ) ;
border_and_inset . setDate ( QDate : : fromString ( root . attribute ( " date " ) , " yyyyMMdd " ) ) ;
border_and_inset . setFileName ( root . attribute ( " filename " ) ) ;
border_and_inset . setFolio ( root . attribute ( " folio " ) ) ;
2007-02-28 20:48:11 +00:00
bool ok ;
// nombre de colonnes
2007-10-27 13:18:17 +00:00
int nb_cols = root . attribute ( " cols " ) . toInt ( & ok ) ;
2007-02-28 20:48:11 +00:00
if ( ok ) border_and_inset . setNbColumns ( nb_cols ) ;
// taille des colonnes
2007-10-27 13:18:17 +00:00
double col_size = root . attribute ( " colsize " ) . toDouble ( & ok ) ;
2007-02-28 20:48:11 +00:00
if ( ok ) border_and_inset . setColumnsWidth ( col_size ) ;
// hauteur du schema
2007-10-27 13:18:17 +00:00
double height = root . attribute ( " height " ) . toDouble ( & ok ) ;
2007-02-28 20:48:11 +00:00
if ( ok ) border_and_inset . setColumnsHeight ( height ) ;
2007-10-14 21:38:27 +00:00
2007-11-14 20:27:45 +00:00
border_and_inset . adjustInsetToColumns ( ) ;
2007-10-14 21:38:27 +00:00
// repere le permier element "defaultconductor"
2007-10-27 13:18:17 +00:00
for ( QDomNode node = root . firstChild ( ) ; ! node . isNull ( ) ; node = node . nextSibling ( ) ) {
2007-10-14 21:38:27 +00:00
QDomElement elmts = node . toElement ( ) ;
if ( elmts . isNull ( ) | | elmts . tagName ( ) ! = " defaultconductor " ) continue ;
defaultConductorProperties . fromXml ( elmts ) ;
break ;
}
2007-01-28 00:53:17 +00:00
}
2006-10-27 15:47:22 +00:00
// si la racine n'a pas d'enfant : le chargement est fini (schema vide)
2007-10-27 13:18:17 +00:00
if ( root . firstChild ( ) . isNull ( ) ) return ( true ) ;
// chargement de tous les elements du fichier XML
QList < Element * > added_elements ;
QHash < int , Terminal * > table_adr_id ;
foreach ( QDomElement e , QET : : findInDomElement ( root , " elements " , " element " ) ) {
if ( ! Element : : valideXml ( e ) ) continue ;
2007-12-05 21:16:01 +00:00
// cree un element dont le type correspond a l'id type
2007-10-27 13:18:17 +00:00
QString type_id = e . attribute ( " type " ) ;
QString chemin_fichier = QETApp : : realPath ( type_id ) ;
CustomElement * nvel_elmt = new CustomElement ( chemin_fichier ) ;
if ( nvel_elmt - > isNull ( ) ) {
QString debug_message = QString ( " Le chargement de la description de l'element %1 a echoue avec le code d'erreur %2 " ) . arg ( chemin_fichier ) . arg ( nvel_elmt - > etat ( ) ) ;
delete nvel_elmt ;
qDebug ( debug_message . toLatin1 ( ) . data ( ) ) ;
continue ;
}
// charge les caracteristiques de l'element
if ( nvel_elmt - > fromXml ( e , table_adr_id ) ) {
// ajout de l'element au schema et a la liste des elements ajoutes
addItem ( nvel_elmt ) ;
added_elements < < nvel_elmt ;
} else {
delete nvel_elmt ;
qDebug ( " Le chargement des parametres d'un element a echoue " ) ;
2006-10-27 15:47:22 +00:00
}
}
2007-10-27 13:18:17 +00:00
// chargement de tous les textes du fichiers XML
QList < DiagramTextItem * > added_texts ;
foreach ( QDomElement f , QET : : findInDomElement ( root , " inputs " , " input " ) ) {
DiagramTextItem * dti = new DiagramTextItem ( 0 , this ) ;
dti - > fromXml ( f ) ;
added_texts < < dti ;
}
2006-10-27 15:47:22 +00:00
2007-10-27 13:18:17 +00:00
// gere la translation des nouveaux elements et texte si celle-ci est demandee
2006-10-27 15:47:22 +00:00
if ( position ! = QPointF ( ) ) {
// determine quel est le coin superieur gauche du rectangle entourant les elements ajoutes
qreal minimum_x = 0 , minimum_y = 0 ;
bool init = false ;
2007-10-27 13:18:17 +00:00
QList < QGraphicsItem * > added_items ;
foreach ( Element * added_element , added_elements ) added_items < < added_element ;
foreach ( DiagramTextItem * added_text , added_texts ) added_items < < added_text ;
foreach ( QGraphicsItem * item , added_items ) {
2007-11-02 18:04:13 +00:00
QPointF csg = item - > mapToScene ( item - > boundingRect ( ) ) . boundingRect ( ) . topLeft ( ) ;
2006-10-27 15:47:22 +00:00
qreal px = csg . x ( ) ;
qreal py = csg . y ( ) ;
if ( ! init ) {
minimum_x = px ;
minimum_y = py ;
init = true ;
} else {
if ( px < minimum_x ) minimum_x = px ;
if ( py < minimum_y ) minimum_y = py ;
}
}
qreal diff_x = position . x ( ) - minimum_x ;
qreal diff_y = position . y ( ) - minimum_y ;
2007-10-27 13:18:17 +00:00
foreach ( Element * added_element , added_elements ) {
added_element - > setPos ( added_element - > pos ( ) . x ( ) + diff_x , added_element - > pos ( ) . y ( ) + diff_y ) ;
}
foreach ( DiagramTextItem * added_text , added_texts ) {
added_text - > setPos ( added_text - > pos ( ) . x ( ) + diff_x , added_text - > pos ( ) . y ( ) + diff_y ) ;
2006-10-27 15:47:22 +00:00
}
}
// chargement de tous les Conducteurs du fichier XML
2007-10-27 13:18:17 +00:00
QList < Conductor * > added_conductors ;
foreach ( QDomElement f , QET : : findInDomElement ( root , " conductors " , " conductor " ) ) {
if ( ! Conductor : : valideXml ( f ) ) continue ;
// verifie que les bornes que le conducteur relie sont connues
int id_p1 = f . attribute ( " terminal1 " ) . toInt ( ) ;
int id_p2 = f . attribute ( " terminal2 " ) . toInt ( ) ;
if ( table_adr_id . contains ( id_p1 ) & & table_adr_id . contains ( id_p2 ) ) {
// pose le conducteur... si c'est possible
Terminal * p1 = table_adr_id . value ( id_p1 ) ;
Terminal * p2 = table_adr_id . value ( id_p2 ) ;
if ( p1 ! = p2 ) {
bool can_add_conductor = true ;
2007-12-09 10:30:35 +00:00
bool cia = ( ( Element * ) p2 - > parentItem ( ) ) - > internalConnections ( ) ;
2007-10-27 13:18:17 +00:00
if ( ! cia ) {
foreach ( QGraphicsItem * item , p2 - > parentItem ( ) - > children ( ) ) {
if ( item = = p1 ) can_add_conductor = false ;
2007-02-18 19:33:15 +00:00
}
2006-10-27 15:47:22 +00:00
}
2007-10-27 13:18:17 +00:00
if ( can_add_conductor ) {
Conductor * c = new Conductor ( table_adr_id . value ( id_p1 ) , table_adr_id . value ( id_p2 ) , 0 , this ) ;
c - > fromXml ( f ) ;
added_conductors < < c ;
}
}
} else qDebug ( ) < < " Le chargement du conductor " < < id_p1 < < id_p2 < < " a echoue " ;
2006-10-27 15:47:22 +00:00
}
2007-10-27 13:18:17 +00:00
// remplissage des listes facultatives
2007-11-09 13:06:51 +00:00
if ( content_ptr ! = NULL ) {
content_ptr - > elements = added_elements ;
content_ptr - > conductorsToMove = added_conductors ;
content_ptr - > textFields = added_texts ;
}
2007-10-27 13:18:17 +00:00
2006-10-27 15:47:22 +00:00
return ( true ) ;
}
2007-02-25 17:53:16 +00:00
/**
Verifie si la selection est passe d ' un etat ou elle est vide a un etat ou
elle ne l ' est pas , et inversement . Si c ' est le cas , le signal
EmptinessChanged ( ) est emis .
*/
void Diagram : : slot_checkSelectionEmptinessChange ( ) {
static bool selection_was_empty = true ;
bool selection_is_empty = selectedItems ( ) . isEmpty ( ) ;
if ( selection_was_empty ! = selection_is_empty ) {
emit ( selectionEmptinessChanged ( ) ) ;
selection_was_empty = selection_is_empty ;
}
}
2007-01-28 00:53:17 +00:00
/**
@ return Le rectangle ( coordonnees par rapport a la scene ) delimitant le bord du schema
*/
2007-01-29 00:41:12 +00:00
QRectF Diagram : : border ( ) const {
2007-01-28 00:53:17 +00:00
return (
QRectF (
2007-10-10 22:35:32 +00:00
margin ,
margin ,
2007-01-28 00:53:17 +00:00
border_and_inset . borderWidth ( ) ,
border_and_inset . borderHeight ( )
)
) ;
}
2007-09-05 20:42:08 +00:00
2007-09-15 22:14:23 +00:00
/// oublie la liste des elements et conducteurs en mouvement
void Diagram : : invalidateMovedElements ( ) {
if ( ! moved_elements_fetched ) return ;
moved_elements_fetched = false ;
elements_to_move . clear ( ) ;
2007-10-03 17:02:39 +00:00
conductors_to_move . clear ( ) ;
conductors_to_update . clear ( ) ;
2007-10-27 13:18:17 +00:00
texts_to_move . clear ( ) ;
2007-09-15 22:14:23 +00:00
}
/// reconstruit la liste des elements et conducteurs en mouvement
void Diagram : : fetchMovedElements ( ) {
// recupere les elements deplaces
foreach ( QGraphicsItem * item , selectedItems ( ) ) {
if ( Element * elmt = qgraphicsitem_cast < Element * > ( item ) ) {
elements_to_move < < elmt ;
2007-10-27 13:18:17 +00:00
} else if ( DiagramTextItem * t = qgraphicsitem_cast < DiagramTextItem * > ( item ) ) {
if ( ! t - > parentItem ( ) ) texts_to_move < < t ;
2007-09-15 22:14:23 +00:00
}
}
// pour chaque element deplace, determine les conducteurs qui seront modifies
foreach ( Element * elmt , elements_to_move ) {
foreach ( Terminal * terminal , elmt - > terminals ( ) ) {
2007-10-03 17:02:39 +00:00
foreach ( Conductor * conductor , terminal - > conductors ( ) ) {
2007-09-15 22:14:23 +00:00
Terminal * other_terminal ;
2007-10-03 17:02:39 +00:00
if ( conductor - > terminal1 = = terminal ) {
other_terminal = conductor - > terminal2 ;
2007-09-15 22:14:23 +00:00
} else {
2007-10-03 17:02:39 +00:00
other_terminal = conductor - > terminal1 ;
2007-09-15 22:14:23 +00:00
}
// si les deux elements du conducteur sont deplaces
if ( elements_to_move . contains ( static_cast < Element * > ( other_terminal - > parentItem ( ) ) ) ) {
2007-10-03 17:02:39 +00:00
conductors_to_move < < conductor ;
2007-09-15 22:14:23 +00:00
} else {
2007-10-03 17:02:39 +00:00
conductors_to_update . insert ( conductor , terminal ) ;
2007-09-15 22:14:23 +00:00
}
}
}
}
moved_elements_fetched = true ;
}
2007-09-30 12:35:25 +00:00
2007-10-27 13:18:17 +00:00
/**
Deplace les elements , conducteurs et textes selectionnes en gerant au
mieux les conducteurs ( seuls les conducteurs dont un seul des elements
est deplace sont recalcules , les autres sont deplaces ) .
@ param diff Translation a effectuer
@ param dontmove QGraphicsItem ( optionnel ) a ne pas deplacer ; note : ce
parametre ne concerne que les elements et les champs de texte .
*/
void Diagram : : moveElements ( const QPointF & diff , QGraphicsItem * dontmove ) {
// inutile de deplacer les autres elements s'il n'y a pas eu de mouvement concret
if ( diff . isNull ( ) ) return ;
current_movement + = diff ;
// deplace les elements selectionnes
foreach ( Element * element , elementsToMove ( ) ) {
if ( dontmove ! = NULL & & element = = dontmove ) continue ;
element - > setPos ( element - > pos ( ) + diff ) ;
}
// deplace certains conducteurs
foreach ( Conductor * conductor , conductorsToMove ( ) ) {
conductor - > setPos ( conductor - > pos ( ) + diff ) ;
}
// recalcule les autres conducteurs
const QHash < Conductor * , Terminal * > & conductors_modify = conductorsToUpdate ( ) ;
foreach ( Conductor * conductor , conductors_modify . keys ( ) ) {
conductor - > updateWithNewPos ( QRectF ( ) , conductors_modify [ conductor ] , conductors_modify [ conductor ] - > amarrageConductor ( ) ) ;
}
// deplace les champs de texte
foreach ( DiagramTextItem * dti , textsToMove ( ) ) {
if ( dontmove ! = NULL & & dti = = dontmove ) continue ;
dti - > setPos ( dti - > pos ( ) + diff ) ;
}
}
2007-10-10 17:50:26 +00:00
/**
Definit s ' il faut afficher ou non les bornes
@ param dt true pour afficher les bornes , false sinon
*/
2007-09-30 12:35:25 +00:00
void Diagram : : setDrawTerminals ( bool dt ) {
foreach ( QGraphicsItem * qgi , items ( ) ) {
if ( Terminal * t = qgraphicsitem_cast < Terminal * > ( qgi ) ) {
t - > setVisible ( dt ) ;
}
}
}
2007-10-03 13:11:47 +00:00
2007-10-10 17:50:26 +00:00
/**
@ return la liste des conducteurs selectionnes sur le schema
*/
2007-10-03 17:02:39 +00:00
QSet < Conductor * > Diagram : : selectedConductors ( ) const {
QSet < Conductor * > conductors_set ;
2007-10-03 13:11:47 +00:00
foreach ( QGraphicsItem * qgi , selectedItems ( ) ) {
2007-10-03 17:02:39 +00:00
if ( Conductor * c = qgraphicsitem_cast < Conductor * > ( qgi ) ) {
conductors_set < < c ;
2007-10-03 13:11:47 +00:00
}
}
2007-10-03 17:02:39 +00:00
return ( conductors_set ) ;
2007-10-03 13:11:47 +00:00
}
2007-11-03 20:20:34 +00:00
/// @return true si le presse-papier semble contenir un schema
bool Diagram : : clipboardMayContainDiagram ( ) {
QString clipboard_text = QApplication : : clipboard ( ) - > text ( ) . trimmed ( ) ;
bool may_be_diagram = clipboard_text . startsWith ( " <diagram " ) & & clipboard_text . endsWith ( " </diagram> " ) ;
return ( may_be_diagram ) ;
}
2007-11-09 13:06:51 +00:00
/**
@ return Le contenu du schema . Les conducteurs sont tous places dans
conductorsToMove .
*/
DiagramContent Diagram : : content ( ) const {
DiagramContent dc ;
foreach ( QGraphicsItem * qgi , items ( ) ) {
if ( Element * e = qgraphicsitem_cast < Element * > ( qgi ) ) {
dc . elements < < e ;
} else if ( DiagramTextItem * dti = qgraphicsitem_cast < DiagramTextItem * > ( qgi ) ) {
dc . textFields < < dti ;
} else if ( Conductor * c = qgraphicsitem_cast < Conductor * > ( qgi ) ) {
dc . conductorsToMove < < c ;
}
}
return ( dc ) ;
}
/**
@ return le contenu selectionne du schema .
*/
DiagramContent Diagram : : selectedContent ( ) {
2007-11-11 16:12:45 +00:00
invalidateMovedElements ( ) ;
2007-11-09 13:06:51 +00:00
DiagramContent dc ;
dc . elements = elementsToMove ( ) . toList ( ) ;
dc . textFields = textsToMove ( ) . toList ( ) ;
dc . conductorsToMove = conductorsToMove ( ) . toList ( ) ;
dc . conductorsToUpdate = conductorsToUpdate ( ) ;
2007-11-11 16:12:45 +00:00
// recupere les conducteurs selectionnes isoles (= non deplacables mais supprimables)
foreach ( QGraphicsItem * qgi , items ( ) ) {
if ( Conductor * c = qgraphicsitem_cast < Conductor * > ( qgi ) ) {
if (
c - > isSelected ( ) & & \
! c - > terminal1 - > parentItem ( ) - > isSelected ( ) & & \
! c - > terminal2 - > parentItem ( ) - > isSelected ( )
) {
dc . otherConductors < < c ;
}
}
}
invalidateMovedElements ( ) ;
2007-11-09 13:06:51 +00:00
return ( dc ) ;
}