2007-12-01 10:47:15 +00:00
/*
2025-01-04 13:37:40 +01:00
Copyright 2006 - 2025 The QElectroTech Team
2020-10-17 20:25:30 +02:00
This file is part of QElectroTech .
2020-09-18 23:03:35 +02:00
2020-10-17 20:25:30 +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-18 23:03:35 +02:00
2020-10-17 20:25:30 +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-18 23:03:35 +02:00
2020-10-17 20:25:30 +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-06-30 17:41:07 +00:00
# include "qet.h"
2018-06-20 18:35:06 +00:00
# include "qeticons.h"
2009-04-03 19:30:25 +00:00
# include <limits>
2013-02-08 22:05:15 +00:00
# include <QGraphicsSceneContextMenuEvent>
2018-06-20 18:35:06 +00:00
# include <QAction>
2019-03-16 10:50:30 +00:00
# include <QFileInfo>
2019-07-01 20:12:12 +02:00
# include <QSaveFile>
2020-05-12 11:17:25 +02:00
# include <QTextStream>
2020-09-18 23:03:35 +02:00
# include <QRegularExpression>
2020-10-03 11:57:23 +02:00
# include <QActionGroup>
2007-06-30 17:41:07 +00:00
/**
2020-10-17 20:25:30 +02:00
Permet de convertir une chaine de caracteres ( " n " , " s " , " e " ou " w " )
en orientation . Si la chaine fait plusieurs caracteres , seul le
premier est pris en compte . En cas d ' incoherence , Qet : : North est
retourne .
@ param s Chaine de caractere cense representer une orientation
@ return l ' orientation designee par la chaine de caractere
2021-03-11 19:52:50 +01:00
*/
Qet : : Orientation Qet : : orientationFromString ( const QString & s ) {
QChar c = s [ 0 ] ;
if ( c = = ' e ' ) return ( Qet : : East ) ;
else if ( c = = ' s ' ) return ( Qet : : South ) ;
else if ( c = = ' w ' ) return ( Qet : : West ) ;
else return ( Qet : : North ) ;
}
/**
@ param o une orientation
@ return une chaine de caractere representant l ' orientation
*/
QString Qet : : orientationToString ( Qet : : Orientation o ) {
QString ret ;
switch ( o ) {
case Qet : : North : ret = " n " ; break ;
case Qet : : East : ret = " e " ; break ;
case Qet : : South : ret = " s " ; break ;
case Qet : : West : ret = " w " ; break ;
}
return ( ret ) ;
}
/**
2020-10-17 20:25:30 +02:00
Indique si deux orientations de Borne sont sur le meme axe ( Vertical / Horizontal ) .
@ param a La premiere orientation de Borne
@ param b La seconde orientation de Borne
@ return Un booleen a true si les deux orientations de bornes sont sur le meme axe
2007-06-30 17:41:07 +00:00
*/
2014-05-29 13:46:04 +00:00
bool Qet : : surLeMemeAxe ( Qet : : Orientation a , Qet : : Orientation b ) {
2020-10-17 20:25:30 +02:00
if ( ( a = = Qet : : North | | a = = Qet : : South ) & & ( b = = Qet : : North | | b = = Qet : : South ) ) return ( true ) ;
else if ( ( a = = Qet : : East | | a = = Qet : : West ) & & ( b = = Qet : : East | | b = = Qet : : West ) ) return ( true ) ;
else return ( false ) ;
2007-06-30 17:41:07 +00:00
}
2015-01-07 19:21:17 +00:00
/**
2020-10-17 20:25:30 +02:00
@ brief Qet : : isOpposed
@ param a
@ param b
@ return true if a and b is opposed , else false ;
2020-08-16 11:19:36 +02:00
*/
2015-01-07 19:21:17 +00:00
bool Qet : : isOpposed ( Qet : : Orientation a , Qet : : Orientation b )
{
2020-10-17 20:25:30 +02:00
bool result = false ;
switch ( a )
{
case Qet : : North :
if ( b = = Qet : : South ) result = true ;
break ;
case Qet : : East :
if ( b = = Qet : : West ) result = true ;
break ;
case Qet : : South :
if ( b = = Qet : : North ) result = true ;
break ;
case Qet : : West :
if ( b = = Qet : : East ) result = true ;
break ;
default :
break ;
}
return result ;
2020-10-16 11:45:17 +02:00
}
/**
2020-10-17 20:25:30 +02:00
@ brief Qet : : isHorizontal
@ param a
@ return true if @ a is horizontal , else false .
2020-08-16 11:19:36 +02:00
*/
2015-01-18 11:28:56 +00:00
bool Qet : : isHorizontal ( Qet : : Orientation a ) {
2020-10-17 20:25:30 +02:00
return ( a = = Qet : : East | | a = = Qet : : West ) ;
2007-06-30 17:41:07 +00:00
}
/**
2020-10-17 20:25:30 +02:00
@ brief Qet : : isVertical
@ param a
@ return true if @ a is vertical , else false .
2020-08-16 11:19:36 +02:00
*/
2015-01-18 11:28:56 +00:00
bool Qet : : isVertical ( Qet : : Orientation a ) {
2020-10-17 20:25:30 +02:00
return ( a = = Qet : : North | | a = = Qet : : South ) ;
2007-06-30 17:41:07 +00:00
}
/**
2020-10-17 20:25:30 +02:00
Permet de connaitre l ' orientation suivante apres celle donnee en parametre .
Les orientations sont generalement presentees dans l ' ordre suivant : Nord ,
Est , Sud , Ouest .
@ param o une orientation
@ return l ' orientation suivante
2007-06-30 17:41:07 +00:00
*/
2014-05-29 13:46:04 +00:00
Qet : : Orientation Qet : : nextOrientation ( Qet : : Orientation o ) {
2020-10-17 20:25:30 +02:00
if ( o < 0 | | o > 2 ) return ( Qet : : North ) ;
return ( ( Qet : : Orientation ) ( o + 1 ) ) ;
2007-06-30 17:41:07 +00:00
}
/**
2020-10-17 20:25:30 +02:00
Permet de connaitre l ' orientation precedant celle donnee en parametre .
Les orientations sont generalement presentees dans l ' ordre suivant : Nord ,
Est , Sud , Ouest .
@ param o une orientation
@ return l ' orientation precedente
2007-06-30 17:41:07 +00:00
*/
2014-05-29 13:46:04 +00:00
Qet : : Orientation Qet : : previousOrientation ( Qet : : Orientation o ) {
2020-10-17 20:25:30 +02:00
if ( o < 0 | | o > 3 ) return ( Qet : : North ) ;
if ( o = = Qet : : North ) return ( Qet : : West ) ;
return ( ( Qet : : Orientation ) ( o - 1 ) ) ;
2007-06-30 17:41:07 +00:00
}
2010-05-08 21:24:43 +00:00
/**
2020-10-17 20:25:30 +02:00
@ param line Un segment de droite
@ param point Un point
@ return true si le point appartient au segment de droite , false sinon
2010-05-08 21:24:43 +00:00
*/
bool QET : : lineContainsPoint ( const QLineF & line , const QPointF & point ) {
2020-10-17 20:25:30 +02:00
if ( point = = line . p1 ( ) ) return ( true ) ;
QLineF point_line ( line . p1 ( ) , point ) ;
if ( point_line . unitVector ( ) ! = line . unitVector ( ) ) return ( false ) ;
return ( point_line . length ( ) < = line . length ( ) ) ;
2010-05-08 21:24:43 +00:00
}
/**
2020-10-17 20:25:30 +02:00
@ param point Un point donne
@ param line Un segment de droite donnee
@ param intersection si ce pointeur est different de 0 , le QPointF ainsi
designe contiendra les coordonnees du projete orthogonal , meme si celui - ci
n ' appartient pas au segment de droite
@ return true si le projete orthogonal du point sur la droite appartient au
segment de droite .
2010-05-08 21:24:43 +00:00
*/
2020-10-03 09:37:53 +02:00
bool QET : : orthogonalProjection (
2020-10-17 20:25:30 +02:00
const QPointF & point , const QLineF & line , QPointF * intersection )
2020-10-03 09:37:53 +02:00
{
2020-10-17 20:25:30 +02:00
// recupere le vecteur normal de `line'
QLineF line_normal_vector ( line . normalVector ( ) ) ;
QPointF normal_vector ( line_normal_vector . dx ( ) , line_normal_vector . dy ( ) ) ;
2020-09-18 23:03:35 +02:00
2020-10-17 20:25:30 +02:00
// cree une droite perpendiculaire a `line' passant par `point'
QLineF perpendicular_line ( point , point + normal_vector ) ;
2020-09-18 23:03:35 +02:00
2020-10-17 20:25:30 +02:00
// determine le point d'intersection des deux droites = le projete orthogonal
QPointF intersection_point ;
2020-09-24 17:01:33 +02:00
# if TODO_LIST
2020-08-28 18:32:24 +02:00
# pragma message("@TODO remove code for QT 5.14 or later")
2020-09-24 17:01:33 +02:00
# endif
2020-10-17 20:25:30 +02:00
QLineF : : IntersectType it = line .
2020-05-28 19:02:50 +02:00
# if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
2020-10-17 20:25:30 +02:00
intersect // ### Qt 6: remove
2020-05-28 19:02:50 +02:00
# else
2020-10-17 20:25:30 +02:00
intersects
2020-05-28 19:02:50 +02:00
# endif
2020-10-17 20:25:30 +02:00
( perpendicular_line , & intersection_point ) ;
2020-09-18 23:03:35 +02:00
2020-10-17 20:25:30 +02:00
// ne devrait pas arriver (mais bon...)
if ( it = = QLineF : : NoIntersection ) return ( false ) ;
2020-09-18 23:03:35 +02:00
2020-10-17 20:25:30 +02:00
// fournit le point d'intersection a l'appelant si necessaire
if ( intersection ) {
* intersection = intersection_point ;
}
2020-09-18 23:03:35 +02:00
2020-10-17 20:25:30 +02:00
// determine si le point d'intersection appartient au segment de droite
if ( QET : : lineContainsPoint ( line , intersection_point ) ) {
return ( true ) ;
}
return ( false ) ;
2010-05-08 21:24:43 +00:00
}
2007-06-30 17:41:07 +00:00
/**
2020-10-17 20:25:30 +02:00
Permet de savoir si l ' attribut nom_attribut d ' un element XML e est bien un
entier . Si oui , sa valeur est copiee dans entier .
@ param e Element XML
@ param nom_attribut Nom de l ' attribut a analyser
@ param entier Pointeur facultatif vers un entier
@ return true si l ' attribut est bien un entier , false sinon
2007-06-30 17:41:07 +00:00
*/
2020-10-03 09:37:53 +02:00
bool QET : : attributeIsAnInteger (
2020-10-17 20:25:30 +02:00
const QDomElement & e , const QString & nom_attribut , int * entier )
2020-10-03 09:37:53 +02:00
{
2020-10-17 20:25:30 +02:00
// verifie la presence de l'attribut
if ( ! e . hasAttribute ( nom_attribut ) ) return ( false ) ;
// verifie la validite de l'attribut
bool ok ;
int tmp = e . attribute ( nom_attribut ) . toInt ( & ok ) ;
if ( ! ok ) return ( false ) ;
if ( entier ! = nullptr ) * entier = tmp ;
return ( true ) ;
2007-06-30 17:41:07 +00:00
}
/**
2020-10-17 20:25:30 +02:00
Permet de savoir si l ' attribut nom_attribut d ' un element XML e est bien un
reel . Si oui , sa valeur est copiee dans reel .
@ param e Element XML
@ param nom_attribut Nom de l ' attribut a analyser
@ param reel Pointeur facultatif vers un double
@ return true si l ' attribut est bien un reel , false sinon
2007-06-30 17:41:07 +00:00
*/
2020-10-03 09:37:53 +02:00
bool QET : : attributeIsAReal (
2020-10-17 20:25:30 +02:00
const QDomElement & e , const QString & nom_attribut , qreal * reel )
2020-10-03 09:37:53 +02:00
{
2020-10-17 20:25:30 +02:00
// verifie la presence de l'attribut
if ( ! e . hasAttribute ( nom_attribut ) ) return ( false ) ;
// verifie la validite de l'attribut
bool ok ;
qreal tmp = e . attribute ( nom_attribut ) . toDouble ( & ok ) ;
if ( ! ok ) return ( false ) ;
if ( reel ! = nullptr ) * reel = tmp ;
return ( true ) ;
2020-10-16 11:45:17 +02:00
}
/**
2020-10-17 20:25:30 +02:00
@ brief QET : : ElementsAndConductorsSentence
Permet de composer rapidement la proposition " x elements et y conducteurs "
ou encore " x elements, y conducteurs et z champs de texte " .
@ param elements_count nombre d ' elements
@ param conductors_count nombre de conducteurs
@ param texts_count nombre de champs de texte
@ param images_count nombre d ' images
@ param shapes_count
@ param element_text_count
@ param tables_count
@ return la proposition decrivant le nombre d ' elements , de conducteurs et de
textes
2007-09-26 12:36:31 +00:00
*/
2020-10-03 09:37:53 +02:00
QString QET : : ElementsAndConductorsSentence (
2020-10-17 20:25:30 +02:00
int elements_count ,
int conductors_count ,
int texts_count ,
int images_count ,
int shapes_count ,
int element_text_count ,
2022-11-08 19:20:32 +01:00
int tables_count ,
int terminal_strip_count )
2020-05-12 11:17:25 +02:00
{
2020-10-17 20:25:30 +02:00
QString text ;
if ( elements_count ) {
text + = QObject : : tr (
" %n élément(s) " ,
" part of a sentence listing the content of a diagram " ,
elements_count
) ;
}
if ( conductors_count ) {
if ( ! text . isEmpty ( ) ) text + = " , " ;
text + = QObject : : tr (
" %n conducteur(s) " ,
" part of a sentence listing the content of a diagram " ,
conductors_count
) ;
}
if ( texts_count ) {
if ( ! text . isEmpty ( ) ) text + = " , " ;
text + = QObject : : tr (
" %n champ(s) de texte " ,
" part of a sentence listing the content of a diagram " ,
texts_count
) ;
}
if ( images_count ) {
if ( ! text . isEmpty ( ) ) text + = " , " ;
text + = QObject : : tr (
" %n image(s) " ,
" part of a sentence listing the content of a diagram " ,
images_count
) ;
}
if ( shapes_count ) {
if ( ! text . isEmpty ( ) ) text + = " , " ;
text + = QObject : : tr (
" %n forme(s) " ,
" part of a sentence listing the content of a diagram " ,
shapes_count
) ;
}
if ( element_text_count ) {
if ( ! text . isEmpty ( ) ) text + = " , " ;
text + = QObject : : tr (
" %n texte(s) d'élément " ,
" part of a sentence listing the content of a diagram " ,
element_text_count ) ;
}
if ( tables_count ) {
if ( ! text . isEmpty ( ) ) text + = " , " ;
text + = QObject : : tr (
" %n tableau(s) " ,
" part of a sentence listing the content of diagram " ,
tables_count ) ;
}
2022-11-08 19:20:32 +01:00
if ( terminal_strip_count ) {
if ( ! text . isEmpty ( ) ) text + = " , " ;
text + = QObject : : tr (
" %n plan de bornes " ,
" part of a sentence listing the content of a diagram " ,
terminal_strip_count ) ;
}
2020-10-17 20:25:30 +02:00
return ( text ) ;
2020-10-16 11:45:17 +02:00
}
/**
2020-10-17 20:25:30 +02:00
@ return the list of \ a tag_name elements directly under the \ a e XML element .
2012-07-01 21:54:05 +00:00
*/
2020-10-03 09:37:53 +02:00
QList < QDomElement > QET : : findInDomElement (
2020-10-17 20:25:30 +02:00
const QDomElement & e , const QString & tag_name )
2020-10-03 09:37:53 +02:00
{
2020-10-17 20:25:30 +02:00
QList < QDomElement > return_list ;
for ( QDomNode node = e . firstChild ( ) ;
! node . isNull ( ) ;
node = node . nextSibling ( ) )
{
if ( ! node . isElement ( ) ) continue ;
QDomElement element = node . toElement ( ) ;
if ( element . isNull ( ) | | element . tagName ( ) ! = tag_name ) continue ;
return_list < < element ;
}
return ( return_list ) ;
2020-10-16 11:45:17 +02:00
}
/**
2020-10-17 20:25:30 +02:00
Etant donne un element XML e , renvoie la liste de tous les elements
children imbriques dans les elements parent , eux - memes enfants de l ' elememt e
@ param e Element XML a explorer
@ param parent tag XML intermediaire
@ param children tag XML a rechercher
@ return La liste des elements XML children
2007-10-27 13:18:17 +00:00
*/
2020-10-03 09:37:53 +02:00
QList < QDomElement > QET : : findInDomElement (
2020-10-17 20:25:30 +02:00
const QDomElement & e , const QString & parent , const QString & children )
2020-10-03 09:37:53 +02:00
{
2020-10-17 20:25:30 +02:00
QList < QDomElement > return_list ;
// parcours des elements parents
for ( QDomNode enfant = e . firstChild ( ) ;
! enfant . isNull ( ) ;
enfant = enfant . nextSibling ( ) )
{
// on s'interesse a l'element XML "parent"
QDomElement parents = enfant . toElement ( ) ;
if ( parents . isNull ( ) | | parents . tagName ( ) ! = parent ) continue ;
// parcours des enfants de l'element XML "parent"
for ( QDomNode node_children = parents . firstChild ( ) ;
! node_children . isNull ( ) ;
node_children = node_children . nextSibling ( ) )
{
// on s'interesse a l'element XML "children"
QDomElement n_children = node_children . toElement ( ) ;
if ( ! n_children . isNull ( ) & & n_children . tagName ( ) = = children ) return_list . append ( n_children ) ;
}
}
return ( return_list ) ;
2007-10-27 13:18:17 +00:00
}
2007-10-28 01:32:57 +00:00
/// @return le texte de la licence de QElectroTech (GNU/GPL)
2020-09-07 22:03:40 +02:00
QString QET : : license ( )
{
2020-10-17 20:25:30 +02:00
// Recuperation du texte de la GNU/GPL dans un fichier integre a l'application
QFile * file_license = new QFile ( " :/LICENSE " ) ;
QString txt_license ;
// verifie que le fichier existe
if ( ! file_license - > exists ( ) ) {
txt_license = QString ( QObject : : tr ( " Le fichier texte contenant la licence GNU/GPL est introuvable - bon bah de toute façon, vous la connaissez par coeur non ? " ) ) ;
} else {
// ouvre le fichier en mode texte et en lecture seule
if ( ! file_license - > open ( QIODevice : : ReadOnly | QIODevice : : Text ) ) {
txt_license = QString ( QObject : : tr ( " Le fichier texte contenant la licence GNU/GPL existe mais n'a pas pu être ouvert - bon bah de toute façon, vous la connaissez par coeur non ? " ) ) ;
} else {
// charge le contenu du fichier dans une QString
QTextStream in ( file_license ) ;
txt_license = QString ( " " ) ;
while ( ! in . atEnd ( ) ) txt_license + = in . readLine ( ) + " \n " ;
// ferme le fichier
file_license - > close ( ) ;
}
}
return ( txt_license ) ;
2007-10-28 01:32:57 +00:00
} ;
2007-12-23 01:15:16 +00:00
/**
2020-10-17 20:25:30 +02:00
@ return la liste des caracteres interdits dans les noms de fichiers sous
Windows
2007-12-23 01:15:16 +00:00
*/
2020-09-07 22:03:40 +02:00
QList < QChar > QET : : forbiddenCharacters ( )
{
2020-10-17 20:25:30 +02:00
return ( QList < QChar > ( )
< < ' \\ ' < < ' / ' < < ' : ' < < ' * ' < < ' ? ' < < ' " ' < < ' < ' < < ' > ' < < ' | ' ) ;
2007-12-23 01:15:16 +00:00
}
2009-04-03 19:30:25 +00:00
/**
2020-10-17 20:25:30 +02:00
Cette fonction transforme une chaine de caracteres ( typiquement : un nom de
schema , de projet , d ' element ) en un nom de fichier potable .
Par nom de fichier potable , on entend un nom :
* ne comprenant pas de caracteres interdits sous Windows
* ne comprenant pas d ' espace
@ param name Chaine de caractere a transformer en nom de fichier potable
@ todo virer les caracteres accentues ?
2009-04-03 19:30:25 +00:00
*/
2020-09-24 17:01:33 +02:00
QString QET : : stringToFileName ( const QString & name )
{
# if TODO_LIST
# pragma message("@TODO virer les caracteres accentues ?")
# endif
2020-10-17 20:25:30 +02:00
QString file_name ( name . toLower ( ) ) ;
2020-09-18 23:03:35 +02:00
2020-10-17 20:25:30 +02:00
// remplace les caracteres interdits par des tirets
foreach ( QChar c , QET : : forbiddenCharacters ( ) ) {
file_name . replace ( c , ' - ' ) ;
}
2020-09-18 23:03:35 +02:00
2020-10-17 20:25:30 +02:00
// remplace les espaces par des underscores
file_name . replace ( ' ' , ' _ ' ) ;
2020-09-18 23:03:35 +02:00
2020-10-17 20:25:30 +02:00
return ( file_name ) ;
2009-04-03 19:30:25 +00:00
}
2008-07-26 15:26:19 +00:00
/**
2020-10-17 20:25:30 +02:00
@ param string une chaine de caracteres
@ return la meme chaine de caracteres , mais avec les espaces et backslashes
echappes
2008-07-26 15:26:19 +00:00
*/
QString QET : : escapeSpaces ( const QString & string ) {
2020-10-17 20:25:30 +02:00
return ( QString ( string ) . replace ( ' \\ ' , " \\ \\ " ) . replace ( ' ' , " \\ " ) ) ;
2008-07-26 15:26:19 +00:00
}
/**
2020-10-17 20:25:30 +02:00
@ param string une chaine de caracteres
@ return la meme chaine de caracteres , mais avec les espaces et backslashes
non echappes
2008-07-26 15:26:19 +00:00
*/
QString QET : : unescapeSpaces ( const QString & string ) {
2020-10-17 20:25:30 +02:00
return ( QString ( string ) . replace ( " \\ \\ " , " \\ " ) . replace ( " \\ " , " " ) ) ;
2008-07-26 15:26:19 +00:00
}
/**
2020-10-17 20:25:30 +02:00
Assemble une liste de chaines en une seule . Un espace separe chaque chaine .
Les espaces et backslashes des chaines sont echappes .
@ param string_list une liste de chaine
@ return l ' assemblage des chaines
2008-07-26 15:26:19 +00:00
*/
QString QET : : joinWithSpaces ( const QStringList & string_list ) {
2020-10-17 20:25:30 +02:00
QString returned_string ;
2020-09-18 23:03:35 +02:00
2020-10-17 20:25:30 +02:00
for ( int i = 0 ; i < string_list . count ( ) ; + + i ) {
returned_string + = QET : : escapeSpaces ( string_list . at ( i ) ) ;
if ( i ! = string_list . count ( ) - 1 ) returned_string + = " " ;
}
2020-09-18 23:03:35 +02:00
2020-10-17 20:25:30 +02:00
return ( returned_string ) ;
2008-07-26 15:26:19 +00:00
}
/**
2020-10-17 20:25:30 +02:00
@ param string Une chaine de caracteres contenant des sous - chaines a
extraire separees par des espaces non echappes . Les espaces des sous - chaines
sont echappes .
@ return La liste des sous - chaines , sans echappement .
2008-07-26 15:26:19 +00:00
*/
QStringList QET : : splitWithSpaces ( const QString & string ) {
2020-10-17 20:25:30 +02:00
// les chaines sont separees par des espaces non echappes
// = avec un nombre nul ou pair de backslashes devant
2020-09-24 17:01:33 +02:00
# if TODO_LIST
2020-08-28 18:32:24 +02:00
# pragma message("@TODO remove code for QT 5.14 or later")
2020-09-24 17:01:33 +02:00
# endif
2020-10-17 20:25:30 +02:00
QStringList escaped_strings = string . split ( QRegularExpression ( " [^ \\ ]?(?: \\ \\ )* " ) ,
# if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) // ### Qt 6: remove
QString
2020-06-09 22:41:01 +02:00
# else
2020-10-17 20:25:30 +02:00
Qt
2020-06-09 22:41:01 +02:00
# endif
2020-10-17 20:25:30 +02:00
: : SkipEmptyParts ) ;
2020-06-09 22:41:01 +02:00
2020-10-17 20:25:30 +02:00
QStringList returned_list ;
foreach ( QString escaped_string , escaped_strings ) {
returned_list < < QET : : unescapeSpaces ( escaped_string ) ;
}
return ( returned_list ) ;
2008-07-26 15:26:19 +00:00
}
2009-04-03 19:30:25 +00:00
/**
2020-10-17 20:25:30 +02:00
@ param end_type un type d ' extremite
@ return une chaine representant le type d ' extremite
2009-04-03 19:30:25 +00:00
*/
2014-05-29 13:46:04 +00:00
QString Qet : : endTypeToString ( const Qet : : EndType & end_type ) {
2020-10-17 20:25:30 +02:00
switch ( end_type ) {
case Qet : : Simple : return ( " simple " ) ;
case Qet : : Triangle : return ( " triangle " ) ;
case Qet : : Circle : return ( " circle " ) ;
case Qet : : Diamond : return ( " diamond " ) ;
case Qet : : None :
default :
return ( " none " ) ;
}
2009-04-03 19:30:25 +00:00
}
/**
2020-10-17 20:25:30 +02:00
@ param string une chaine representant un type d ' extremite
@ return le type d ' extremite correspondant ; si la chaine est invalide ,
QET : : None est retourne .
2009-04-03 19:30:25 +00:00
*/
2014-05-29 13:46:04 +00:00
Qet : : EndType Qet : : endTypeFromString ( const QString & string ) {
2021-03-11 19:52:50 +01:00
if ( string = = " simple " ) return ( Qet : : Simple ) ;
2020-10-17 20:25:30 +02:00
else if ( string = = " triangle " ) return ( Qet : : Triangle ) ;
else if ( string = = " circle " ) return ( Qet : : Circle ) ;
else if ( string = = " diamond " ) return ( Qet : : Diamond ) ;
else return ( Qet : : None ) ;
2009-04-03 19:30:25 +00:00
}
2009-08-09 12:51:02 +00:00
/**
2020-10-17 20:25:30 +02:00
@ param diagram_area un type de zone de schema
@ return une chaine representant le type de zone de schema
2009-08-09 12:51:02 +00:00
*/
QString QET : : diagramAreaToString ( const QET : : DiagramArea & diagram_area ) {
2020-10-17 20:25:30 +02:00
if ( diagram_area = = ElementsArea ) return ( " elements " ) ;
else return ( " border " ) ;
2009-08-09 12:51:02 +00:00
}
/**
2020-10-17 20:25:30 +02:00
@ param string une chaine representant un type de zone de schema
@ return le type de zone de schema correspondant ; si la chaine est invalide ,
QET : : ElementsArea est retourne .
2009-08-09 12:51:02 +00:00
*/
QET : : DiagramArea QET : : diagramAreaFromString ( const QString & string ) {
2020-10-17 20:25:30 +02:00
if ( ! string . compare ( " border " , Qt : : CaseInsensitive ) ) return ( QET : : BorderArea ) ;
else return ( QET : : ElementsArea ) ;
2009-08-09 12:51:02 +00:00
}
2013-03-06 18:50:46 +00:00
/**
2020-10-17 20:25:30 +02:00
Round \ a x to the nearest multiple of the invert of \ a epsilon .
For instance , epsilon = 10 will round to 1 / 10 = 0.1
2013-03-06 18:50:46 +00:00
*/
qreal QET : : round ( qreal x , qreal epsilon ) {
2020-10-17 20:25:30 +02:00
return ( int ( x * epsilon ) / epsilon ) ;
2013-03-06 18:50:46 +00:00
}
2009-12-13 16:43:35 +00:00
/**
2020-10-17 20:25:30 +02:00
@ param angle Un angle quelconque
@ return l ' angle passe en parametre , mais ramene entre - 360.0 + 360.0 degres
2009-12-13 16:43:35 +00:00
*/
2020-11-20 20:52:19 +01:00
qreal QET : : correctAngle ( const qreal & angle , const bool & positive ) {
2020-10-17 20:25:30 +02:00
// ramene l'angle demande entre -360.0 et +360.0 degres
qreal corrected_angle = angle ;
2020-11-20 20:52:19 +01:00
while ( corrected_angle < = - 360.0 | |
( positive & & corrected_angle < 0 ) ) corrected_angle + = 360.0 ;
2020-10-17 20:25:30 +02:00
while ( corrected_angle > = 360.0 ) corrected_angle - = 360.0 ;
return ( corrected_angle ) ;
2009-12-13 16:43:35 +00:00
}
2010-03-28 16:27:48 +00:00
/**
2020-10-17 20:25:30 +02:00
@ param first Un premier chemin vers un fichier
@ param second Un second chemin vers un fichier
@ return true si les deux chemins existent existent et sont identiques
lorsqu ' ils sont exprimes sous forme canonique
2010-03-28 16:27:48 +00:00
*/
bool QET : : compareCanonicalFilePaths ( const QString & first , const QString & second ) {
2020-10-17 20:25:30 +02:00
QString first_canonical_path = QFileInfo ( first ) . canonicalFilePath ( ) ;
if ( first_canonical_path . isEmpty ( ) ) return ( false ) ;
2010-03-28 16:27:48 +00:00
2020-10-17 20:25:30 +02:00
QString second_canonical_path = QFileInfo ( second ) . canonicalFilePath ( ) ;
if ( second_canonical_path . isEmpty ( ) ) return ( false ) ;
2020-09-18 23:03:35 +02:00
2015-03-02 20:14:56 +00:00
# ifdef Q_OS_WIN
2020-10-17 20:25:30 +02:00
// sous Windows, on ramene les chemins en minuscules
first_canonical_path = first_canonical_path . toLower ( ) ;
second_canonical_path = second_canonical_path . toLower ( ) ;
2010-03-28 16:27:48 +00:00
# endif
2020-09-18 23:03:35 +02:00
2020-10-17 20:25:30 +02:00
return ( first_canonical_path = = second_canonical_path ) ;
2010-03-28 16:27:48 +00:00
}
2010-12-19 18:08:08 +00:00
2012-04-09 01:03:08 +00:00
/**
2020-10-17 20:25:30 +02:00
Export an XML document to an UTF - 8 text file indented with 4 spaces , with LF
end of lines and no BOM .
@ param xml_doc An XML document to be exported
@ param filepath Path to the file to be written
@ param error_message If non - zero , will contain an error message explaining
what happened when this function returns false .
@ return false if an error occurred , true otherwise
2012-04-09 01:03:08 +00:00
*/
2019-07-01 20:12:12 +02:00
bool QET : : writeXmlFile ( QDomDocument & xml_doc , const QString & filepath , QString * error_message )
{
2020-10-17 20:25:30 +02:00
QSaveFile file ( filepath ) ;
// Note: we do not set QIODevice::Text to avoid generating CRLF end of lines
bool file_opening = file . open ( QIODevice : : WriteOnly ) ;
if ( ! file_opening )
{
if ( error_message )
{
* error_message = QString ( QObject : : tr (
" Impossible d'ouvrir le fichier %1 en écriture, erreur %2 rencontrée. " ,
" error message when attempting to write an XML file " ) ) . arg ( filepath ) . arg ( file . error ( ) ) ;
}
return ( false ) ;
}
QTextStream out ( & file ) ;
# if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) // ### Qt 6: remove
out . setCodec ( " UTF-8 " ) ;
2020-10-03 09:37:53 +02:00
# else
# if TODO_LIST
# pragma message("@TODO remove code for QT 6 or later")
# endif
2020-10-17 20:25:30 +02:00
out . setEncoding ( QStringConverter : : Utf8 ) ;
2020-10-03 09:37:53 +02:00
# endif
2020-10-17 20:25:30 +02:00
out . setGenerateByteOrderMark ( false ) ;
out < < xml_doc . toString ( 4 ) ;
if ( ! file . commit ( ) )
{
if ( error_message ) {
* error_message = QString ( QObject : : tr (
" Une erreur est survenue lors de l'écriture du fichier %1, erreur %2 rencontrée. " ,
" error message when attempting to write an XML file " ) ) . arg ( filepath ) . arg ( file . error ( ) ) ;
}
2020-09-18 23:03:35 +02:00
2020-10-17 20:25:30 +02:00
return false ;
}
2020-09-18 23:03:35 +02:00
2020-10-17 20:25:30 +02:00
return ( true ) ;
2012-04-09 01:03:08 +00:00
}
2013-02-08 22:05:15 +00:00
2014-12-04 10:57:21 +00:00
/**
2020-10-17 20:25:30 +02:00
@ brief QET : : eachStrIsEqual
@ param qsl list of string to compare
@ return true if every string is identical , else false ;
The list must not be empty
If the list can be empty , call isEmpty ( ) before calling this function
2020-08-16 11:19:36 +02:00
*/
2014-12-04 10:57:21 +00:00
bool QET : : eachStrIsEqual ( const QStringList & qsl ) {
2020-10-17 20:25:30 +02:00
if ( qsl . size ( ) = = 1 ) return true ;
foreach ( const QString t , qsl ) {
if ( qsl . at ( 0 ) ! = t ) return false ;
}
return true ;
2014-12-04 10:57:21 +00:00
}
2015-04-17 11:36:28 +00:00
/**
2020-10-17 20:25:30 +02:00
@ brief QET : : qetCollectionToString
@ param c QetCollection value to convert
@ return The QetCollection enum value converted to a QString
2020-08-16 11:19:36 +02:00
*/
2015-04-17 11:36:28 +00:00
QString QET : : qetCollectionToString ( const QET : : QetCollection & c )
{
2020-10-17 20:25:30 +02:00
switch ( c )
{
case Common :
return " common " ;
2023-12-09 12:02:04 +01:00
case Company :
return " company " ;
2020-10-17 20:25:30 +02:00
case Custom :
return " custom " ;
case Embedded :
return " embedded " ;
default :
return " common " ;
}
2015-04-17 11:36:28 +00:00
}
/**
2020-10-17 20:25:30 +02:00
@ brief QET : : qetCollectionFromString
@ param str string to convert
@ return The corresponding QetCollection value from a string .
If the string don ' t match anything , we return the failsafe value QetCollection : : Common
2020-08-16 11:19:36 +02:00
*/
2015-04-17 11:36:28 +00:00
QET : : QetCollection QET : : qetCollectionFromString ( const QString & str )
{
2020-10-17 20:25:30 +02:00
if ( str = = " common " )
return QetCollection : : Common ;
2023-12-09 12:02:04 +01:00
else if ( str = = " company " )
return QetCollection : : Company ;
2020-10-17 20:25:30 +02:00
else if ( str = = " custom " )
return QetCollection : : Custom ;
else if ( str = = " embedded " )
return QetCollection : : Embedded ;
else
return QetCollection : : Common ;
2015-04-17 11:36:28 +00:00
}
2018-06-20 18:35:06 +00:00
/**
2020-10-17 20:25:30 +02:00
@ brief QET : : depthActionGroup
@ param parent
@ return an action group which contain 4 actions ( forward , raise , lower , backward )
already made with icon , shortcut and data ( see QET : : DepthOption )
2020-08-16 11:19:36 +02:00
*/
2018-06-20 18:35:06 +00:00
QActionGroup * QET : : depthActionGroup ( QObject * parent )
{
2020-10-17 20:25:30 +02:00
QActionGroup * action_group = new QActionGroup ( parent ) ;
2018-06-20 18:35:06 +00:00
2020-10-17 20:25:30 +02:00
QAction * edit_forward = new QAction ( QET : : Icons : : BringForward , QObject : : tr ( " Amener au premier plan " ) , action_group ) ;
2021-03-11 19:52:50 +01:00
QAction * edit_raise = new QAction ( QET : : Icons : : Raise , QObject : : tr ( " Rapprocher " ) , action_group ) ;
QAction * edit_lower = new QAction ( QET : : Icons : : Lower , QObject : : tr ( " Éloigner " ) , action_group ) ;
QAction * edit_backward = new QAction ( QET : : Icons : : SendBackward , QObject : : tr ( " Envoyer au fond " ) , action_group ) ;
2019-05-18 19:35:57 +00:00
2020-10-17 20:25:30 +02:00
edit_forward - > setStatusTip ( QObject : : tr ( " Ramène la ou les sélections au premier plan " ) ) ;
edit_raise - > setStatusTip ( QObject : : tr ( " Rapproche la ou les sélections " ) ) ;
edit_lower - > setStatusTip ( QObject : : tr ( " Éloigne la ou les sélections " ) ) ;
edit_backward - > setStatusTip ( QObject : : tr ( " Envoie en arrière plan la ou les sélections " ) ) ;
2020-09-18 23:03:35 +02:00
2025-02-11 14:36:15 +01:00
edit_raise - > setShortcut ( Qt : : CTRL | Qt : : SHIFT | Qt : : Key_Up ) ;
edit_lower - > setShortcut ( Qt : : CTRL | Qt : : SHIFT | Qt : : Key_Down ) ;
edit_backward - > setShortcut ( Qt : : CTRL | Qt : : SHIFT | Qt : : Key_End ) ;
edit_forward - > setShortcut ( Qt : : CTRL | Qt : : SHIFT | Qt : : Key_Home ) ;
2020-09-18 23:03:35 +02:00
2020-10-17 20:25:30 +02:00
edit_forward - > setData ( QET : : BringForward ) ;
edit_raise - > setData ( QET : : Raise ) ;
edit_lower - > setData ( QET : : Lower ) ;
edit_backward - > setData ( QET : : SendBackward ) ;
2020-09-18 23:03:35 +02:00
2020-10-17 20:25:30 +02:00
return action_group ;
2018-06-20 18:35:06 +00:00
}
2019-03-16 10:50:30 +00:00
bool QET : : writeToFile ( QDomDocument & xml_doc , QFile * file , QString * error_message )
{
2020-10-17 20:25:30 +02:00
bool opened_here = file - > isOpen ( ) ? false : true ;
if ( ! file - > isOpen ( ) )
{
bool open_ = file - > open ( QIODevice : : WriteOnly ) ;
if ( ! open_ )
{
if ( error_message )
{
QFileInfo info_ ( * file ) ;
* error_message = QString (
QObject : : tr (
" Impossible d'ouvrir le fichier %1 en écriture, erreur %2 rencontrée. " ,
" error message when attempting to write an XML file " )
) . arg ( info_ . absoluteFilePath ( ) ) . arg ( file - > error ( ) ) ;
}
return false ;
}
}
QTextStream out ( file ) ;
out . seek ( 0 ) ;
# if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) // ### Qt 6: remove
out . setCodec ( " UTF-8 " ) ;
2020-10-03 09:37:53 +02:00
# else
# if TODO_LIST
# pragma message("@TODO remove code for QT 6 or later")
# endif
2020-10-17 20:25:30 +02:00
out . setEncoding ( QStringConverter : : Utf8 ) ;
2020-10-03 09:37:53 +02:00
# endif
2020-10-17 20:25:30 +02:00
out . setGenerateByteOrderMark ( false ) ;
out < < xml_doc . toString ( 4 ) ;
if ( opened_here ) {
file - > close ( ) ;
}
2019-03-16 10:50:30 +00:00
2020-10-17 20:25:30 +02:00
return ( true ) ;
2019-03-16 10:50:30 +00:00
}