2007-12-01 10:47:15 +00:00
/*
2020-10-16 11:45:17 +02:00
Copyright 2006 - 2020 The QElectroTech Team
This file is part of QElectroTech .
2020-09-24 17:01:33 +02:00
2020-10-16 11:45:17 +02:00
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 .
2020-09-24 17:01:33 +02:00
2020-10-16 11:45:17 +02:00
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 .
2020-09-24 17:01:33 +02:00
2020-10-16 11:45:17 +02:00
You should have received a copy of the GNU General Public License
along with QElectroTech . If not , see < http : //www.gnu.org/licenses/>.
2007-12-01 10:47:15 +00:00
*/
2007-01-29 20:14:26 +00:00
# include "terminal.h"
2018-07-19 14:14:31 +00:00
# include <utility>
2007-01-29 00:41:12 +00:00
# include "diagram.h"
2013-11-14 10:11:22 +00:00
# include "qetgraphicsitem/element.h"
# include "qetgraphicsitem/conductor.h"
2007-09-25 23:24:36 +00:00
# include "diagramcommands.h"
2015-01-09 17:18:16 +00:00
# include "conductorautonumerotation.h"
2016-08-29 15:37:42 +00:00
# include "conductortextitem.h"
2020-05-25 22:17:17 +02:00
# include "terminaldata.h"
2006-10-27 15:47:22 +00:00
2010-04-18 20:48:15 +00:00
QColor Terminal : : neutralColor = QColor ( Qt : : blue ) ;
QColor Terminal : : allowedColor = QColor ( Qt : : darkGreen ) ;
QColor Terminal : : warningColor = QColor ( " #ff8000 " ) ;
QColor Terminal : : forbiddenColor = QColor ( Qt : : red ) ;
2020-10-16 11:43:45 +02:00
const qreal Terminal : : terminalSize = 4.0 ; // TODO: store terminalSize in terminaldata, because in PartTerminal there is the same parameter. So only one is needed
2018-06-17 18:21:56 +00:00
const qreal Terminal : : Z = 1000 ;
2007-06-30 17:41:07 +00:00
2006-10-27 15:47:22 +00:00
/**
2020-10-16 11:45:17 +02:00
@ brief Terminal : : init
Methode privee pour initialiser la borne .
@ param number of terminal
@ param name of terminal
@ param hiddenName
2006-10-27 15:47:22 +00:00
*/
2020-09-07 22:03:40 +02:00
void Terminal : : init (
2020-10-16 11:45:17 +02:00
QString number , QString name , bool hiddenName )
{
// calcul de la position du point d'amarrage a l'element
dock_elmt_ = d - > m_pos ;
switch ( d - > m_orientation ) {
case Qet : : North : dock_elmt_ + = QPointF ( 0 , Terminal : : terminalSize ) ; break ;
case Qet : : East : dock_elmt_ + = QPointF ( - Terminal : : terminalSize , 0 ) ; break ;
case Qet : : West : dock_elmt_ + = QPointF ( Terminal : : terminalSize , 0 ) ; break ;
case Qet : : South :
default : dock_elmt_ + = QPointF ( 0 , - Terminal : : terminalSize ) ;
}
// Number of terminal
number_terminal_ = std : : move ( number ) ;
// Name of terminal
2020-10-16 11:43:45 +02:00
d - > m_name = std : : move ( name ) ;
2020-10-16 11:45:17 +02:00
name_terminal_hidden = hiddenName ;
// par defaut : pas de conducteur
// QRectF null
br_ = new QRectF ( ) ;
// divers
setAcceptHoverEvents ( true ) ;
setAcceptedMouseButtons ( Qt : : LeftButton ) ;
setToolTip ( QObject : : tr ( " Borne " , " tooltip " ) ) ;
setZValue ( Z ) ;
2006-10-27 15:47:22 +00:00
}
2020-05-25 22:17:17 +02:00
/*!
2020-10-16 11:45:17 +02:00
\ brief Terminal : : init
Additionaly to the init above , this method stores position and orientation into the data class
\ param pf
\ param o
\ param number
\ param name
\ param hiddenName
2020-08-16 11:19:36 +02:00
*/
2020-09-07 22:03:40 +02:00
void Terminal : : init (
2020-10-16 11:45:17 +02:00
QPointF pf ,
Qet : : Orientation o ,
QString number ,
QString name ,
bool hiddenName )
2020-05-25 22:17:17 +02:00
{
2020-10-16 11:45:17 +02:00
// definition du pount d'amarrage pour un conducteur
d - > m_pos = pf ;
2020-05-25 22:17:17 +02:00
2020-10-16 11:45:17 +02:00
// definition de l'orientation de la borne (par defaut : sud)
if ( o < Qet : : North | | o > Qet : : West ) d - > m_orientation = Qet : : South ;
else d - > m_orientation = o ;
2020-05-25 22:17:17 +02:00
2020-10-16 11:45:17 +02:00
init ( number , name , hiddenName ) ;
2020-05-25 22:17:17 +02:00
}
2006-10-27 15:47:22 +00:00
/**
2020-10-16 11:45:17 +02:00
initialise une borne
@ param pf position du point d ' amarrage pour un conducteur
@ param o orientation de la borne : Qt : : Horizontal ou Qt : : Vertical
@ param e Element auquel cette borne appartient
2006-10-27 15:47:22 +00:00
*/
2014-12-14 13:06:21 +00:00
Terminal : : Terminal ( QPointF pf , Qet : : Orientation o , Element * e ) :
2020-10-16 11:45:17 +02:00
QGraphicsObject ( e ) ,
d ( new TerminalData ( this ) ) ,
parent_element_ ( e )
2007-06-30 17:41:07 +00:00
{
2020-10-16 11:45:17 +02:00
init ( pf , o , " _ " , " _ " , false ) ;
2006-10-27 15:47:22 +00:00
}
/**
2020-10-16 11:45:17 +02:00
initialise une borne
@ param pf_x Abscisse du point d ' amarrage pour un conducteur
@ param pf_y Ordonnee du point d ' amarrage pour un conducteur
@ param o orientation de la borne : Qt : : Horizontal ou Qt : : Vertical
@ param e Element auquel cette borne appartient
2006-10-27 15:47:22 +00:00
*/
2014-12-14 13:06:21 +00:00
Terminal : : Terminal ( qreal pf_x , qreal pf_y , Qet : : Orientation o , Element * e ) :
2020-10-16 11:45:17 +02:00
QGraphicsObject ( e ) ,
d ( new TerminalData ( this ) ) ,
parent_element_ ( e )
2007-06-30 17:41:07 +00:00
{
2020-10-16 11:45:17 +02:00
init ( QPointF ( pf_x , pf_y ) , o , " _ " , " _ " , false ) ;
2013-11-13 11:55:27 +00:00
}
/**
2020-10-16 11:45:17 +02:00
initialise une borne
@ param pf position du point d ' amarrage pour un conducteur
@ param o orientation de la borne : Qt : : Horizontal ou Qt : : Vertical
@ param num number of terminal ( ex 3 - 4 for NO )
@ param name of terminal
@ param hiddenName hide or show the name
@ param e Element auquel cette borne appartient
2013-11-13 11:55:27 +00:00
*/
2020-09-07 22:03:40 +02:00
Terminal : : Terminal (
2020-10-16 11:45:17 +02:00
QPointF pf ,
Qet : : Orientation o ,
QString num ,
QString name ,
bool hiddenName ,
Element * e ) :
QGraphicsObject ( e ) ,
d ( new TerminalData ( this ) ) ,
parent_element_ ( e )
2013-11-13 11:55:27 +00:00
{
2020-10-16 11:45:17 +02:00
init ( pf , o , std : : move ( num ) , std : : move ( name ) , hiddenName ) ;
2006-10-27 15:47:22 +00:00
}
2020-05-25 22:17:17 +02:00
Terminal : : Terminal ( TerminalData * data , Element * e ) :
2020-10-16 11:45:17 +02:00
QGraphicsObject ( e ) ,
d ( data ) ,
parent_element_ ( e )
2020-05-25 22:17:17 +02:00
{
2020-09-24 17:01:33 +02:00
# if TODO_LIST
# pragma message("@TODO what is when multiple parents exist. So the other relation is lost.")
# endif
2020-10-16 11:45:17 +02:00
// TODO: what is when multiple parents exist. So the other relation is lost.
d - > setParent ( this ) ;
init ( " _ " , " _ " , false ) ;
2020-05-25 22:17:17 +02:00
}
2006-10-27 15:47:22 +00:00
/**
2020-10-16 11:45:17 +02:00
Destructeur
La destruction de la borne entraine la destruction des conducteurs
associes .
2006-10-27 15:47:22 +00:00
*/
2020-09-07 22:03:40 +02:00
Terminal : : ~ Terminal ( )
{
2020-10-16 11:45:17 +02:00
foreach ( Conductor * c , conductors_ ) delete c ;
delete br_ ;
2006-10-27 15:47:22 +00:00
}
/**
2020-10-16 11:45:17 +02:00
Permet de connaitre l ' orientation de la borne . Si le parent de la borne
est bien un Element , cette fonction renvoie l ' orientation par rapport a
la scene de la borne , en tenant compte du fait que l ' element ait pu etre
pivote . Sinon elle renvoie son sens normal .
@ return L ' orientation actuelle de la Terminal .
2006-10-27 15:47:22 +00:00
*/
2020-09-07 22:03:40 +02:00
Qet : : Orientation Terminal : : orientation ( ) const
{
2020-10-16 11:45:17 +02:00
if ( Element * elt = qgraphicsitem_cast < Element * > ( parentItem ( ) ) ) {
// orientations actuelle et par defaut de l'element
int ori_cur = elt - > orientation ( ) ;
if ( ori_cur = = 0 ) return ( d - > m_orientation ) ;
else {
// calcul l'angle de rotation implique par l'orientation de l'element parent
// angle de rotation de la borne sur la scene, divise par 90
int angle = ori_cur + d - > m_orientation ;
while ( angle > = 4 ) angle - = 4 ;
return ( ( Qet : : Orientation ) angle ) ;
}
} else return ( d - > m_orientation ) ;
2006-10-27 15:47:22 +00:00
}
2013-11-13 11:55:27 +00:00
/**
2020-10-16 11:45:17 +02:00
@ brief Terminal : : setNumber
@ param number
2020-07-15 18:17:39 +02:00
*/
2020-09-07 22:03:40 +02:00
void Terminal : : setNumber ( QString number )
{
2020-10-16 11:45:17 +02:00
number_terminal_ = std : : move ( number ) ;
2013-11-13 11:55:27 +00:00
}
2013-11-16 16:53:46 +00:00
/**
2020-10-16 11:45:17 +02:00
@ brief Terminal : : setName
@ param name : QString
@ param hiddenName : bool
2020-07-15 18:17:39 +02:00
*/
2020-09-07 22:03:40 +02:00
void Terminal : : setName ( QString name , bool hiddenName )
2020-10-16 11:43:45 +02:00
d - > m_name = std : : move ( name ) ;
2020-10-16 11:45:17 +02:00
name_terminal_hidden = hiddenName ;
2013-11-16 16:53:46 +00:00
}
2020-10-16 11:43:45 +02:00
/**
@ brief Terminal : : name
@ return the name of terminal .
*/
inline QString Terminal : : name ( ) const {
return ( d - > m_name ) ;
}
2006-10-27 15:47:22 +00:00
/**
2020-10-16 11:45:17 +02:00
@ brief Terminal : : addConductor
Add a conductor to this terminal
@ param conductor : the conductor to add .
@ return true if the conductor was successfully added
2020-07-15 18:17:39 +02:00
*/
2015-09-10 08:48:33 +00:00
bool Terminal : : addConductor ( Conductor * conductor )
{
2020-10-16 11:45:17 +02:00
if ( ! conductor ) return ( false ) ;
2020-09-07 22:03:40 +02:00
2020-10-16 11:45:17 +02:00
Q_ASSERT_X ( ( ( conductor - > terminal1 = = this ) ^ ( conductor - > terminal2 = = this ) ) ,
" Terminal::addConductor " ,
" The conductor must be linked exactly once to this terminal " ) ;
2020-09-07 22:03:40 +02:00
2020-10-16 11:45:17 +02:00
//Get the other terminal where the conductor must be linked
Terminal * other_terminal = ( conductor - > terminal1 = = this )
? conductor - > terminal2 : conductor - > terminal1 ;
2020-09-24 17:01:33 +02:00
2020-10-16 11:45:17 +02:00
//Check if this terminal isn't already linked with other_terminal
foreach ( Conductor * cond , conductors_ )
if ( cond - > terminal1 = = other_terminal | | cond - > terminal2 = = other_terminal )
return false ; //They already a conductor linked to this and other_terminal
2015-09-10 08:48:33 +00:00
2020-10-16 11:45:17 +02:00
conductors_ . append ( conductor ) ;
emit conductorWasAdded ( conductor ) ;
return ( true ) ;
2006-10-27 15:47:22 +00:00
}
2007-04-09 02:56:47 +00:00
/**
2020-10-16 11:45:17 +02:00
@ brief Terminal : : removeConductor
Remove a conductor from this terminal
@ param conductor : conductor to remove
2020-07-15 18:17:39 +02:00
*/
2015-09-10 08:48:33 +00:00
void Terminal : : removeConductor ( Conductor * conductor )
{
2020-10-16 11:45:17 +02:00
int index = conductors_ . indexOf ( conductor ) ;
if ( index = = - 1 ) return ;
conductors_ . removeAt ( index ) ;
emit conductorWasRemoved ( conductor ) ;
2006-10-27 15:47:22 +00:00
}
/**
2020-10-16 11:45:17 +02:00
@ brief Terminal : : paint
Fonction de dessin des bornes
@ param painter Le QPainter a utiliser
@ param options Les options de dessin
2006-10-27 15:47:22 +00:00
*/
2020-09-07 22:03:40 +02:00
void Terminal : : paint (
2020-10-16 11:45:17 +02:00
QPainter * painter ,
const QStyleOptionGraphicsItem * options ,
QWidget * )
2020-09-07 22:03:40 +02:00
{
2020-10-16 11:45:17 +02:00
// en dessous d'un certain zoom, les bornes ne sont plus dessinees
# if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) // ### Qt 6: remove
if ( options & & options - > levelOfDetail < 0.5 ) return ;
2020-10-03 15:48:40 +02:00
# else
# if TODO_LIST
# pragma message("@TODO remove code for QT 6 or later")
# endif
2020-10-16 11:45:17 +02:00
if ( options & & options - > levelOfDetailFromTransform ( painter - > worldTransform ( ) ) < 0.5 )
return ;
2020-10-03 15:48:40 +02:00
# endif
2020-10-16 11:45:17 +02:00
painter - > save ( ) ;
2015-11-19 15:19:45 +00:00
2020-10-16 11:45:17 +02:00
//annulation des renderhints
painter - > setRenderHint ( QPainter : : Antialiasing , false ) ;
painter - > setRenderHint ( QPainter : : TextAntialiasing , false ) ;
painter - > setRenderHint ( QPainter : : SmoothPixmapTransform , false ) ;
2020-09-07 22:03:40 +02:00
2020-10-16 11:45:17 +02:00
// on travaille avec les coordonnees de l'element parent
QPointF c = mapFromParent ( d - > m_pos ) ;
QPointF e = mapFromParent ( dock_elmt_ ) ;
2020-09-07 22:03:40 +02:00
2020-10-16 11:45:17 +02:00
QPen t ;
t . setWidthF ( 1.0 ) ;
2020-09-07 22:03:40 +02:00
2020-10-16 11:45:17 +02:00
# if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) // ### Qt 6: remove
if ( options & & options - > levelOfDetail < 1.0 )
2020-10-03 15:48:40 +02:00
# else
# if TODO_LIST
# pragma message("@TODO remove code for QT 6 or later")
# endif
2020-10-16 11:45:17 +02:00
if ( options & & options - > levelOfDetailFromTransform ( painter - > worldTransform ( ) ) < 1.0 )
2020-10-03 15:48:40 +02:00
# endif
2020-10-16 11:45:17 +02:00
{
t . setCosmetic ( true ) ;
}
// dessin de la borne en rouge
t . setColor ( Qt : : red ) ;
painter - > setPen ( t ) ;
painter - > drawLine ( c , e ) ;
// dessin du point d'amarrage au conducteur en bleu
t . setColor ( hovered_color_ ) ;
painter - > setPen ( t ) ;
painter - > setBrush ( hovered_color_ ) ;
if ( hovered_ ) {
painter - > setRenderHint ( QPainter : : Antialiasing , true ) ;
painter - > drawEllipse ( QRectF ( c . x ( ) - 2.5 , c . y ( ) - 2.5 , 5.0 , 5.0 ) ) ;
} else painter - > drawPoint ( c ) ;
//Draw help line if needed,
if ( diagram ( ) & & m_draw_help_line )
{
//Draw the help line with same orientation of terminal
//Only if there isn't docked conductor
if ( conductors ( ) . isEmpty ( ) )
{
if ( ! m_help_line )
m_help_line = new QGraphicsLineItem ( this ) ;
QPen pen ;
pen . setColor ( Qt : : darkBlue ) ;
QLineF line ( HelpLine ( ) ) ;
if ( diagram ( ) - > project ( ) - > autoConductor ( ) )
{
Terminal * t = alignedWithTerminal ( ) ;
if ( t )
{
line . setP2 ( t - > dockConductor ( ) ) ;
pen . setColor ( Qt : : darkGreen ) ;
}
}
//Map the line (in scene coordinate) to m_help_line coordinate
line . setP1 ( m_help_line - > mapFromScene ( line . p1 ( ) ) ) ;
line . setP2 ( m_help_line - > mapFromScene ( line . p2 ( ) ) ) ;
m_help_line - > setPen ( pen ) ;
m_help_line - > setLine ( line ) ;
}
//Draw the help line perpendicular to the terminal
if ( ! m_help_line_a )
{
m_help_line_a = new QGraphicsLineItem ( this ) ;
QPen pen ;
pen . setColor ( Diagram : : background_color = = Qt : : darkGray ? Qt : : lightGray : Qt : : darkGray ) ;
m_help_line_a - > setPen ( pen ) ;
}
QRectF rect = diagram ( ) - > border_and_titleblock . insideBorderRect ( ) ;
QLineF line ;
if ( Qet : : isHorizontal ( orientation ( ) ) )
{
line . setP1 ( QPointF ( dockConductor ( ) . x ( ) , rect . topLeft ( ) . y ( ) ) ) ;
line . setP2 ( QPointF ( dockConductor ( ) . x ( ) , rect . bottomLeft ( ) . y ( ) ) ) ;
}
else
{
line . setP1 ( QPointF ( rect . topLeft ( ) . x ( ) , dockConductor ( ) . y ( ) ) ) ;
line . setP2 ( QPointF ( rect . topRight ( ) . x ( ) , dockConductor ( ) . y ( ) ) ) ;
}
//Map the line (in scene coordinate) to m_help_line_a coordinate
line . setP1 ( m_help_line_a - > mapFromScene ( line . p1 ( ) ) ) ;
line . setP2 ( m_help_line_a - > mapFromScene ( line . p2 ( ) ) ) ;
m_help_line_a - > setLine ( line ) ;
}
painter - > restore ( ) ;
}
/**
@ brief Terminal : : drawHelpLine
@ param draw : true , display the help line
false , hide it .
2020-07-15 18:17:39 +02:00
*/
2015-01-07 19:21:17 +00:00
void Terminal : : drawHelpLine ( bool draw )
{
2020-10-16 11:45:17 +02:00
if ( m_draw_help_line = = draw ) return ;
2015-01-07 19:21:17 +00:00
2020-10-16 11:45:17 +02:00
m_draw_help_line = draw ;
2015-01-07 19:21:17 +00:00
2020-10-16 11:45:17 +02:00
if ( ! draw )
{
if ( m_help_line )
{
delete m_help_line ;
m_help_line = nullptr ;
}
if ( m_help_line_a )
{
delete m_help_line_a ;
m_help_line_a = nullptr ;
}
}
2015-01-07 19:21:17 +00:00
}
/**
2020-10-16 11:45:17 +02:00
@ brief Terminal : : HelpLine
@ return a line with coordinate P1 the dock point of conductor
and P2 the border of diagram , according to the orientation of terminal
The line is in scene coordinate ;
2020-07-15 18:17:39 +02:00
*/
2015-01-07 19:21:17 +00:00
QLineF Terminal : : HelpLine ( ) const
{
2020-10-16 11:45:17 +02:00
QPointF scene_dock = dockConductor ( ) ;
QRectF rect = diagram ( ) - > border_and_titleblock . insideBorderRect ( ) ;
2015-01-07 19:21:17 +00:00
2020-10-16 11:45:17 +02:00
QLineF line ( scene_dock , QPointF ( ) ) ;
2015-01-07 19:21:17 +00:00
2020-10-16 11:45:17 +02:00
//Set te second point of line to the edge of diagram,
//according with the orientation of this terminal
switch ( orientation ( ) )
{
case Qet : : North :
line . setP2 ( QPointF ( scene_dock . x ( ) , rect . top ( ) ) ) ;
break ;
case Qet : : East :
line . setP2 ( QPointF ( rect . right ( ) , scene_dock . y ( ) ) ) ;
break ;
case Qet : : South :
line . setP2 ( QPointF ( scene_dock . x ( ) , rect . bottom ( ) ) ) ;
break ;
case Qet : : West :
line . setP2 ( QPointF ( rect . left ( ) , scene_dock . y ( ) ) ) ;
break ;
}
2015-01-07 19:21:17 +00:00
2020-10-16 11:45:17 +02:00
return line ;
2015-01-07 19:21:17 +00:00
}
2006-10-27 15:47:22 +00:00
/**
2020-10-16 11:45:17 +02:00
@ brief Terminal : : boundingRect
@ return Le rectangle ( en precision flottante ) delimitant la borne et ses alentours .
2006-10-27 15:47:22 +00:00
*/
2020-09-07 22:03:40 +02:00
QRectF Terminal : : boundingRect ( ) const
{
2020-10-16 11:45:17 +02:00
if ( br_ - > isNull ( ) )
{
qreal dcx = d - > m_pos . x ( ) ;
qreal dcy = d - > m_pos . y ( ) ;
qreal dex = dock_elmt_ . x ( ) ;
qreal dey = dock_elmt_ . y ( ) ;
QPointF origin = ( dcx < = dex & & dcy < = dey ? d - > m_pos : dock_elmt_ ) ;
origin + = QPointF ( - 3.0 , - 3.0 ) ;
qreal w = qAbs ( ( int ) ( dcx - dex ) ) + 7 ;
qreal h = qAbs ( ( int ) ( dcy - dey ) ) + 7 ;
* br_ = QRectF ( origin , QSizeF ( w , h ) ) ;
}
return ( * br_ ) ;
2006-10-27 15:47:22 +00:00
}
2015-01-07 19:21:17 +00:00
/**
2020-10-16 11:45:17 +02:00
@ brief Terminal : : alignedWithTerminal
If this terminal is aligned with an other terminal
and is orientation is opposed return the other terminal
else return nullptr
@ return
2020-07-15 18:17:39 +02:00
*/
2015-01-07 19:21:17 +00:00
Terminal * Terminal : : alignedWithTerminal ( ) const
{
2020-10-16 11:45:17 +02:00
QLineF line ( HelpLine ( ) ) ;
2015-01-07 19:21:17 +00:00
2020-10-16 11:45:17 +02:00
QPainterPath path ;
path . moveTo ( line . p1 ( ) ) ;
path . lineTo ( line . p2 ( ) ) ;
2015-01-07 19:21:17 +00:00
2020-10-16 11:45:17 +02:00
//Get all QGraphicsItem in the alignement of this terminal
QList < QGraphicsItem * > qgi_list = diagram ( ) - > items ( path ) ;
2015-01-07 19:21:17 +00:00
2020-10-16 11:45:17 +02:00
//Remove all terminals of the parent element
foreach ( Terminal * t , parent_element_ - > terminals ( ) )
qgi_list . removeAll ( t ) ;
2015-01-07 19:21:17 +00:00
2020-10-16 11:45:17 +02:00
if ( qgi_list . isEmpty ( ) ) return nullptr ;
2015-01-07 19:21:17 +00:00
2020-10-16 11:45:17 +02:00
//Get terminals only if orientation is opposed with this terminal
QList < Terminal * > available_terminals ;
foreach ( QGraphicsItem * qgi , qgi_list )
{
if ( Terminal * tt = qgraphicsitem_cast < Terminal * > ( qgi ) )
{
//Call QET::lineContainsPoint to be sure the line intersect
//the dock point and not an other part of terminal
if ( Qet : : isOpposed ( orientation ( ) , tt - > orientation ( ) ) & &
QET : : lineContainsPoint ( line , tt - > dockConductor ( ) ) )
{
available_terminals < < tt ;
}
}
}
2015-01-07 19:21:17 +00:00
2020-10-16 11:45:17 +02:00
if ( available_terminals . isEmpty ( ) ) return nullptr ;
if ( available_terminals . size ( ) = = 1 ) return ( available_terminals . first ( ) ) ;
2015-01-07 19:21:17 +00:00
2020-10-16 11:45:17 +02:00
//Available_terminals have several terminals, we get the nearest terminal
line . setP2 ( available_terminals . first ( ) - > dockConductor ( ) ) ;
qreal current_lenght = line . length ( ) ;
Terminal * nearest_terminal = available_terminals . takeFirst ( ) ;
2015-01-07 19:21:17 +00:00
2020-10-16 11:45:17 +02:00
//Search the nearest terminal to this one
foreach ( Terminal * terminal , available_terminals )
{
line . setP2 ( terminal - > dockConductor ( ) ) ;
if ( line . length ( ) < current_lenght )
{
current_lenght = line . length ( ) ;
nearest_terminal = terminal ;
}
}
2015-01-07 19:21:17 +00:00
2020-10-16 11:45:17 +02:00
return nearest_terminal ;
2015-01-07 19:21:17 +00:00
}
2006-10-27 15:47:22 +00:00
/**
2020-10-16 11:45:17 +02:00
@ brief Terminal : : hoverEnterEvent
Gere l ' entree de la souris sur la zone de la Borne .
2006-10-27 15:47:22 +00:00
*/
2020-09-07 22:03:40 +02:00
void Terminal : : hoverEnterEvent ( QGraphicsSceneHoverEvent * )
{
2020-10-16 11:45:17 +02:00
hovered_ = true ;
update ( ) ;
2006-10-27 15:47:22 +00:00
}
/**
2020-10-16 11:45:17 +02:00
@ brief Terminal : : hoverMoveEvent
Gere les mouvements de la souris sur la zone de la Borne .
2006-10-27 15:47:22 +00:00
*/
2020-09-07 22:03:40 +02:00
void Terminal : : hoverMoveEvent ( QGraphicsSceneHoverEvent * ) { }
2006-10-27 15:47:22 +00:00
/**
2020-10-16 11:45:17 +02:00
@ brief Terminal : : hoverLeaveEvent
Gere le fait que la souris sorte de la zone de la Borne .
2006-10-27 15:47:22 +00:00
*/
2020-09-07 22:03:40 +02:00
void Terminal : : hoverLeaveEvent ( QGraphicsSceneHoverEvent * )
{
2020-10-16 11:45:17 +02:00
hovered_ = false ;
update ( ) ;
2006-10-27 15:47:22 +00:00
}
/**
2020-10-16 11:45:17 +02:00
@ brief Terminal : : mousePressEvent
Gere le fait qu ' on enfonce un bouton de la souris sur la Borne .
@ param e L ' evenement souris correspondant
2006-10-27 15:47:22 +00:00
*/
2020-09-07 22:03:40 +02:00
void Terminal : : mousePressEvent ( QGraphicsSceneMouseEvent * e )
{
2020-10-16 11:45:17 +02:00
if ( Diagram * diag = diagram ( ) ) {
diag - > setConductorStart ( mapToScene ( QPointF ( d - > m_pos ) ) ) ;
diag - > setConductorStop ( e - > scenePos ( ) ) ;
diag - > setConductor ( true ) ;
//setCursor(Qt::CrossCursor);
}
2006-10-27 15:47:22 +00:00
}
/**
2020-10-16 11:45:17 +02:00
@ brief Terminal : : mouseMoveEvent
Gere le fait qu ' on bouge la souris sur la Borne .
@ param e L ' evenement souris correspondant
2006-10-27 15:47:22 +00:00
*/
2020-09-07 22:03:40 +02:00
void Terminal : : mouseMoveEvent ( QGraphicsSceneMouseEvent * e )
{
2020-10-16 11:45:17 +02:00
// pendant la pose d'un conducteur, on adopte un autre curseur
//setCursor(Qt::CrossCursor);
2020-09-07 22:03:40 +02:00
2020-10-16 11:45:17 +02:00
// d'un mouvement a l'autre, il faut retirer l'effet hover de la borne precedente
if ( previous_terminal_ ) {
if ( previous_terminal_ = = this ) hovered_ = true ;
else previous_terminal_ - > hovered_ = false ;
previous_terminal_ - > hovered_color_ = previous_terminal_ - > neutralColor ;
previous_terminal_ - > update ( ) ;
}
2020-07-15 18:17:39 +02:00
2020-10-16 11:45:17 +02:00
Diagram * diag = diagram ( ) ;
if ( ! diag ) return ;
// si la scene est un Diagram, on actualise le poseur de conducteur
diag - > setConductorStop ( e - > scenePos ( ) ) ;
2020-09-24 17:01:33 +02:00
2020-10-16 11:45:17 +02:00
// on recupere la liste des qgi sous le pointeur
QList < QGraphicsItem * > qgis = diag - > items ( e - > scenePos ( ) ) ;
2020-09-24 17:01:33 +02:00
2020-10-16 11:45:17 +02:00
/* le qgi le plus haut
= le poseur de conductor
= le premier element de la liste
= la liste ne peut etre vide
= on prend le deuxieme element de la liste
*/
Q_ASSERT_X ( ! ( qgis . isEmpty ( ) ) , " Terminal::mouseMoveEvent " , " La liste d'items ne devrait pas etre vide " ) ;
2020-09-24 17:01:33 +02:00
2020-10-16 11:45:17 +02:00
// s'il n'y rien d'autre que le poseur de conducteur dans la liste, on arrete la
if ( qgis . size ( ) < = 1 ) return ;
2020-09-24 17:01:33 +02:00
2020-10-16 11:45:17 +02:00
// sinon on prend le deuxieme element de la liste et on verifie s'il s'agit d'une borne
QGraphicsItem * qgi = qgis . at ( 1 ) ;
// si le qgi est une borne...
Terminal * other_terminal = qgraphicsitem_cast < Terminal * > ( qgi ) ;
if ( ! other_terminal ) return ;
previous_terminal_ = other_terminal ;
2020-09-24 17:01:33 +02:00
2020-10-16 11:45:17 +02:00
// s'il s'agit d'une borne, on lui applique l'effet hover approprie
if ( ! canBeLinkedTo ( other_terminal ) ) {
other_terminal - > hovered_color_ = forbiddenColor ;
} else if ( other_terminal - > conductorsCount ( ) ) {
other_terminal - > hovered_color_ = warningColor ;
} else {
other_terminal - > hovered_color_ = allowedColor ;
}
2020-09-07 22:03:40 +02:00
2020-10-16 11:45:17 +02:00
other_terminal - > hovered_ = true ;
other_terminal - > update ( ) ;
2006-10-27 15:47:22 +00:00
}
2015-01-09 17:18:16 +00:00
2006-10-27 15:47:22 +00:00
/**
2020-10-16 11:45:17 +02:00
@ brief Terminal : : mouseReleaseEvent
@ param e
2020-07-15 18:17:39 +02:00
*/
2015-01-09 17:18:16 +00:00
void Terminal : : mouseReleaseEvent ( QGraphicsSceneMouseEvent * e )
{
2020-10-16 11:45:17 +02:00
previous_terminal_ = nullptr ;
hovered_color_ = neutralColor ;
if ( ! diagram ( ) ) return ;
//Stop conductor preview
diagram ( ) - > setConductor ( false ) ;
//Get item under cursor
QGraphicsItem * qgi = diagram ( ) - > itemAt ( e - > scenePos ( ) , QTransform ( ) ) ;
if ( ! qgi ) return ;
//Element must be a terminal
Terminal * other_terminal = qgraphicsitem_cast < Terminal * > ( qgi ) ;
if ( ! other_terminal ) return ;
other_terminal - > hovered_color_ = neutralColor ;
other_terminal - > hovered_ = false ;
//We stop her if we can't link this terminal with other terminal
if ( ! canBeLinkedTo ( other_terminal ) ) return ;
//Create conductor
Conductor * new_conductor = new Conductor ( this , other_terminal ) ;
//Get all conductors at the same potential of new conductors
QSet < Conductor * > conductors_list = new_conductor - > relatedPotentialConductors ( ) ;
//Compare the properties of every conductors stored in conductors_list,
//if every conductors properties is equal, we use this properties for the new conductor.
ConductorProperties others_properties ;
bool use_properties = false ;
if ( ! conductors_list . isEmpty ( ) )
{
use_properties = true ;
others_properties = ( * conductors_list . begin ( ) ) - > properties ( ) ;
foreach ( Conductor * conductor , conductors_list ) {
if ( conductor - > properties ( ) ! = others_properties )
use_properties = false ;
}
}
QUndoCommand * undo = new QUndoCommand ( ) ;
QUndoCommand * aic = new AddItemCommand < Conductor * > ( new_conductor , diagram ( ) , QPointF ( ) , undo ) ;
undo - > setText ( aic - > text ( ) ) ;
if ( use_properties )
{
Conductor * other = conductors_list . values ( ) . first ( ) ;
new_conductor - > rSequenceNum ( ) = other - > sequenceNum ( ) ;
new_conductor - > setProperties ( others_properties ) ;
}
else
{
//Autonum it
ConductorAutoNumerotation can ( new_conductor , diagram ( ) , undo ) ;
can . numerate ( ) ;
}
//Add undo command to the parent diagram
diagram ( ) - > undoStack ( ) . push ( undo ) ;
if ( use_properties )
{
Conductor * other = conductors_list . values ( ) . first ( ) ;
new_conductor - > setProperties ( other - > properties ( ) ) ;
}
}
/**
@ brief Terminal : : updateConductor
Update the path of conductor docked to this terminal
2020-07-15 18:17:39 +02:00
*/
2020-09-07 22:03:40 +02:00
void Terminal : : updateConductor ( )
{
2020-10-16 11:45:17 +02:00
foreach ( Conductor * conductor , conductors_ )
conductor - > updatePath ( ) ;
2010-04-18 20:48:15 +00:00
}
/**
2020-10-16 11:45:17 +02:00
@ brief Terminal : : isLinkedTo
@ param other_terminal Autre borne
@ return true si cette borne est reliee a other_terminal , false sion
2010-04-18 20:48:15 +00:00
*/
bool Terminal : : isLinkedTo ( Terminal * other_terminal ) {
2020-10-16 11:45:17 +02:00
if ( other_terminal = = this ) return ( false ) ;
2020-09-24 17:01:33 +02:00
2020-10-16 11:45:17 +02:00
bool already_linked = false ;
foreach ( Conductor * c , conductors_ ) {
if ( c - > terminal1 = = other_terminal | | c - > terminal2 = = other_terminal ) {
already_linked = true ;
break ;
}
}
return ( already_linked ) ;
2010-04-18 20:48:15 +00:00
}
/**
2020-10-16 11:45:17 +02:00
@ brief Terminal : : canBeLinkedTo
Checking if the terminal can be linked to \ p other_terminal or not
Reasons for not linable :
- \ p other_terminal is this terminal
- this terminal is already connected to \ p other_terminal
@ param other_terminal
@ return true if this terminal can be linked to other_terminal ,
otherwise false
2020-07-15 18:17:39 +02:00
*/
2014-12-23 19:00:37 +00:00
bool Terminal : : canBeLinkedTo ( Terminal * other_terminal )
{
2020-10-16 11:45:17 +02:00
if ( other_terminal = = this | | isLinkedTo ( other_terminal ) )
return false ;
2014-12-23 19:00:37 +00:00
2020-10-16 11:45:17 +02:00
return true ;
2006-10-27 15:47:22 +00:00
}
2020-10-16 11:43:45 +02:00
void Terminal : : setID ( int id ) {
m_id = id ;
}
2006-10-27 15:47:22 +00:00
/**
2020-10-16 11:45:17 +02:00
@ brief Terminal : : conductors
@ return La liste des conducteurs lies a cette borne
2006-10-27 15:47:22 +00:00
*/
2020-09-07 22:03:40 +02:00
QList < Conductor * > Terminal : : conductors ( ) const
{
2020-10-16 11:45:17 +02:00
return ( conductors_ ) ;
2006-10-27 15:47:22 +00:00
}
/**
2020-10-16 11:45:17 +02:00
@ brief Terminal : : toXml
Methode d ' export en XML
@ param doc Le Document XML a utiliser pour creer l ' element XML
@ return un QDomElement representant cette borne
2006-10-27 15:47:22 +00:00
*/
2020-09-07 22:03:40 +02:00
QDomElement Terminal : : toXml ( QDomDocument & doc ) const
{
2020-10-16 11:45:17 +02:00
QDomElement qdo = doc . createElement ( " terminal " ) ;
2020-07-15 18:20:08 +02:00
2020-10-16 11:43:45 +02:00
qdo . appendChild ( createXmlProperty ( doc , " number " , number_terminal_ ) ) ;
qdo . appendChild ( createXmlProperty ( doc , " nameHidden " , name_terminal_hidden ) ) ;
// store terminal data too!
// Do not store terminal data in its own child
// Bad hack. The problem is that in the diagrams the terminal is described by the position and in the Collection by the dock.
QPointF tempPos = d - > m_pos ;
d - > m_pos = dock_elmt_ ;
QDomElement terminalDataElement = d - > toXml ( doc ) ;
d - > m_pos = tempPos ;
int childsCount = terminalDataElement . childNodes ( ) . count ( ) ;
for ( int i = 0 ; i < childsCount ; i + + ) {
QDomNode node = terminalDataElement . childNodes ( ) . at ( i ) . cloneNode ( ) ; // cloneNode() is important, otherwise no deep clone is made
qdo . appendChild ( node ) ;
}
2020-07-15 18:20:08 +02:00
2020-10-16 11:45:17 +02:00
return ( qdo ) ;
2006-10-27 15:47:22 +00:00
}
/**
2020-10-16 11:45:17 +02:00
@ brief Terminal : : valideXml
Permet de savoir si un element XML represente une borne
@ param terminal Le QDomElement a analyser
@ return true si le QDomElement passe en parametre est une borne , false sinon
2006-10-27 15:47:22 +00:00
*/
2020-10-16 11:43:45 +02:00
bool Terminal : : valideXml ( const QDomElement & terminal ) {
2020-09-07 22:03:40 +02:00
{
2020-10-16 11:45:17 +02:00
if ( terminal . tagName ( ) ! = " terminal " ) return ( false ) ;
2020-09-24 17:01:33 +02:00
2020-10-16 11:43:45 +02:00
// affuteuse_250h.qet contains in line 8398 terminals which do not have this
// if (propertyString(terminal, "number"))
// return false;
// affuteuse_250h.qet contains in line 8398 terminals which do not have this
// if (propertyBool(terminal, "nameHidden"))
// return false;
2020-09-24 17:01:33 +02:00
2020-10-16 11:43:45 +02:00
if ( ! TerminalData : : valideXml ( terminal ) )
return false ;
2020-09-24 17:01:33 +02:00
2020-10-16 11:45:17 +02:00
// a ce stade, la borne est syntaxiquement correcte
2020-10-16 11:43:45 +02:00
return true ;
2006-10-27 15:47:22 +00:00
}
2020-10-16 11:43:45 +02:00
/** RETURNS True
2020-10-16 11:45:17 +02:00
@ brief Terminal : : fromXml
Permet de savoir si un element XML represente cette borne . Attention ,
l ' element XML n ' est pas verifie
@ param terminal Le QDomElement a analyser
@ return true si la borne " se reconnait "
( memes coordonnes , meme orientation ) , false sinon
2006-10-27 15:47:22 +00:00
*/
2020-10-16 11:43:45 +02:00
bool Terminal : : fromXml ( const QDomElement & terminal ) {
propertyString ( terminal , " number " , & number_terminal_ ) ;
propertyBool ( terminal , " nameHidden " , & name_terminal_hidden ) ;
if ( ! d - > fromXml ( terminal ) )
return false ;
2020-05-25 22:17:17 +02:00
2020-10-16 11:43:45 +02:00
init ( number_terminal_ , d - > m_name , name_terminal_hidden ) ; // initialize dock_elmt_. This must be done after Terminal data is initialized
return true ;
2006-10-27 15:47:22 +00:00
}
2007-09-25 23:24:36 +00:00
2020-05-25 22:17:17 +02:00
/**
2020-10-16 11:45:17 +02:00
@ brief Terminal : : dockConductor
@ return the position , relative to the scene , of the docking point for
conductors .
2020-05-25 22:17:17 +02:00
*/
2020-09-07 22:03:40 +02:00
QPointF Terminal : : dockConductor ( ) const
{
2020-10-16 11:45:17 +02:00
return ( mapToScene ( d - > m_pos ) ) ;
2020-05-25 22:17:17 +02:00
}
2010-04-18 20:48:15 +00:00
/**
2020-10-16 11:45:17 +02:00
@ brief Terminal : : diagram
@ return le Diagram auquel cette borne appartient ,
ou 0 si cette borne est independant
2010-04-18 20:48:15 +00:00
*/
2020-09-07 22:03:40 +02:00
Diagram * Terminal : : diagram ( ) const
{
2020-10-16 11:45:17 +02:00
return ( qobject_cast < Diagram * > ( scene ( ) ) ) ;
2007-09-25 23:24:36 +00:00
}
2010-04-18 20:48:15 +00:00
/**
2020-10-16 11:45:17 +02:00
@ brief Terminal : : parentElement
@ return L ' element auquel cette borne est rattachee
2010-04-18 20:48:15 +00:00
*/
2020-09-07 22:03:40 +02:00
Element * Terminal : : parentElement ( ) const
{
2020-10-16 11:45:17 +02:00
return ( parent_element_ ) ;
2010-04-18 20:48:15 +00:00
}
2013-11-13 11:55:27 +00:00
2020-09-07 22:03:40 +02:00
QUuid Terminal : : uuid ( ) const
{
2020-10-16 11:45:17 +02:00
return d - > m_uuid ;
2020-05-26 18:47:24 +02:00
}
2020-10-16 11:43:45 +02:00
int Terminal : : ID ( ) const {
return m_id ;
}
QPointF Terminal : : dockPos ( ) {
return dock_elmt_ ;
}
QPointF Terminal : : originPos ( ) {
return d - > m_pos ;
}
2014-10-09 09:02:41 +00:00
/**
2020-10-16 11:45:17 +02:00
@ brief Conductor : : relatedPotentialTerminal
Return terminal at the same potential from the same
parent element of terminal .
For folio report , return the terminal of linked other report .
For Terminal element , return the other terminal of terminal element .
@ param terminal : to start search
@ param all_diagram : if true return all related terminal ,
false return only terminal in the same diagram of t
@ return the list of terminal at the same potential
2020-07-15 18:17:39 +02:00
*/
2020-09-07 22:03:40 +02:00
QList < Terminal * > relatedPotentialTerminal (
2020-10-16 11:45:17 +02:00
const Terminal * terminal , const bool all_diagram )
{
// If terminal parent element is a folio report.
if ( all_diagram & & terminal - > parentElement ( ) - > linkType ( ) & Element : : AllReport )
{
QList < Element * > elmt_list = terminal - > parentElement ( ) - > linkedElements ( ) ;
if ( ! elmt_list . isEmpty ( ) )
{
return ( elmt_list . first ( ) - > terminals ( ) ) ;
}
}
// If terminal parent element is a Terminal element.
else if ( terminal - > parentElement ( ) - > linkType ( ) & Element : : Terminale )
{
QList < Terminal * > terminals = terminal - > parentElement ( ) - > terminals ( ) ;
terminals . removeAll ( const_cast < Terminal * > ( terminal ) ) ;
return terminals ;
}
return QList < Terminal * > ( ) ;
2014-10-09 09:02:41 +00:00
}