[ Thread Index |
Date Index
| More lists.tuxfamily.org/qet Archives
]
Modified Paths:
--------------
branches/devel/sources/conductorautonumerotation.h
branches/devel/sources/conductorautonumerotationwidget.h
branches/devel/sources/conductorprofile.cpp
branches/devel/sources/conductorpropertieswidget.cpp
branches/devel/sources/diagram.cpp
branches/devel/sources/diagramcommands.cpp
branches/devel/sources/diagramcommands.h
branches/devel/sources/diagramcontent.cpp
branches/devel/sources/diagramview.cpp
branches/devel/sources/editor/customelementpart.cpp
branches/devel/sources/elementscategorieslist.cpp
branches/devel/sources/elementscollectioncache.cpp
branches/devel/sources/elementsmover.cpp
branches/devel/sources/elementspanel.cpp
branches/devel/sources/elementtextsmover.cpp
branches/devel/sources/newelementwizard.cpp
branches/devel/sources/nomenclature.h
branches/devel/sources/qetdiagrameditor.cpp
branches/devel/sources/qetgraphicsitem/diagramimageitem.cpp
branches/devel/sources/qetgraphicsitem/diagramimageitem.h
branches/devel/sources/qetgraphicsitem/qetgraphicsitem.cpp
branches/devel/sources/qetgraphicsitem/qetgraphicsitem.h
branches/devel/sources/terminal.cpp
Added Paths:
-----------
branches/devel/sources/qetgraphicsitem/conductor.cpp
branches/devel/sources/qetgraphicsitem/conductor.h
branches/devel/sources/qetgraphicsitem/conductortextitem.cpp
branches/devel/sources/qetgraphicsitem/conductortextitem.h
branches/devel/sources/qetgraphicsitem/customelement.cpp
branches/devel/sources/qetgraphicsitem/customelement.h
branches/devel/sources/qetgraphicsitem/diagramtextitem.cpp
branches/devel/sources/qetgraphicsitem/diagramtextitem.h
branches/devel/sources/qetgraphicsitem/element.cpp
branches/devel/sources/qetgraphicsitem/element.h
branches/devel/sources/qetgraphicsitem/elementtextitem.cpp
branches/devel/sources/qetgraphicsitem/elementtextitem.h
branches/devel/sources/qetgraphicsitem/fixedelement.cpp
branches/devel/sources/qetgraphicsitem/fixedelement.h
branches/devel/sources/qetgraphicsitem/ghostelement.cpp
branches/devel/sources/qetgraphicsitem/ghostelement.h
branches/devel/sources/qetgraphicsitem/independenttextitem.cpp
branches/devel/sources/qetgraphicsitem/independenttextitem.h
Removed Paths:
-------------
branches/devel/sources/conductor.cpp
branches/devel/sources/conductor.h
branches/devel/sources/conductortextitem.cpp
branches/devel/sources/conductortextitem.h
branches/devel/sources/customelement.cpp
branches/devel/sources/customelement.h
branches/devel/sources/diagramtextitem.cpp
branches/devel/sources/diagramtextitem.h
branches/devel/sources/element.cpp
branches/devel/sources/element.h
branches/devel/sources/elementtextitem.cpp
branches/devel/sources/elementtextitem.h
branches/devel/sources/fixedelement.cpp
branches/devel/sources/fixedelement.h
branches/devel/sources/ghostelement.cpp
branches/devel/sources/ghostelement.h
branches/devel/sources/independenttextitem.cpp
branches/devel/sources/independenttextitem.h
--Ofro6XGXHTz
Content-Disposition: attachment; filename=r2596-blacksun.diff
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Deleted: branches/devel/sources/conductor.cpp
===================================================================
--- branches/devel/sources/conductor.cpp 2013-11-06 18:44:39 UTC (rev 2595)
+++ branches/devel/sources/conductor.cpp 2013-11-07 09:18:03 UTC (rev 2596)
@@ -1,1631 +0,0 @@
-/*
- Copyright 2006-2013 The QElectroTech Team
- 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/>.
-*/
-#include <QtDebug>
-#include "conductor.h"
-#include "conductorsegment.h"
-#include "conductorsegmentprofile.h"
-#include "conductortextitem.h"
-#include "element.h"
-#include "diagram.h"
-#include "diagramcommands.h"
-#include "conductorautonumerotation.h"
-#define PR(x) qDebug() << #x " = " << x;
-
-bool Conductor::pen_and_brush_initialized = false;
-QPen Conductor::conductor_pen = QPen();
-QBrush Conductor::conductor_brush = QBrush();
-QBrush Conductor::square_brush = QBrush(Qt::darkGreen);
-/**
- Constructeur
- @param p1 Premiere Borne a laquelle le conducteur est lie
- @param p2 Seconde Borne a laquelle le conducteur est lie
- @param parent_diagram QGraphicsScene a laquelle appartient le conducteur
-*/
-Conductor::Conductor(Terminal *p1, Terminal* p2, Diagram *parent_diagram) :
- QObject(),
- QGraphicsPathItem(0, parent_diagram),
- terminal1(p1),
- terminal2(p2),
- destroyed_(false),
- text_item(0),
- segments(NULL),
- moving_point(false),
- moving_segment(false),
- modified_path(false),
- has_to_save_profile(false),
- segments_squares_scale_(1.0),
- must_highlight_(Conductor::None)
-{
- //set Zvalue at 9 to be upper than the DiagramImageItem and bottom of element(10)
- setZValue(9);
- previous_z_value = zValue();
-
- // ajout du conducteur a la liste de conducteurs de chacune des deux bornes
- bool ajout_p1 = terminal1 -> addConductor(this);
- bool ajout_p2 = terminal2 -> addConductor(this);
-
- // en cas d'echec de l'ajout (conducteur deja existant notamment)
- if (!ajout_p1 || !ajout_p2) return;
-
- // attributs de dessin par defaut (communs a tous les conducteurs)
- if (!pen_and_brush_initialized) {
- conductor_pen.setJoinStyle(Qt::MiterJoin);
- conductor_pen.setCapStyle(Qt::SquareCap);
- conductor_pen.setColor(Qt::black);
- conductor_pen.setStyle(Qt::SolidLine);
- conductor_pen.setWidthF(1.0);
- conductor_brush.setColor(Qt::white);
- conductor_brush.setStyle(Qt::NoBrush);
- pen_and_brush_initialized = true;
- }
-
- // par defaut, les 4 profils sont des profils nuls = il faut utiliser priv_calculeConductor
- conductor_profiles.insert(Qt::TopLeftCorner, ConductorProfile());
- conductor_profiles.insert(Qt::TopRightCorner, ConductorProfile());
- conductor_profiles.insert(Qt::BottomLeftCorner, ConductorProfile());
- conductor_profiles.insert(Qt::BottomRightCorner, ConductorProfile());
-
- // calcul du rendu du conducteur
- generateConductorPath(terminal1 -> dockConductor(), terminal1 -> orientation(), terminal2 -> dockConductor(), terminal2 -> orientation());
- setFlags(QGraphicsItem::ItemIsSelectable);
- setAcceptsHoverEvents(true);
-
- // ajout du champ de texte editable
- text_item = new ConductorTextItem(properties_.text, this);
- calculateTextItemPosition();
- connect(
- text_item,
- SIGNAL(diagramTextChanged(DiagramTextItem *, const QString &, const QString &)),
- this,
- SLOT(displayedTextChanged())
- );
-}
-
-/**
- Destructeur
- Detruit le conducteur ainsi que ses segments. Il ne detruit pas les bornes
- mais s'en detache
-*/
-Conductor::~Conductor() {
- // se detache des bornes
- if (!isDestroyed()) destroy();
-
- // supprime les segments
- deleteSegments();
-}
-
-/**
- Met a jour la representation graphique du conducteur en recalculant son
- trace. Cette fonction est typiquement appelee lorsqu'une seule des bornes du
- conducteur a change de position.
- @param rect Rectangle a mettre a jour
- @see QGraphicsPathItem::update()
-*/
-void Conductor::updatePath(const QRectF &rect) {
- QPointF p1, p2;
- p1 = terminal1 -> dockConductor();
- p2 = terminal2 -> dockConductor();
- if (segmentsCount() && !conductor_profiles[currentPathType()].isNull())
- updateConductorPath(p1, terminal1 -> orientation(), p2, terminal2 -> orientation());
- else
- generateConductorPath(p1, terminal1 -> orientation(), p2, terminal2 -> orientation());
- calculateTextItemPosition();
- QGraphicsPathItem::update(rect);
-}
-
-/**
- Genere le QPainterPath a partir de la liste des points
-*/
-void Conductor::segmentsToPath() {
- // chemin qui sera dessine
- QPainterPath path;
-
- // s'il n'y a pa des segments, on arrete la
- if (segments == NULL) setPath(path);
-
- // demarre le chemin
- path.moveTo(segments -> firstPoint());
-
- // parcourt les segments pour dessiner le chemin
- ConductorSegment *segment = segments;
- while(segment -> hasNextSegment()) {
- path.lineTo(segment -> secondPoint());
- segment = segment -> nextSegment();
- }
-
- // termine le chemin
- path.lineTo(segment -> secondPoint());
-
- // affecte le chemin au conducteur
- setPath(path);
-}
-
-/**
- Gere les updates
- @param p1 Coordonnees du point d'amarrage de la borne 1
- @param o1 Orientation de la borne 1
- @param p2 Coordonnees du point d'amarrage de la borne 2
- @param o2 Orientation de la borne 2
-*/
-void Conductor::updateConductorPath(const QPointF &p1, QET::Orientation o1, const QPointF &p2, QET::Orientation o2) {
- Q_UNUSED(o1);
- Q_UNUSED(o2);
-
- ConductorProfile &conductor_profile = conductor_profiles[currentPathType()];
-
- Q_ASSERT_X(conductor_profile.segmentsCount(QET::Both) > 1, "Conductor::priv_modifieConductor", "pas de points a modifier");
- Q_ASSERT_X(!conductor_profile.isNull(), "Conductor::priv_modifieConductor", "pas de profil utilisable");
-
- // recupere les coordonnees fournies des bornes
- QPointF new_p1 = mapFromScene(p1);
- QPointF new_p2 = mapFromScene(p2);
- QRectF new_rect = QRectF(new_p1, new_p2);
-
- // recupere la largeur et la hauteur du profil
- qreal profile_width = conductor_profile.width();
- qreal profile_height = conductor_profile.height();
-
- // calcule les differences verticales et horizontales a appliquer
- qreal h_diff = (qAbs(new_rect.width()) - qAbs(profile_width) ) * getSign(profile_width);
- qreal v_diff = (qAbs(new_rect.height()) - qAbs(profile_height)) * getSign(profile_height);
-
- // applique les differences aux segments
- QHash<ConductorSegmentProfile *, qreal> segments_lengths;
- segments_lengths.unite(shareOffsetBetweenSegments(h_diff, conductor_profile.horizontalSegments()));
- segments_lengths.unite(shareOffsetBetweenSegments(v_diff, conductor_profile.verticalSegments()));
-
- // en deduit egalement les coefficients d'inversion (-1 pour une inversion, +1 pour conserver le meme sens)
- int horiz_coeff = getCoeff(new_rect.width(), profile_width);
- int verti_coeff = getCoeff(new_rect.height(), profile_height);
-
- // genere les nouveaux points
- QList<QPointF> points;
- points << new_p1;
- int limit = conductor_profile.segments.count() - 1;
- for (int i = 0 ; i < limit ; ++ i) {
- // dernier point
- QPointF previous_point = points.last();
-
- // profil de segment de conducteur en cours
- ConductorSegmentProfile *csp = conductor_profile.segments.at(i);
-
- // coefficient et offset a utiliser pour ce point
- qreal coeff = csp -> isHorizontal ? horiz_coeff : verti_coeff;
- qreal offset_applied = segments_lengths[csp];
-
- // applique l'offset et le coeff au point
- if (csp -> isHorizontal) {
- points << QPointF (
- previous_point.x() + (coeff * offset_applied),
- previous_point.y()
- );
- } else {
- points << QPointF (
- previous_point.x(),
- previous_point.y() + (coeff * offset_applied)
- );
- }
- }
- points << new_p2;
- pointsToSegments(points);
- segmentsToPath();
-}
-
-/**
- @param offset Longueur a repartir entre les segments
- @param segments_list Segments sur lesquels il faut repartir la longueur
- @param precision seuil en-deca duquel on considere qu'il ne reste rien a repartir
-*/
-QHash<ConductorSegmentProfile *, qreal> Conductor::shareOffsetBetweenSegments(
- const qreal &offset,
- const QList<ConductorSegmentProfile *> &segments_list,
- const qreal &precision
-) const {
- // construit le QHash qui sera retourne
- QHash<ConductorSegmentProfile *, qreal> segments_hash;
- foreach(ConductorSegmentProfile *csp, segments_list) {
- segments_hash.insert(csp, csp -> length);
- }
-
- // memorise le signe de la longueur de chaque segement
- QHash<ConductorSegmentProfile *, int> segments_signs;
- foreach(ConductorSegmentProfile *csp, segments_hash.keys()) {
- segments_signs.insert(csp, getSign(csp -> length));
- }
-
- //qDebug() << "repartition d'un offset de" << offset << "px sur" << segments_list.count() << "segments";
-
- // repartit l'offset sur les segments
- qreal remaining_offset = offset;
- while (remaining_offset > precision || remaining_offset < -precision) {
- // recupere le nombre de segments differents ayant une longueur non nulle
- uint segments_count = 0;
- foreach(ConductorSegmentProfile *csp, segments_hash.keys()) if (segments_hash[csp]) ++ segments_count;
- //qDebug() << " remaining_offset =" << remaining_offset;
- qreal local_offset = remaining_offset / segments_count;
- //qDebug() << " repartition d'un offset local de" << local_offset << "px sur" << segments_count << "segments";
- remaining_offset = 0.0;
- foreach(ConductorSegmentProfile *csp, segments_hash.keys()) {
- // ignore les segments de longueur nulle
- if (!segments_hash[csp]) continue;
- // applique l'offset au segment
- //qreal segment_old_length = segments_hash[csp];
- segments_hash[csp] += local_offset;
-
- // (la longueur du segment change de signe) <=> (le segment n'a pu absorbe tout l'offset)
- if (segments_signs[csp] != getSign(segments_hash[csp])) {
-
- // on remet le trop-plein dans la reserve d'offset
- remaining_offset += qAbs(segments_hash[csp]) * getSign(local_offset);
- //qDebug() << " trop-plein de" << qAbs(segments_hash[csp]) * getSign(local_offset) << "remaining_offset =" << remaining_offset;
- segments_hash[csp] = 0.0;
- } else {
- //qDebug() << " offset local de" << local_offset << "accepte";
- }
- }
- }
-
- return(segments_hash);
-}
-
-/**
- Calcule un trajet "par defaut" pour le conducteur
- @param p1 Coordonnees du point d'amarrage de la borne 1
- @param o1 Orientation de la borne 1
- @param p2 Coordonnees du point d'amarrage de la borne 2
- @param o2 Orientation de la borne 2
-*/
-void Conductor::generateConductorPath(const QPointF &p1, QET::Orientation o1, const QPointF &p2, QET::Orientation o2) {
- QPointF sp1, sp2, depart, newp1, newp2, arrivee, depart0, arrivee0;
- QET::Orientation ori_depart, ori_arrivee;
-
- // s'assure qu'il n'y a ni points
- QList<QPointF> points;
-
- // mappe les points par rapport a la scene
- sp1 = mapFromScene(p1);
- sp2 = mapFromScene(p2);
-
- // prolonge les bornes
- newp1 = extendTerminal(sp1, o1);
- newp2 = extendTerminal(sp2, o2);
-
- // distingue le depart de l'arrivee : le trajet se fait toujours de gauche a droite (apres prolongation)
- if (newp1.x() <= newp2.x()) {
- depart = newp1;
- arrivee = newp2;
- depart0 = sp1;
- arrivee0 = sp2;
- ori_depart = o1;
- ori_arrivee = o2;
- } else {
- depart = newp2;
- arrivee = newp1;
- depart0 = sp2;
- arrivee0 = sp1;
- ori_depart = o2;
- ori_arrivee = o1;
- }
-
- // debut du trajet
- points << depart0;
-
- // prolongement de la borne de depart
- points << depart;
-
- // commence le vrai trajet
- if (depart.y() < arrivee.y()) {
- // trajet descendant
- if ((ori_depart == QET::North && (ori_arrivee == QET::South || ori_arrivee == QET::West)) || (ori_depart == QET::East && ori_arrivee == QET::West)) {
- // cas "3"
- int ligne_inter_x = qRound(depart.x() + arrivee.x()) / 2;
- while (ligne_inter_x % Diagram::xGrid) -- ligne_inter_x;
- points << QPointF(ligne_inter_x, depart.y());
- points << QPointF(ligne_inter_x, arrivee.y());
- } else if ((ori_depart == QET::South && (ori_arrivee == QET::North || ori_arrivee == QET::East)) || (ori_depart == QET::West && ori_arrivee == QET::East)) {
- // cas "4"
- int ligne_inter_y = qRound(depart.y() + arrivee.y()) / 2;
- while (ligne_inter_y % Diagram::yGrid) -- ligne_inter_y;
- points << QPointF(depart.x(), ligne_inter_y);
- points << QPointF(arrivee.x(), ligne_inter_y);
- } else if ((ori_depart == QET::North || ori_depart == QET::East) && (ori_arrivee == QET::North || ori_arrivee == QET::East)) {
- points << QPointF(arrivee.x(), depart.y()); // cas "2"
- } else {
- points << QPointF(depart.x(), arrivee.y()); // cas "1"
- }
- } else {
- // trajet montant
- if ((ori_depart == QET::West && (ori_arrivee == QET::East || ori_arrivee == QET::South)) || (ori_depart == QET::North && ori_arrivee == QET::South)) {
- // cas "3"
- int ligne_inter_y = qRound(depart.y() + arrivee.y()) / 2;
- while (ligne_inter_y % Diagram::yGrid) -- ligne_inter_y;
- points << QPointF(depart.x(), ligne_inter_y);
- points << QPointF(arrivee.x(), ligne_inter_y);
- } else if ((ori_depart == QET::East && (ori_arrivee == QET::West || ori_arrivee == QET::North)) || (ori_depart == QET::South && ori_arrivee == QET::North)) {
- // cas "4"
- int ligne_inter_x = qRound(depart.x() + arrivee.x()) / 2;
- while (ligne_inter_x % Diagram::xGrid) -- ligne_inter_x;
- points << QPointF(ligne_inter_x, depart.y());
- points << QPointF(ligne_inter_x, arrivee.y());
- } else if ((ori_depart == QET::West || ori_depart == QET::North) && (ori_arrivee == QET::West || ori_arrivee == QET::North)) {
- points << QPointF(depart.x(), arrivee.y()); // cas "2"
- } else {
- points << QPointF(arrivee.x(), depart.y()); // cas "1"
- }
- }
-
- // fin du vrai trajet
- points << arrivee;
-
- // prolongement de la borne d'arrivee
- points << arrivee0;
-
- // inverse eventuellement l'ordre des points afin que le trajet soit exprime de la borne 1 vers la borne 2
- if (newp1.x() > newp2.x()) {
- QList<QPointF> points2;
- for (int i = points.size() - 1 ; i >= 0 ; -- i) points2 << points.at(i);
- points = points2;
- }
-
- pointsToSegments(points);
- segmentsToPath();
-}
-
-/**
- Prolonge une borne.
- @param terminal Le point correspondant a la borne
- @param terminal_orientation L'orientation de la borne
- @param ext_size la taille de la prolongation
- @return le point correspondant a la borne apres prolongation
-*/
-QPointF Conductor::extendTerminal(const QPointF &terminal, QET::Orientation terminal_orientation, qreal ext_size) {
- QPointF extended_terminal;
- switch(terminal_orientation) {
- case QET::North:
- extended_terminal = QPointF(terminal.x(), terminal.y() - ext_size);
- break;
- case QET::East:
- extended_terminal = QPointF(terminal.x() + ext_size, terminal.y());
- break;
- case QET::South:
- extended_terminal = QPointF(terminal.x(), terminal.y() + ext_size);
- break;
- case QET::West:
- extended_terminal = QPointF(terminal.x() - ext_size, terminal.y());
- break;
- default: extended_terminal = terminal;
- }
- return(extended_terminal);
-}
-
-/**
- Dessine le conducteur sans antialiasing.
- @param qp Le QPainter a utiliser pour dessiner le conducteur
- @param options Les options de style pour le conducteur
- @param qw Le QWidget sur lequel on dessine
-*/
-void Conductor::paint(QPainter *qp, const QStyleOptionGraphicsItem *options, QWidget *qw) {
- Q_UNUSED(qw);
- qp -> save();
- qp -> setRenderHint(QPainter::Antialiasing, false);
-
- // determine la couleur du conducteur
- QColor final_conductor_color(properties_.color);
- if (must_highlight_ == Normal) {
- final_conductor_color = QColor::fromRgb(69, 137, 255, 255);
- } else if (must_highlight_ == Alert) {
- final_conductor_color =QColor::fromRgb(255, 69, 0, 255);
- } else if (isSelected()) {
- final_conductor_color = Qt::red;
- } else {
- if (Diagram *parent_diagram = diagram()) {
- if (!parent_diagram -> drawColoredConductors()) {
- final_conductor_color = Qt::black;
- }
- }
- }
-
- // affectation du QPen et de la QBrush modifies au QPainter
- qp -> setBrush(conductor_brush);
- QPen final_conductor_pen = conductor_pen;
-
- // modification du QPen generique pour lui affecter la couleur et le style adequats
- final_conductor_pen.setColor(final_conductor_color);
- final_conductor_pen.setStyle(properties_.style);
- final_conductor_pen.setJoinStyle(Qt::SvgMiterJoin); // meilleur rendu des pointilles
-
- // utilisation d'un trait "cosmetique" en-dessous d'un certain zoom
- if (options && options -> levelOfDetail < 1.0) {
- final_conductor_pen.setCosmetic(true);
- }
-
- qp -> setPen(final_conductor_pen);
-
- // dessin du conducteur
- qp -> drawPath(path());
- if (properties_.type == ConductorProperties::Single) {
- qp -> setBrush(final_conductor_color);
- properties_.singleLineProperties.draw(
- qp,
- middleSegment() -> isHorizontal() ? QET::Horizontal : QET::Vertical,
- QRectF(middleSegment() -> middle() - QPointF(12.0, 12.0), QSizeF(24.0, 24.0))
- );
- if (isSelected()) qp -> setBrush(Qt::NoBrush);
- }
-
- // decalage ideal pour le rendu centre d'un carre / cercle de 2.0 px de cote / diametre
- qreal pretty_offset = (options -> levelOfDetail == 1 ? 1.0 : 1.0);
-
- // dessin des points d'accroche du conducteur si celui-ci est selectionne
- if (isSelected()) {
- QList<QPointF> points = segmentsToPoints();
- QPointF previous_point;
- for (int i = 1 ; i < (points.size() -1) ; ++ i) {
- QPointF point = points.at(i);
-
- // dessine le carre de saisie du segment
- if (i > 1) {
- qp -> fillRect(
- QRectF(
- ((previous_point.x() + point.x()) / 2.0 ) - pretty_offset * segments_squares_scale_,
- ((previous_point.y() + point.y()) / 2.0 ) - pretty_offset * segments_squares_scale_,
- 2.0 * segments_squares_scale_,
- 2.0 * segments_squares_scale_
- ),
- square_brush
- );
- }
- previous_point = point;
- }
- }
-
- // dessine les eventuelles jonctions
- QList<QPointF> junctions_list = junctions();
- if (!junctions_list.isEmpty()) {
- final_conductor_pen.setStyle(Qt::SolidLine);
- QBrush junction_brush(final_conductor_color, Qt::SolidPattern);
- qp -> setPen(final_conductor_pen);
- qp -> setBrush(junction_brush);
- qp -> setRenderHint(QPainter::Antialiasing, true);
- foreach(QPointF point, junctions_list) {
- qp -> drawEllipse(QRectF(point.x() - pretty_offset, point.y() - pretty_offset, 2.0, 2.0));
- }
- }
- qp -> restore();
-}
-
-/**
- Methode de preparation a la destruction du conducteur ; le conducteur se detache de ses deux bornes
-*/
-void Conductor::destroy() {
- destroyed_ = true;
- terminal1 -> removeConductor(this);
- terminal2 -> removeConductor(this);
-}
-
-/// @return le Diagram auquel ce conducteur appartient, ou 0 si ce conducteur est independant
-Diagram *Conductor::diagram() const {
- return(qobject_cast<Diagram *>(scene()));
-}
-
-/**
- @return le champ de texte associe a ce conducteur
-*/
-ConductorTextItem *Conductor::textItem() const {
- return(text_item);
-}
-
-/**
- Methode de validation d'element XML
- @param e Un element XML sense represente un Conducteur
- @return true si l'element XML represente bien un Conducteur ; false sinon
-*/
-bool Conductor::valideXml(QDomElement &e){
- // verifie le nom du tag
- if (e.tagName() != "conductor") return(false);
-
- // verifie la presence des attributs minimaux
- if (!e.hasAttribute("terminal1")) return(false);
- if (!e.hasAttribute("terminal2")) return(false);
-
- bool conv_ok;
- // parse l'abscisse
- e.attribute("terminal1").toInt(&conv_ok);
- if (!conv_ok) return(false);
-
- // parse l'ordonnee
- e.attribute("terminal2").toInt(&conv_ok);
- if (!conv_ok) return(false);
- return(true);
-}
-
-/**
- Gere les clics sur le conducteur.
- @param e L'evenement decrivant le clic.
-*/
-void Conductor::mousePressEvent(QGraphicsSceneMouseEvent *e) {
- // clic gauche
- if (e -> buttons() & Qt::LeftButton) {
- // recupere les coordonnees du clic
- press_point = e -> pos();
-
- /*
- parcourt les segments pour determiner si le clic a eu lieu
- - sur l'extremite d'un segment
- - sur le milieu d'un segment
- - ailleurs
- */
- ConductorSegment *segment = segments;
- while (segment -> hasNextSegment()) {
- if (hasClickedOn(press_point, segment -> secondPoint())) {
- moving_point = true;
- moving_segment = false;
- moved_segment = segment;
- break;
- } else if (hasClickedOn(press_point, segment -> middle())) {
- moving_point = false;
- moving_segment = true;
- moved_segment = segment;
- break;
- }
- segment = segment -> nextSegment();
- }
- if (moving_segment || moving_point) {
- // en cas de debut de modification de conducteur, on memorise la position du champ de texte
- before_mov_text_pos_ = text_item -> pos();
- }
- }
- QGraphicsPathItem::mousePressEvent(e);
- if (e -> modifiers() & Qt::ControlModifier) {
- setSelected(!isSelected());
- }
-}
-
-/**
- Gere les deplacements de souris sur le conducteur.
- @param e L'evenement decrivant le deplacement de souris.
-*/
-void Conductor::mouseMoveEvent(QGraphicsSceneMouseEvent *e) {
- // clic gauche
- if (e -> buttons() & Qt::LeftButton) {
- // position pointee par la souris
- qreal mouse_x = e -> pos().x();
- qreal mouse_y = e -> pos().y();
-
- bool snap_conductors_to_grid = e -> modifiers() ^ Qt::ShiftModifier;
- if (snap_conductors_to_grid) {
- mouse_x = qRound(mouse_x / (Diagram::xGrid * 1.0)) * Diagram::xGrid;
- mouse_y = qRound(mouse_y / (Diagram::yGrid * 1.0)) * Diagram::yGrid;
- }
-
- if (moving_point) {
- // la modification par points revient bientot
- /*
- // position precedente du point
- QPointF p = moved_segment -> secondPoint();
- qreal p_x = p.x();
- qreal p_y = p.y();
-
- // calcul du deplacement
- moved_segment -> moveX(mouse_x - p_x());
- moved_segment -> moveY(mouse_y - p_y());
-
- // application du deplacement
- modified_path = true;
- updatePoints();
- segmentsToPath();
- */
- } else if (moving_segment) {
- // position precedente du point
- QPointF p = moved_segment -> middle();
-
- // calcul du deplacement
- moved_segment -> moveX(mouse_x - p.x());
- moved_segment -> moveY(mouse_y - p.y());
-
- // application du deplacement
- modified_path = true;
- has_to_save_profile = true;
- segmentsToPath();
- calculateTextItemPosition();
- }
- }
- QGraphicsPathItem::mouseMoveEvent(e);
-}
-
-/**
- Gere les relachements de boutons de souris sur le conducteur
- @param e L'evenement decrivant le lacher de bouton.
-*/
-void Conductor::mouseReleaseEvent(QGraphicsSceneMouseEvent *e) {
- // clic gauche
- moving_point = false;
- moving_segment = false;
- if (has_to_save_profile) {
- saveProfile();
- has_to_save_profile = false;
- }
- if (!(e -> modifiers() & Qt::ControlModifier)) {
- QGraphicsPathItem::mouseReleaseEvent(e);
- }
- calculateTextItemPosition();
-}
-
-/**
- Gere l'entree de la souris dans la zone du conducteur
- @param e Le QGraphicsSceneHoverEvent decrivant l'evenement
-*/
-void Conductor::hoverEnterEvent(QGraphicsSceneHoverEvent *e) {
- Q_UNUSED(e);
- segments_squares_scale_ = 2.0;
- if (isSelected()) {
- update();
- }
-}
-
-/**
- Gere la sortie de la souris de la zone du conducteur
- @param e Le QGraphicsSceneHoverEvent decrivant l'evenement
-*/
-void Conductor::hoverLeaveEvent(QGraphicsSceneHoverEvent *e) {
- Q_UNUSED(e);
- segments_squares_scale_ = 1.0;
- if (isSelected()) {
- update();
- }
-}
-
-/**
- Gere les mouvements de souris au dessus du conducteur
- @param e Le QGraphicsSceneHoverEvent decrivant l'evenement
-*/
-void Conductor::hoverMoveEvent(QGraphicsSceneHoverEvent *e) {
- /*
- if (isSelected()) {
- QPointF hover_point = mapFromScene(e -> pos());
- ConductorSegment *segment = segments;
- bool cursor_set = false;
- while (segment -> hasNextSegment()) {
- if (hasClickedOn(hover_point, segment -> secondPoint())) {
- setCursor(Qt::CrossCursor);
- cursor_set = true;
- } else if (hasClickedOn(hover_point, segment -> middle())) {
- setCursor(segment -> isVertical() ? Qt::SplitHCursor : Qt::SplitVCursor);
- cursor_set = true;
- }
- segment = segment -> nextSegment();
- }
- if (!cursor_set) setCursor(Qt::ArrowCursor);
- }
- */
- QGraphicsPathItem::hoverMoveEvent(e);
-}
-
-/**
- Gere les changements relatifs au conducteur
- Reimplemente ici pour :
- * positionner le conducteur en avant-plan lorsqu'il est selectionne
- @param change Type de changement
- @param value Valeur relative au changement
-*/
-QVariant Conductor::itemChange(GraphicsItemChange change, const QVariant &value) {
- if (change == QGraphicsItem::ItemSelectedChange) {
- if (value.toBool()) {
- // le conducteur vient de se faire selectionner
- previous_z_value = zValue();
- setZValue(qAbs(previous_z_value) + 10000);
- } else {
- // le conducteur vient de se faire deselectionner
- setZValue(previous_z_value);
- }
- } else if (change == QGraphicsItem::ItemSceneHasChanged) {
- // permet de positionner correctement le texte du conducteur lors de son ajout a un schema
- calculateTextItemPosition();
- } else if (change == QGraphicsItem::ItemVisibleHasChanged) {
- // permet de positionner correctement le texte du conducteur lors de son ajout a un schema
- calculateTextItemPosition();
- }
- return(QGraphicsPathItem::itemChange(change, value));
-}
-
-/**
- @return Le rectangle delimitant l'espace de dessin du conducteur
-*/
-QRectF Conductor::boundingRect() const {
- QRectF retour = QGraphicsPathItem::boundingRect();
- retour.adjust(-11.0, -11.0, 11.0, 11.0);
- return(retour);
-}
-
-/**
- @return La forme / zone "cliquable" du conducteur (epaisseur : 5.0px).
- @see variableShape()
-*/
-QPainterPath Conductor::shape() const {
- return(variableShape(5.0));
-}
-
-/**
- @return la distance en dessous de laquelle on considere qu'un point est a
- proximite du trajet du conducteur. La valeur est actuellement fixee a
- 60.0px.
-*/
-qreal Conductor::nearDistance() const {
- return(60.0);
-}
-
-/**
- @return la zone dans laquelle dont on considere que tous les points sont a
- proximite du trajet du conducteur.
- @see nearDistance()
- @see variableShape()
-*/
-QPainterPath Conductor::nearShape() const {
- return(variableShape(nearDistance()));
-}
-
-/**
- @return la forme du conducteur
- @param thickness la moitie de l'epaisseur voulue pour cette forme
-*/
-QPainterPath Conductor::variableShape(const qreal &thickness) const {
- qreal my_thickness = qAbs(thickness);
-
- QList<QPointF> points = segmentsToPoints();
- QPainterPath area;
- QPointF previous_point;
- QPointF *point1, *point2;
- foreach(QPointF point, points) {
- if (!previous_point.isNull()) {
- if (point.x() == previous_point.x()) {
- if (point.y() <= previous_point.y()) {
- point1 = &point;
- point2 = &previous_point;
- } else {
- point1 = &previous_point;
- point2 = &point;
- }
- } else {
- if (point.x() <= previous_point.x()) {
- point1 = &point;
- point2 = &previous_point;
- } else {
- point1 = &previous_point;
- point2 = &point;
- }
- }
- qreal p1_x = point1 -> x();
- qreal p1_y = point1 -> y();
- qreal p2_x = point2 -> x();
- qreal p2_y = point2 -> y();
- area.setFillRule(Qt::OddEvenFill);
- area.addRect(p1_x - my_thickness, p1_y - my_thickness, my_thickness * 2.0 + p2_x - p1_x, my_thickness * 2.0 + p2_y - p1_y);
- }
- previous_point = point;
- area.setFillRule(Qt::WindingFill);
- area.addRect(point.x() - my_thickness, point.y() - my_thickness, my_thickness * 2.0, my_thickness * 2.0 );
- }
- return(area);
-}
-
-/**
- @param point un point, exprime dans les coordonnees du conducteur
- @return true si le point est a proximite du conducteur, c-a-d a moins de
- 60px du conducteur.
-*/
-bool Conductor::isNearConductor(const QPointF &point) {
- return(variableShape(60.1).contains(point));
-}
-
-/**
- Renvoie une valeur donnee apres l'avoir bornee entre deux autres valeurs,
- en y ajoutant une marge interne.
- @param tobound valeur a borner
- @param bound1 borne 1
- @param bound2 borne 2
- @param space marge interne ajoutee
- @return La valeur bornee
-*/
-qreal Conductor::conductor_bound(qreal tobound, qreal bound1, qreal bound2, qreal space) {
- qDebug() << "will bound" << tobound << "between" << bound1 << "and" << bound2 ;
- if (bound1 < bound2) {
- return(qBound(bound1 + space, tobound, bound2 - space));
- } else {
- return(qBound(bound2 + space, tobound, bound1 - space));
- }
-}
-
-/**
- Renvoie une valeur donnee apres l'avoir bornee avant ou apres une valeur.
- @param tobound valeur a borner
- @param bound borne
- @param positive true pour borner la valeur avant la borne, false sinon
- @return La valeur bornee
-*/
-qreal Conductor::conductor_bound(qreal tobound, qreal bound, bool positive) {
- qreal space = 5.0;
- return(positive ? qMax(tobound, bound + space) : qMin(tobound, bound - space));
-}
-
-/**
- @param type Type de Segments
- @return Le nombre de segments composant le conducteur.
-*/
-uint Conductor::segmentsCount(QET::ConductorSegmentType type) const {
- QList<ConductorSegment *> segments_list = segmentsList();
- if (type == QET::Both) return(segments_list.count());
- uint nb_seg = 0;
- foreach(ConductorSegment *conductor_segment, segments_list) {
- if (conductor_segment -> type() == type) ++ nb_seg;
- }
- return(nb_seg);
-}
-
-/**
- Genere une liste de points a partir des segments de ce conducteur
- @return La liste de points representant ce conducteur
-*/
-QList<QPointF> Conductor::segmentsToPoints() const {
- // liste qui sera retournee
- QList<QPointF> points_list;
-
- // on retourne la liste tout de suite s'il n'y a pas de segments
- if (segments == NULL) return(points_list);
-
- // recupere le premier point
- points_list << segments -> firstPoint();
-
- // parcourt les segments pour recuperer les autres points
- ConductorSegment *segment = segments;
- while(segment -> hasNextSegment()) {
- points_list << segment -> secondPoint();
- segment = segment -> nextSegment();
- }
-
- // recupere le dernier point
- points_list << segment -> secondPoint();
-
- //retourne la liste
- return(points_list);
-}
-
-/**
- Regenere les segments de ce conducteur a partir de la liste de points passee en parametre
- @param points_list Liste de points a utiliser pour generer les segments
-*/
-void Conductor::pointsToSegments(QList<QPointF> points_list) {
- // supprime les segments actuels
- deleteSegments();
-
- // cree les segments a partir de la liste de points
- ConductorSegment *last_segment = NULL;
- for (int i = 0 ; i < points_list.size() - 1 ; ++ i) {
- last_segment = new ConductorSegment(points_list.at(i), points_list.at(i + 1), last_segment);
- if (!i) segments = last_segment;
- }
-}
-
-/**
- Permet de savoir si un point est tres proche d'un autre. Cela sert surtout
- pour determiner si un clic a ete effectue pres d'un point donne.
- @param press_point Point effectivement clique
- @param point point cliquable
- @return true si l'on peut considerer que le point a ete clique, false sinon
-*/
-bool Conductor::hasClickedOn(QPointF press_point, QPointF point) const {
- return (
- press_point.x() >= point.x() - 5.0 &&\
- press_point.x() < point.x() + 5.0 &&\
- press_point.y() >= point.y() - 5.0 &&\
- press_point.y() < point.y() + 5.0
- );
-}
-
-/**
- Charge les caracteristiques du conducteur depuis un element XML.
- @param e Un element XML
- @return true si le chargement a reussi, false sinon
-*/
-bool Conductor::fromXml(QDomElement &e) {
- // recupere la "configuration" du conducteur
- properties_.fromXml(e);
- readProperties();
- qreal user_pos_x, user_pos_y;
- if (
- QET::attributeIsAReal(e, "userx", &user_pos_x) &&
- QET::attributeIsAReal(e, "usery", &user_pos_y)
- ) {
- text_item -> forceMovedByUser(true);
- text_item -> setPos(user_pos_x, user_pos_y);
- }
- if (e.hasAttribute("rotation")) {
- text_item -> setRotationAngle(e.attribute("rotation").toDouble());
- text_item -> forceRotateByUser(true);
- }
-
- // parcourt les elements XML "segment" et en extrait deux listes de longueurs
- // les segments non valides sont ignores
- QList<qreal> segments_x, segments_y;
- for (QDomNode node = e.firstChild() ; !node.isNull() ; node = node.nextSibling()) {
- // on s'interesse aux elements XML "segment"
- QDomElement current_segment = node.toElement();
- if (current_segment.isNull() || current_segment.tagName() != "segment") continue;
-
- // le segment doit avoir une longueur
- if (!current_segment.hasAttribute("length")) continue;
-
- // cette longueur doit etre un reel
- bool ok;
- qreal segment_length = current_segment.attribute("length").toDouble(&ok);
- if (!ok) continue;
-
- if (current_segment.attribute("orientation") == "horizontal") {
- segments_x << segment_length;
- segments_y << 0.0;
- } else {
- segments_x << 0.0;
- segments_y << segment_length;
- }
- }
-
- // s'il n'y a pas de segments, on renvoie true
- if (!segments_x.size()) return(true);
- // les longueurs recueillies doivent etre coherentes avec les positions des bornes
- qreal width = 0.0, height = 0.0;
- foreach (qreal t, segments_x) width += t;
- foreach (qreal t, segments_y) height += t;
- QPointF t1 = terminal1 -> dockConductor();
- QPointF t2 = terminal2 -> dockConductor();
- qreal expected_width = t2.x() - t1.x();
- qreal expected_height = t2.y() - t1.y();
-
- // on considere que le trajet est incoherent a partir d'une unite de difference avec l'espacement entre les bornes
- if (
- qAbs(expected_width - width) > 1.0 ||
- qAbs(expected_height - height) > 1.0
- ) {
- qDebug() << "Conductor::fromXml : les segments du conducteur ne semblent pas coherents - utilisation d'un trajet automatique";
- return(false);
- }
-
- /* on recree les segments a partir des donnes XML */
- // cree la liste de points
- QList<QPointF> points_list;
- points_list << t1;
- for (int i = 0 ; i < segments_x.size() ; ++ i) {
- points_list << QPointF(
- points_list.last().x() + segments_x.at(i),
- points_list.last().y() + segments_y.at(i)
- );
- }
-
- pointsToSegments(points_list);
-
- // initialise divers parametres lies a la modification des conducteurs
- modified_path = true;
- saveProfile(false);
-
- segmentsToPath();
- return(true);
-}
-
-/**
- Exporte les caracteristiques du conducteur sous forme d'une element XML.
- @param d Le document XML a utiliser pour creer l'element XML
- @param table_adr_id Hash stockant les correspondances entre les ids des
- bornes dans le document XML et leur adresse en memoire
- @return Un element XML representant le conducteur
-*/
-QDomElement Conductor::toXml(QDomDocument &d, QHash<Terminal *, int> &table_adr_id) const {
- QDomElement e = d.createElement("conductor");
- e.setAttribute("terminal1", table_adr_id.value(terminal1));
- e.setAttribute("terminal2", table_adr_id.value(terminal2));
-
- // on n'exporte les segments du conducteur que si ceux-ci ont
- // ete modifies par l'utilisateur
- if (modified_path) {
- // parcours et export des segments
- QDomElement current_segment;
- foreach(ConductorSegment *segment, segmentsList()) {
- current_segment = d.createElement("segment");
- current_segment.setAttribute("orientation", segment -> isHorizontal() ? "horizontal" : "vertical");
- current_segment.setAttribute("length", QString("%1").arg(segment -> length()));
- e.appendChild(current_segment);
- }
- }
-
- // exporte la "configuration" du conducteur
- properties_.toXml(e);
- if (text_item -> wasRotateByUser()) {
- e.setAttribute("rotation", QString("%1").arg(text_item -> rotationAngle()));
- }
- if (text_item -> wasMovedByUser()) {
- e.setAttribute("userx", QString("%1").arg(text_item -> pos().x()));
- e.setAttribute("usery", QString("%1").arg(text_item -> pos().y()));
- }
- return(e);
-}
-
-/// @return les segments de ce conducteur
-const QList<ConductorSegment *> Conductor::segmentsList() const {
- if (segments == NULL) return(QList<ConductorSegment *>());
-
- QList<ConductorSegment *> segments_vector;
- ConductorSegment *segment = segments;
-
- while (segment -> hasNextSegment()) {
- segments_vector << segment;
- segment = segment -> nextSegment();
- }
- segments_vector << segment;
- return(segments_vector);
-}
-
-/**
- @return La longueur totale du conducteur
-*/
-qreal Conductor::length() {
- qreal length = 0.0;
-
- ConductorSegment *s = segments;
- while (s -> hasNextSegment()) {
- length += qAbs(s -> length());
- s = s -> nextSegment();
- }
-
- return(length);
-}
-
-/**
- @return Le segment qui contient le point au milieu du conducteur
-*/
-ConductorSegment *Conductor::middleSegment() {
- if (segments == NULL) return(NULL);
-
- qreal half_length = length() / 2.0;
-
- ConductorSegment *s = segments;
- qreal l = 0;
-
- while (s -> hasNextSegment()) {
- l += qAbs(s -> length());
- if (l >= half_length) break;
- s = s -> nextSegment();
- }
- // s est le segment qui contient le point au milieu du conducteur
- return(s);
-}
-
-/**
- Positionne le texte du conducteur au milieu du segment qui contient le
- point au milieu du conducteur
- @see middleSegment()
-*/
-void Conductor::calculateTextItemPosition() {
- if (!text_item) return;
-
- //position
- if (text_item -> wasMovedByUser()) {
- // le champ de texte a ete deplace par l'utilisateur :
- // on verifie qu'il est encore a proximite du conducteur
- QPointF text_item_pos = text_item -> pos();
- QPainterPath near_shape = nearShape();
- if (!near_shape.contains(text_item_pos)) {
- text_item -> setPos(movePointIntoPolygon(text_item_pos, near_shape));
- }
- } else {
- // positionnement automatique basique
- text_item -> setPos(middleSegment() -> middle());
- //rotation
- if (!text_item -> wasRotateByUser()) {
- middleSegment() -> isVertical()? text_item -> setRotationAngle(properties_.verti_rotate_text):
- text_item -> setRotationAngle(properties_.horiz_rotate_text);
- }
- }
-}
-
-/**
- Sauvegarde le profil courant du conducteur pour l'utiliser ulterieurement
- dans priv_modifieConductor.
-*/
-void Conductor::saveProfile(bool undo) {
- Qt::Corner current_path_type = currentPathType();
- ConductorProfile old_profile(conductor_profiles[current_path_type]);
- conductor_profiles[current_path_type].fromConductor(this);
- Diagram *dia = diagram();
- if (undo && dia) {
- ChangeConductorCommand *undo_object = new ChangeConductorCommand(
- this,
- old_profile,
- conductor_profiles[current_path_type],
- current_path_type
- );
- undo_object -> setConductorTextItemMove(before_mov_text_pos_, text_item -> pos());
- dia -> undoStack().push(undo_object);
- }
-}
-
-/**
- @param value1 Premiere valeur
- @param value2 Deuxieme valeur
- @return 1 si les deux valeurs sont de meme signe, -1 sinon
-*/
-int Conductor::getCoeff(const qreal &value1, const qreal &value2) {
- return(getSign(value1) * getSign(value2));
-}
-
-/**
- @param value valeur
- @return 1 si valeur est negatif, 1 s'il est positif ou nul
-*/
-int Conductor::getSign(const qreal &value) {
- return(value < 0 ? -1 : 1);
-}
-
-/**
- Applique un nouveau profil a ce conducteur
- @param cp Profil a appliquer a ce conducteur
- @param path_type Type de trajet pour lequel ce profil convient
-*/
-void Conductor::setProfile(const ConductorProfile &cp, Qt::Corner path_type) {
- conductor_profiles[path_type] = cp;
- // si le type de trajet correspond a l'actuel
- if (currentPathType() == path_type) {
- if (conductor_profiles[path_type].isNull()) {
- generateConductorPath(terminal1 -> dockConductor(), terminal1 -> orientation(), terminal2 -> dockConductor(), terminal2 -> orientation());
- modified_path = false;
- } else {
- updateConductorPath(terminal1 -> dockConductor(), terminal1 -> orientation(), terminal2 -> dockConductor(), terminal2 -> orientation());
- modified_path = true;
- }
- if (type() == ConductorProperties::Multi) {
- calculateTextItemPosition();
- }
- }
-}
-
-/// @return le profil de ce conducteur
-ConductorProfile Conductor::profile(Qt::Corner path_type) const {
- return(conductor_profiles[path_type]);
-}
-
-/// @return le texte du conducteur
-QString Conductor::text() const {
- return(text_item -> toPlainText());
-}
-
-/**
- @param t Nouveau texte du conducteur
-*/
-void Conductor::setText(const QString &t) {
- text_item -> setPlainText(t);
-}
-
-/// @param p les proprietes de ce conducteur
-void Conductor::setProperties(const ConductorProperties &p) {
- properties_ = p;
- readProperties();
-}
-
-/// @return les proprietes de ce conducteur
-ConductorProperties Conductor::properties() const {
- return(properties_);
-}
-
-/**
- Relit les proprietes et les applique
-*/
-void Conductor::readProperties() {
- // la couleur n'est vraiment applicable que lors du rendu du conducteur
- setText(properties_.text);
- calculateTextItemPosition();
- text_item -> setVisible(properties_.type == ConductorProperties::Multi);
-}
-
-/**
- S'assure que le texte du conducteur est a une position raisonnable
- Cette methode ne fait rien si ce conducteur n'affiche pas son champ de
- texte.
-*/
-void Conductor::adjustTextItemPosition() {
- calculateTextItemPosition();
-}
-
-/**
- @return true si le conducteur est mis en evidence
-*/
-Conductor::Highlight Conductor::highlight() const {
- return(must_highlight_);
-}
-
-/**
- @param hl true pour mettre le conducteur en evidence, false sinon
-*/
-void Conductor::setHighlighted(Conductor::Highlight hl) {
- must_highlight_ = hl;
- update();
-}
-
-/**
- * @brief Conductor::autoText
- *lance l'autoNumerotation sur ce conducteur
- */
-void Conductor::autoText() {
- ConductorAutoNumerotation can(this);
- can.numerate();
-}
-
-/**
- Met a jour les proprietes du conducteur apres modification du champ de texte affiche
-*/
-void Conductor::displayedTextChanged() {
- // verifie que le texte a reellement change
- if (text_item -> toPlainText() == properties_.text) return;
-
- if (Diagram *my_diagram = diagram()) {
- int qmbreturn=0;
- //if conductor isn't alone at this potential
- //ask user to apply text on every conductors of this potential
- if (relatedPotentialConductors().size() >= 1){
- qmbreturn = QMessageBox::question(diagramEditor(), tr("Textes de conducteurs"),
- tr("Voulez-vous appliquer le nouveau texte \n"
- "\340 l'ensemble des conducteurs de ce potentiel ?"),
- QMessageBox::No| QMessageBox::Yes, QMessageBox::Yes);
- if (qmbreturn == QMessageBox::Yes){
- ConductorAutoNumerotation can(this);
- can.applyText(text_item -> toPlainText());
- }
- }
- if (qmbreturn == 0 || qmbreturn == QMessageBox::No) {
- // initialise l'objet UndoCommand correspondant
- ConductorProperties new_properties(properties_);
- new_properties.text = text_item -> toPlainText();
-
- ChangeConductorPropertiesCommand *ccpc = new ChangeConductorPropertiesCommand(this);
- ccpc -> setOldSettings(properties_);
- ccpc -> setNewSettings(new_properties);
- my_diagram -> undoStack().push(ccpc);
- }
- }
-}
-
-/**
- @return les conducteurs avec lesquels ce conducteur partage des bornes
- communes
-*/
-QSet<Conductor *> Conductor::relatedConductors() const {
- QList<Conductor *> other_conductors_list = terminal1 -> conductors();
- other_conductors_list += terminal2 -> conductors();
- QSet<Conductor *> other_conductors = other_conductors_list.toSet();
- other_conductors.remove(const_cast<Conductor *>(this));
- return(other_conductors);
-}
-
-/**
- * @param t_list terminaux a ne pas inclure dans la recherche
- * @return les conducteurs avec lesquels ce conducteur partage
- * le meme potentiel electrique a l'exception de lui même
- */
-QSet<Conductor *> Conductor::relatedPotentialConductors(QList <Terminal *> *t_list) {
- bool declar_t_list = false;
- if (t_list == 0) {
- declar_t_list = true;
- t_list = new QList <Terminal *>;
- }
-
- QSet <Conductor *> other_conductors;
- //renvoie tous les conducteurs du terminal 1
- if (!t_list -> contains(terminal1)) {
- t_list -> append(terminal1);
- QList <Conductor *> other_conductors_list_t1 = terminal1 -> conductors();
- other_conductors_list_t1.removeAll(this);
- //recherche les conducteurs connecté au conducteur déjà trouvé
- foreach (Conductor *c, other_conductors_list_t1) {
- other_conductors += c -> relatedPotentialConductors(t_list);
- }
- other_conductors += other_conductors_list_t1.toSet();
- }
- //renvoie tous les conducteurs du terminal 2
- if (!t_list -> contains(terminal2)) {
- t_list -> append(terminal2);
- QList <Conductor *> other_conductors_list_t2 = terminal2 -> conductors();
- other_conductors_list_t2.removeAll(this);
- //recherche les conducteurs connecté au conducteur déjà trouvé
- foreach (Conductor *c, other_conductors_list_t2) {
- other_conductors += c -> relatedPotentialConductors(t_list);
- }
- other_conductors += other_conductors_list_t2.toSet();
- }
- other_conductors.remove(const_cast<Conductor *>(this));
-
- if (declar_t_list) delete t_list;
- return(other_conductors);
-}
-
-/**
- * @return l'editeur de schemas parent ou 0
- */
-QETDiagramEditor* Conductor::diagramEditor() const {
- QWidget *w = const_cast<QGraphicsView *>(diagram() -> views().at(0));
- while (w -> parentWidget() && !w -> isWindow()) {
- w = w -> parentWidget();
- }
- return(qobject_cast<QETDiagramEditor *>(w));
-}
-
-/**
- @param a reel
- @param b reel
- @param c reel
- @return true si a est entre b et c ou est egal a l'un des deux
-*/
-bool isBetween(qreal a, qreal b, qreal c) {
- if (b <= c) {
- return(a >= b && a <= c);
- } else {
- return(a <= b && a >= c);
- }
-}
-
-/**
- @param a point
- @param b point
- @param c point
- @return true si le point a est contenu dans le rectangle delimite par les points b et c
-*/
-bool isContained(const QPointF &a, const QPointF &b, const QPointF &c) {
- return(
- isBetween(a.x(), b.x(), c.x()) &&
- isBetween(a.y(), b.y(), c.y())
- );
-}
-
-/**
- @return la liste des positions des jonctions avec d'autres conducteurs
-*/
-QList<QPointF> Conductor::junctions() const {
- QList<QPointF> junctions_list;
-
- // pour qu'il y ait des jonctions, il doit y avoir d'autres conducteurs et des bifurcations
- QSet<Conductor *> other_conductors = relatedConductors();
- QList<ConductorBend> bends_list = bends();
- if (other_conductors.isEmpty() || bends_list.isEmpty()) {
- return(junctions_list);
- }
-
- QList<QPointF> points = segmentsToPoints();
- for (int i = 1 ; i < (points.size() -1) ; ++ i) {
- QPointF point = points.at(i);
-
- // determine si le point est une bifurcation ou non
- bool is_bend = false;
- Qt::Corner current_bend_type = Qt::TopLeftCorner;
- foreach(ConductorBend cb, bends_list) {
- if (cb.first == point) {
- is_bend = true;
- current_bend_type = cb.second;
- break;
- }
- }
- // si le point n'est pas une bifurcation, il ne peut etre une jonction (enfin pas au niveau de ce conducteur)
- if (!is_bend) continue;
-
- bool is_junction = false;
- QPointF scene_point = mapToScene(point);
- foreach(Conductor *c, other_conductors) {
- // exprime le point dans les coordonnees de l'autre conducteur
- QPointF conductor_point = c -> mapFromScene(scene_point);
- // recupere les segments de l'autre conducteur
- QList<ConductorSegment *> c_segments = c -> segmentsList();
- if (c_segments.isEmpty()) continue;
- // parcoure les segments a la recherche d'un point commun
- for (int j = 0 ; j < c_segments.count() ; ++ j) {
- ConductorSegment *segment = c_segments[j];
- // un point commun a ete trouve sur ce segment
- if (isContained(conductor_point, segment -> firstPoint(), segment -> secondPoint())) {
- is_junction = true;
- // ce point commun ne doit pas etre une bifurcation identique a celle-ci
- QList<ConductorBend> other_conductor_bends = c -> bends();
- foreach(ConductorBend cb, other_conductor_bends) {
- if (cb.first == conductor_point && cb.second == current_bend_type) {
- is_junction = false;
- }
- }
- }
- if (is_junction) junctions_list << point;
- }
- }
- }
- return(junctions_list);
-}
-
-/**
- @return la liste des bifurcations de ce conducteur ; ConductorBend est un
- typedef pour une QPair\<QPointF, Qt::Corner\>. Le point indique la position
- (en coordonnees locales) de la bifurcation tandis que le Corner indique le
- type de bifurcation.
-*/
-QList<ConductorBend> Conductor::bends() const {
- QList<ConductorBend> points;
- if (!segments) return(points);
-
- // recupere la liste des segments de taille non nulle
- QList<ConductorSegment *> visible_segments;
- ConductorSegment *segment = segments;
- while (segment -> hasNextSegment()) {
- if (!segment -> isPoint()) visible_segments << segment;
- segment = segment -> nextSegment();
- }
- if (!segment -> isPoint()) visible_segments << segment;
-
- ConductorSegment *next_segment;
- for (int i = 0 ; i < visible_segments.count() -1 ; ++ i) {
- segment = visible_segments[i];
- next_segment = visible_segments[i + 1];
- if (!segment -> isPoint() && !next_segment -> isPoint()) {
- // si les deux segments ne sont pas dans le meme sens, on a une bifurcation
- if (next_segment -> type() != segment -> type()) {
- Qt::Corner bend_type;
- qreal sl = segment -> length();
- qreal nsl = next_segment -> length();
-
- if (segment -> isHorizontal()) {
- if (sl < 0 && nsl < 0) {
- bend_type = Qt::BottomLeftCorner;
- } else if (sl < 0 && nsl > 0) {
- bend_type = Qt::TopLeftCorner;
- } else if (sl > 0 && nsl < 0) {
- bend_type = Qt::BottomRightCorner;
- } else {
- bend_type = Qt::TopRightCorner;
- }
- } else {
- if (sl < 0 && nsl < 0) {
- bend_type = Qt::TopRightCorner;
- } else if (sl < 0 && nsl > 0) {
- bend_type = Qt::TopLeftCorner;
- } else if (sl > 0 && nsl < 0) {
- bend_type = Qt::BottomRightCorner;
- } else {
- bend_type = Qt::BottomLeftCorner;
- }
- }
- points << qMakePair(segment -> secondPoint(), bend_type);
- }
- }
- }
- return(points);
-}
-
-/**
- @param p Point, en coordonnees locales
- @return true si le point p appartient au trajet du conducteur
-*/
-bool Conductor::containsPoint(const QPointF &p) const {
- if (!segments) return(false);
- ConductorSegment *segment = segments;
- while (segment -> hasNextSegment()) {
- QRectF rect(segment -> firstPoint(), segment -> secondPoint());
- if (rect.contains(p)) return(true);
- segment = segment -> nextSegment();
- }
- return(false);
-}
-
-/**
- @param start Point de depart
- @param end Point d'arrivee
- @return le coin vers lequel se dirige le trajet de start vers end
-*/
-Qt::Corner Conductor::movementType(const QPointF &start, const QPointF &end) {
- Qt::Corner result = Qt::BottomRightCorner;
- if (start.x() <= end.x()) {
- result = start.y() <= end.y() ? Qt::BottomRightCorner : Qt::TopRightCorner;
- } else {
- result = start.y() <= end.y() ? Qt::BottomLeftCorner : Qt::TopLeftCorner;
- }
- return(result);
-}
-
-/// @return le type de trajet actuel de ce conducteur
-Qt::Corner Conductor::currentPathType() const {
- return(movementType(terminal1 -> dockConductor(), terminal2 -> dockConductor()));
-}
-
-/// @return les profils de ce conducteur
-ConductorProfilesGroup Conductor::profiles() const {
- return(conductor_profiles);
-}
-
-/**
- @param cpg Les nouveaux profils de ce conducteur
-*/
-void Conductor::setProfiles(const ConductorProfilesGroup &cpg) {
- conductor_profiles = cpg;
- if (conductor_profiles[currentPathType()].isNull()) {
- generateConductorPath(terminal1 -> dockConductor(), terminal1 -> orientation(), terminal2 -> dockConductor(), terminal2 -> orientation());
- modified_path = false;
- } else {
- updateConductorPath(terminal1 -> dockConductor(), terminal1 -> orientation(), terminal2 -> dockConductor(), terminal2 -> orientation());
- modified_path = true;
- }
- if (type() == ConductorProperties::Multi) {
- calculateTextItemPosition();
- }
-}
-
-/// Supprime les segments
-void Conductor::deleteSegments() {
- if (segments != NULL) {
- while (segments -> hasNextSegment()) delete segments -> nextSegment();
- delete segments;
- segments = NULL;
- }
-}
-
-/**
- @param point Un point situe a l'exterieur du polygone
- @param polygon Le polygone dans lequel on veut rapatrier le point
- @return la position du point, une fois ramene dans le polygone, ou plus
- exactement sur le bord du polygone
-*/
-QPointF Conductor::movePointIntoPolygon(const QPointF &point, const QPainterPath &polygon) {
- // decompose le polygone en lignes et points
- QList<QPolygonF> polygons = polygon.simplified().toSubpathPolygons();
- QList<QLineF> lines;
- QList<QPointF> points;
- foreach(QPolygonF polygon, polygons) {
- if (polygon.count() <= 1) continue;
-
- // on recense les lignes et les points
- for (int i = 1 ; i < polygon.count() ; ++ i) {
- lines << QLineF(polygon.at(i - 1), polygon.at(i));
- points << polygon.at(i -1);
- }
- }
-
- // on fait des projetes orthogonaux du point sur les differents segments du
- // polygone, en les triant par longueur croissante
- QMap<qreal, QPointF> intersections;
- foreach (QLineF line, lines) {
- QPointF intersection_point;
- if (QET::orthogonalProjection(point, line, &intersection_point)) {
- intersections.insert(QLineF(intersection_point, point).length(), intersection_point);
- }
- }
- if (intersections.count()) {
- // on determine la plus courte longueur pour un projete orthogonal
- QPointF the_point = intersections[intersections.keys().first()];
- return(the_point);
- } else {
- // determine le coin du polygone le plus proche du point exterieur
- qreal minimum_length = -1;
- int point_index = -1;
- for (int i = 0 ; i < points.count() ; ++ i) {
- qreal length = qAbs(QLineF(points.at(i), point).length());
- if (minimum_length < 0 || length < minimum_length) {
- minimum_length = length;
- point_index = i;
- }
- }
- // on connait desormais le coin le plus proche du texte
-
- // aucun projete orthogonal n'a donne quoi que ce soit, on met le texte sur un des coins du polygone
- return(points.at(point_index));
- }
-}
Deleted: branches/devel/sources/conductor.h
===================================================================
--- branches/devel/sources/conductor.h 2013-11-06 18:44:39 UTC (rev 2595)
+++ branches/devel/sources/conductor.h 2013-11-07 09:18:03 UTC (rev 2596)
@@ -1,170 +0,0 @@
-/*
- Copyright 2006-2013 The QElectroTech Team
- 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/>.
-*/
-#ifndef CONDUCTOR_H
-#define CONDUCTOR_H
-#include <QtGui>
-#include "terminal.h"
-#include "conductorprofile.h"
-#include "conductorproperties.h"
-#include "qetdiagrameditor.h"
-class ConductorSegment;
-class ConductorTextItem;
-class Element;
-typedef QPair<QPointF, Qt::Corner> ConductorBend;
-typedef QHash<Qt::Corner, ConductorProfile> ConductorProfilesGroup;
-/**
- This class represents a conductor, i.e. a wire between two element
- terminals.
-*/
-class Conductor : public QObject, public QGraphicsPathItem {
-
- Q_OBJECT
-
- // constructors, destructor
- public:
- Conductor(Terminal *, Terminal *, Diagram * = 0);
- virtual ~Conductor();
-
- private:
- Conductor(const Conductor &);
-
- // attributes
- public:
- enum { Type = UserType + 1001 };
- enum Highlight { None, Normal, Alert };
-
- /// First terminal the wire is attached to
- Terminal *terminal1;
- /// Second terminal the wire is attached to
- Terminal *terminal2;
-
- // methods
- public:
- /**
- Enable the use of qgraphicsitem_cast to safely cast a QGraphicsItem into a
- Conductor.
- @return the QGraphicsItem type
- */
- virtual int type() const { return Type; }
- void destroy();
- /// @return true if this conductor is destroyed
- bool isDestroyed() const { return(destroyed_); }
- Diagram *diagram() const;
- ConductorTextItem *textItem() const;
- void updatePath(const QRectF & = QRectF());
- void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *);
- QRectF boundingRect() const;
- virtual QPainterPath shape() const;
- virtual qreal nearDistance() const;
- virtual QPainterPath nearShape() const;
- virtual QPainterPath variableShape(const qreal &) const;
- virtual bool isNearConductor(const QPointF &);
- qreal length();
- ConductorSegment *middleSegment();
- bool containsPoint(const QPointF &) const;
- QString text() const;
- void setText(const QString &);
- static bool valideXml(QDomElement &);
- bool fromXml(QDomElement &);
- QDomElement toXml(QDomDocument &, QHash<Terminal *, int> &) const;
- const QList<ConductorSegment *> segmentsList() const;
- void setProperties(const ConductorProperties &);
- ConductorProperties properties() const;
- void setProfile(const ConductorProfile &, Qt::Corner);
- ConductorProfile profile(Qt::Corner) const;
- void setProfiles(const ConductorProfilesGroup &);
- ConductorProfilesGroup profiles() const;
- void readProperties();
- void adjustTextItemPosition();
- virtual Highlight highlight() const;
- virtual void setHighlighted(Highlight);
- void autoText();
- QSet<Conductor *> relatedPotentialConductors(QList <Terminal *> *t_list=0);
- QETDiagramEditor* diagramEditor() const;
-
- public slots:
- void displayedTextChanged();
-
- protected:
- virtual void mousePressEvent(QGraphicsSceneMouseEvent *);
- virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *);
- virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *);
- virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *);
- virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent *);
- virtual void hoverMoveEvent(QGraphicsSceneHoverEvent *);
- virtual QVariant itemChange(GraphicsItemChange, const QVariant &);
-
- private:
- /// Functional properties
- ConductorProperties properties_;
- /// Whether this conductor is still valid
- bool destroyed_;
- /// Text input for non simple, non-singleline conductors
- ConductorTextItem *text_item;
- /// Segments composing the conductor
- ConductorSegment *segments;
- /// Attributs related to mouse interaction
- QPointF press_point;
- bool moving_point;
- bool moving_segment;
- int moved_point;
- qreal previous_z_value;
- ConductorSegment *moved_segment;
- QPointF before_mov_text_pos_;
- /// Whether the conductor was manually modified by users
- bool modified_path;
- /// Whether the current profile should be saved as soon as possible
- bool has_to_save_profile;
- /// conductor profile: "photography" of what the conductor is supposed to look
- /// like - there is one profile per kind of traject
- ConductorProfilesGroup conductor_profiles;
- /// QPen et QBrush objects used to draw conductors
- static QPen conductor_pen;
- static QBrush conductor_brush;
- static QBrush square_brush;
- static bool pen_and_brush_initialized;
- /// Scale factor to render square used to move segments
- qreal segments_squares_scale_;
- /// Define whether and how the conductor should be highlighted
- Highlight must_highlight_;
-
- private:
- void segmentsToPath();
- void saveProfile(bool = true);
- void generateConductorPath(const QPointF &, QET::Orientation, const QPointF &, QET::Orientation);
- void updateConductorPath(const QPointF &, QET::Orientation, const QPointF &, QET::Orientation);
- uint segmentsCount(QET::ConductorSegmentType = QET::Both) const;
- QList<QPointF> segmentsToPoints() const;
- QSet<Conductor *> relatedConductors() const;
- QList<ConductorBend> bends() const;
- QList<QPointF> junctions() const;
- void pointsToSegments(QList<QPointF>);
- bool hasClickedOn(QPointF, QPointF) const;
- void calculateTextItemPosition();
- Qt::Corner currentPathType() const;
- void deleteSegments();
- static int getCoeff(const qreal &, const qreal &);
- static int getSign(const qreal &);
- QHash<ConductorSegmentProfile *, qreal> shareOffsetBetweenSegments(const qreal &offset, const QList<ConductorSegmentProfile *> &, const qreal & = 0.01) const;
- static QPointF extendTerminal(const QPointF &, QET::Orientation, qreal = 9.0);
- static qreal conductor_bound(qreal, qreal, qreal, qreal = 0.0);
- static qreal conductor_bound(qreal, qreal, bool);
- static Qt::Corner movementType(const QPointF &, const QPointF &);
- static QPointF movePointIntoPolygon(const QPointF &, const QPainterPath &);
-};
-#endif
Modified: branches/devel/sources/conductorautonumerotation.h
===================================================================
--- branches/devel/sources/conductorautonumerotation.h 2013-11-06 18:44:39 UTC (rev 2595)
+++ branches/devel/sources/conductorautonumerotation.h 2013-11-07 09:18:03 UTC (rev 2596)
@@ -18,7 +18,7 @@
#ifndef CONDUCTORAUTONUMEROTATION_H
#define CONDUCTORAUTONUMEROTATION_H
-#include "conductor.h"
+#include "qetgraphicsitem/conductor.h"
#include "numerotationcontext.h"
#include "autonumerotation.h"
Modified: branches/devel/sources/conductorautonumerotationwidget.h
===================================================================
--- branches/devel/sources/conductorautonumerotationwidget.h 2013-11-06 18:44:39 UTC (rev 2595)
+++ branches/devel/sources/conductorautonumerotationwidget.h 2013-11-07 09:18:03 UTC (rev 2596)
@@ -6,7 +6,7 @@
#include <QSet>
#include <QMultiMap>
#include <QString>
-#include "conductor.h"
+#include "qetgraphicsitem/conductor.h"
#include "diagram.h"
class ConductorAutoNumerotationWidget : public QDialog
Modified: branches/devel/sources/conductorprofile.cpp
===================================================================
--- branches/devel/sources/conductorprofile.cpp 2013-11-06 18:44:39 UTC (rev 2595)
+++ branches/devel/sources/conductorprofile.cpp 2013-11-07 09:18:03 UTC (rev 2596)
@@ -16,7 +16,7 @@
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
*/
#include "conductorprofile.h"
-#include "conductor.h"
+#include "qetgraphicsitem/conductor.h"
#include "conductorsegmentprofile.h"
/// Constructeur
Modified: branches/devel/sources/conductorpropertieswidget.cpp
===================================================================
--- branches/devel/sources/conductorpropertieswidget.cpp 2013-11-06 18:44:39 UTC (rev 2595)
+++ branches/devel/sources/conductorpropertieswidget.cpp 2013-11-07 09:18:03 UTC (rev 2596)
@@ -17,7 +17,7 @@
*/
#include "conductorpropertieswidget.h"
#include <QtGui>
-#include "conductor.h"
+#include "qetgraphicsitem/conductor.h"
#include "qeticons.h"
#include "qetapp.h"
Deleted: branches/devel/sources/conductortextitem.cpp
===================================================================
--- branches/devel/sources/conductortextitem.cpp 2013-11-06 18:44:39 UTC (rev 2595)
+++ branches/devel/sources/conductortextitem.cpp 2013-11-07 09:18:03 UTC (rev 2596)
@@ -1,223 +0,0 @@
-/*
- Copyright 2006-2013 The QElectroTech Team
- 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/>.
-*/
-#include "conductortextitem.h"
-#include "conductor.h"
-#include "diagramcommands.h"
-
-/**
- Constructeur
- @param parent_conductor Conducteur auquel ce texte est rattache
- @param parent_diagram Schema auquel ce texte et son conducteur parent sont rattaches
-*/
-ConductorTextItem::ConductorTextItem(Conductor *parent_conductor, Diagram *parent_diagram) :
- DiagramTextItem(parent_conductor, parent_diagram),
- parent_conductor_(parent_conductor),
- moved_by_user_(false),
- rotate_by_user_(false),
- first_move_(true)
-{
- // par defaut, les DiagramTextItem sont Selectable et Movable
- // cela nous convient, on ne touche pas a ces flags
-}
-
-/**
- Constructeur
- @param text Le texte affiche par le champ de texte
- @param parent_conductor Conducteur auquel ce texte est rattache
- @param parent_diagram Schema auquel ce texte et son conducteur parent sont rattaches
-*/
-ConductorTextItem::ConductorTextItem(const QString &text, Conductor *parent_conductor, Diagram *parent_diagram) :
- DiagramTextItem(text, parent_conductor, parent_diagram),
- parent_conductor_(parent_conductor),
- moved_by_user_(false),
- rotate_by_user_(false),
- first_move_(true)
-{
- // par defaut, les DiagramTextItem sont Selectable et Movable
- // cela nous convient, on ne touche pas a ces flags
-}
-
-/**
- Destructeur
-*/
-ConductorTextItem::~ConductorTextItem() {
-}
-
-/**
- @return le conducteur parent de ce champ de texte, ou 0 si celui-ci n'en a
- pas
-*/
-Conductor *ConductorTextItem::parentConductor() const {
- return(parent_conductor_);
-}
-
-/**
- Permet de lire le texte a mettre dans le champ a partir d'un element XML.
- Cette methode se base sur la position du champ pour assigner ou non la
- valeur a ce champ.
- @param e L'element XML representant le champ de texte
-*/
-void ConductorTextItem::fromXml(const QDomElement &e) {
- setPlainText(e.attribute("text"));
-
- qreal user_pos_x, user_pos_y;
- if (
- QET::attributeIsAReal(e, "userx", &user_pos_x) &&
- QET::attributeIsAReal(e, "usery", &user_pos_y)
- ) {
- setPos(user_pos_x, user_pos_y);
- }
-
- setRotationAngle(e.attribute("rotation").toDouble());
-}
-
-/**
- @param document Le document XML a utiliser
- @return L'element XML representant ce champ de texte
-*/
-QDomElement ConductorTextItem::toXml(QDomDocument &document) const {
- QDomElement result = document.createElement("input");
- result.setAttribute("userx", QString("%1").arg(pos().x()));
- result.setAttribute("usery", QString("%1").arg(pos().y()));
- result.setAttribute("text", toPlainText());
- if (rotationAngle()) {
- result.setAttribute("rotation", QString("%1").arg(rotationAngle()));
- }
- return(result);
-}
-
-/**
- @return true si ce champ de texte a ete explictement deplace par
- l'utilisateur, false sinon
-*/
-bool ConductorTextItem::wasMovedByUser() const {
- return(moved_by_user_);
-}
-
-/**
- * @brief ConductorTextItem::wasRotateByUser
- * @return true if text was explicit moved by user else false
- */
-bool ConductorTextItem::wasRotateByUser() const {
- return(rotate_by_user_);
-}
-
-/**
- @param moved_by_user true pour que la position du texte soit consideree
- comme ayant ete definie par l'utilisateur (et donc soit sauvegardee), false
- pour remettre le texte a sa position originelle
-*/
-void ConductorTextItem::forceMovedByUser(bool moved_by_user) {
- if (moved_by_user == moved_by_user_) return;
-
- moved_by_user_ = moved_by_user;
- if (!moved_by_user && parent_conductor_) {
- parent_conductor_ -> adjustTextItemPosition();
- }
-
-}
-
-/**
- * @brief ConductorTextItem::forceRotateByUser
- * @param rotate_by_user true pour que la rotation du texte soit consideree
- comme ayant ete definie par l'utilisateur (et donc soit sauvegardee), false
- pour remettre le texte a sont angle originelle
- */
-void ConductorTextItem::forceRotateByUser(bool rotate_by_user) {
- if (rotate_by_user == rotate_by_user_) return;
-
- rotate_by_user_ = rotate_by_user;
- if (!rotate_by_user && parent_conductor_) {
- parent_conductor_ -> adjustTextItemPosition();
- }
-}
-
-/**
- Gere les clics de souris lies au champ de texte
- @param e Objet decrivant l'evenement souris
-*/
-void ConductorTextItem::mousePressEvent(QGraphicsSceneMouseEvent *e) {
- if ((flags() & QGraphicsItem::ItemIsMovable) && (e -> buttons() & Qt::LeftButton)) {
- before_mov_pos_ = pos();
- }
- first_move_ = true;
- DiagramTextItem::mousePressEvent(e);
-}
-
-/**
- Gere les mouvements de souris lies au champ de texte
- @param e Objet decrivant l'evenement souris
-*/
-void ConductorTextItem::mouseMoveEvent(QGraphicsSceneMouseEvent *e) {
- if (textInteractionFlags() & Qt::TextEditable) {
- QGraphicsTextItem::mouseMoveEvent(e);
- } else if ((flags() & QGraphicsItem::ItemIsMovable) && (e -> buttons() & Qt::LeftButton)) {
- if (first_move_) {
- mouse_to_origin_movement_ = before_mov_pos_ - mapToParent(e -> buttonDownPos(Qt::LeftButton));
- }
-
- QPointF intended_pos = mapToParent(e -> pos()) + mouse_to_origin_movement_;
- // si ce texte est attache a un conducteur, alors ses mouvements seront
- // limites a une certaine distance du trace de ce conducteur
- if (parent_conductor_) {
- if (parent_conductor_ -> isNearConductor(intended_pos)) {
- setPos(intended_pos);
- parent_conductor_ -> setHighlighted(Conductor::Normal);
- } else {
- parent_conductor_ -> setHighlighted(Conductor::Alert);
- }
- }
-
- } else e -> ignore();
-
- if (first_move_) {
- first_move_ = false;
- }
-}
-
-/**
- Gere le relachement de souris
- Cette methode cree un objet d'annulation pour le deplacement
- @param e Objet decrivant l'evenement souris
-*/
-void ConductorTextItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *e) {
- if (flags() & QGraphicsItem::ItemIsMovable) {
- if (Diagram *diagram_ptr = diagram()) {
- // on cree un objet d'annulation correspondant au deplacement qui s'acheve
- QPointF applied_movement = pos() - before_mov_pos_;
-
- if (!applied_movement.isNull()) {
- // on cree un objet d'annulation seulement pour ce champ de texte
- MoveConductorsTextsCommand *undo_object = new MoveConductorsTextsCommand(diagram_ptr);
- undo_object -> addTextMovement(this, before_mov_pos_, pos(), moved_by_user_);
-
- // on active le flag indiquant que ce champ de texte a ete explicitement repositionne par l'utilisateur
- moved_by_user_ = true;
-
- diagram_ptr -> undoStack().push(undo_object);
- }
-
- if (parent_conductor_) {
- parent_conductor_ -> setHighlighted(Conductor::None);
- }
- }
- }
- if (!(e -> modifiers() & Qt::ControlModifier)) {
- QGraphicsTextItem::mouseReleaseEvent(e);
- }
-}
Deleted: branches/devel/sources/conductortextitem.h
===================================================================
--- branches/devel/sources/conductortextitem.h 2013-11-06 18:44:39 UTC (rev 2595)
+++ branches/devel/sources/conductortextitem.h 2013-11-07 09:18:03 UTC (rev 2596)
@@ -1,69 +0,0 @@
-/*
- Copyright 2006-2013 The QElectroTech Team
- 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/>.
-*/
-#ifndef CONDUCTOR_TEXT_ITEM_H
-#define CONDUCTOR_TEXT_ITEM_H
-#include "diagramtextitem.h"
-class Conductor;
-/**
- This class represents a text item attached to a parent conductor.
- It may be moved and edited by users.
- It may also be rotated to any angle.
- Its movements are however limited to a particular distance around its
- parent conductor.
-*/
-class ConductorTextItem : public DiagramTextItem {
- Q_OBJECT
-
- // constructors, destructor
- public:
- ConductorTextItem(Conductor * = 0, Diagram * = 0);
- ConductorTextItem(const QString &, Conductor * = 0, Diagram * = 0);
- virtual ~ConductorTextItem();
- private:
- ConductorTextItem(const ConductorTextItem &);
-
- // attributes
- public:
- enum { Type = UserType + 1006 };
- Conductor *parentConductor() const;
- virtual void fromXml(const QDomElement &);
- virtual QDomElement toXml(QDomDocument &) const;
-
- // methods
- public:
- virtual int type() const { return Type; }
- virtual bool wasMovedByUser() const;
- virtual bool wasRotateByUser() const;
- virtual void forceMovedByUser(bool);
- virtual void forceRotateByUser(bool);
-
- protected:
- virtual void mousePressEvent(QGraphicsSceneMouseEvent *);
- virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *);
- virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *);
-
- // attributes
- private:
- Conductor *parent_conductor_;
- bool moved_by_user_;
- bool rotate_by_user_;
- QPointF before_mov_pos_;
- bool first_move_;
- QPointF mouse_to_origin_movement_;
-};
-#endif
Deleted: branches/devel/sources/customelement.cpp
===================================================================
--- branches/devel/sources/customelement.cpp 2013-11-06 18:44:39 UTC (rev 2595)
+++ branches/devel/sources/customelement.cpp 2013-11-07 09:18:03 UTC (rev 2596)
@@ -1,806 +0,0 @@
-/*
- Copyright 2006-2013 The QElectroTech Team
- 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/>.
-*/
-#include "customelement.h"
-#include "elementtextitem.h"
-#include "diagram.h"
-#include "qetapp.h"
-#include "partline.h"
-#include "elementdefinition.h"
-#include <iostream>
-
-/**
- Constructeur de la classe CustomElement. Permet d'instancier un element
- utilisable comme un element fixe a la difference que l'element perso est
- construit a partir d'une description au format XML. Celle-ci est recuperee
- a l'emplacement indique.
- @param location Emplacement de la definition d'element a utiliser
- @param qgi Le QGraphicsItem parent de cet element
- @param s Le Schema affichant cet element
- @param state Un pointeur facultatif vers un entier. La valeur de cet entier
- sera changee de maniere a refleter le deroulement de l'instanciation :
- - 0 : L'instanciation a reussi
- - 1 : l'emplacement n'a pas permis d'acceder a une definition d'element
- - 2 : la definition n'etait pas lisible
- - 3 : la definition n'etait pas valide / exploitable / utilisable
- - 4 : Le document XML n'est pas un element "definition"
- - 5 : Les attributs de la definition ne sont pas presents et / ou valides
- - 6 : La definition est vide
- - 7 : L'analyse d'un element XML decrivant une partie du dessin de l'element a echoue
- - 8 : Aucune partie du dessin n'a pu etre chargee
-*/
-CustomElement::CustomElement(const ElementsLocation &location, QGraphicsItem *qgi, Diagram *s, int *state) :
- FixedElement(qgi, s),
- elmt_state(-1),
- location_(location),
- forbid_antialiasing(false)
-{
- // recupere la definition de l'element
- ElementsCollectionItem *element_item = QETApp::collectionItem(location);
- ElementDefinition *element_definition;
- if (
- !element_item ||\
- !element_item -> isElement() ||\
- !(element_definition = qobject_cast<ElementDefinition *>(element_item))
- ) {
- if (state) *state = 1;
- elmt_state = 1;
- return;
- }
-
- if (!element_definition -> isReadable()) {
- if (state) *state = 2;
- elmt_state = 2;
- return;
- }
-
- if (element_definition -> isNull()) {
- if (state) *state = 3;
- elmt_state = 3;
- return;
- }
-
- buildFromXml(element_definition -> xml(), &elmt_state);
- if (state) *state = elmt_state;
- if (elmt_state) return;
-
- if (state) *state = 0;
- elmt_state = 0;
-}
-
-CustomElement::CustomElement(const QDomElement &xml_def_elmt, QGraphicsItem *qgi, Diagram *s, int *state) : FixedElement(qgi, s) {
- int elmt_state = -1;
- buildFromXml(xml_def_elmt, &elmt_state);
- if (state) *state = elmt_state;
-}
-
-/**
- Construit l'element personnalise a partir d'un element XML representant sa
- definition.
- @param xml_def_elmt
- @param state Un pointeur facultatif vers un entier. La valeur de cet entier
- sera changee de maniere a refleter le deroulement de l'instanciation :
- - 0 : La construction s'est bien passee
- - 4 : Le document XML n'est pas un element "definition"
- - 5 : Les attributs de la definition ne sont pas presents et / ou valides
- - 6 : La definition est vide
- - 7 : L'analyse d'un element XML decrivant une partie du dessin de l'element a echoue
- - 8 : Aucune partie du dessin n'a pu etre chargee
- @return true si le chargement a reussi, false sinon
-*/
-bool CustomElement::buildFromXml(const QDomElement &xml_def_elmt, int *state) {
-
- if (xml_def_elmt.tagName() != "definition" || xml_def_elmt.attribute("type") != "element") {
- if (state) *state = 4;
- return(false);
- }
-
- // verifie basiquement que la version actuelle est capable de lire ce fichier
- if (xml_def_elmt.hasAttribute("version")) {
- bool conv_ok;
- qreal element_version = xml_def_elmt.attribute("version").toDouble(&conv_ok);
- if (conv_ok && QET::version.toDouble() < element_version) {
- std::cerr << qPrintable(
- QObject::tr("Avertissement : l'\351l\351ment "
- " a \351t\351 enregistr\351 avec une version"
- " ult\351rieure de QElectroTech.")
- ) << std::endl;
- }
- }
-
- // ces attributs doivent etre presents et valides
- int w, h, hot_x, hot_y;
- if (
- !QET::attributeIsAnInteger(xml_def_elmt, QString("width"), &w) ||\
- !QET::attributeIsAnInteger(xml_def_elmt, QString("height"), &h) ||\
- !QET::attributeIsAnInteger(xml_def_elmt, QString("hotspot_x"), &hot_x) ||\
- !QET::attributeIsAnInteger(xml_def_elmt, QString("hotspot_y"), &hot_y) ||\
- !validOrientationAttribute(xml_def_elmt)
- ) {
- if (state) *state = 5;
- return(false);
- }
-
- // on peut d'ores et deja specifier la taille et le hotspot
- setSize(w, h);
- setHotspot(QPoint(hot_x, hot_y));
- setInternalConnections(xml_def_elmt.attribute("ic") == "true");
-
- // la definition est supposee avoir des enfants
- if (xml_def_elmt.firstChild().isNull()) {
- if (state) *state = 6;
- return(false);
- }
-
- // initialisation du QPainter (pour dessiner l'element)
- QPainter qp;
- qp.begin(&drawing);
-
- QPainter low_zoom_qp;
- low_zoom_qp.begin(&low_zoom_drawing);
- QPen tmp;
- tmp.setWidthF(1.0); // ligne vaudou pour prise en compte du setCosmetic - ne pas enlever
- tmp.setCosmetic(true);
- low_zoom_qp.setPen(tmp);
-
- // extrait les noms de la definition XML
- names.fromXml(xml_def_elmt);
- setToolTip(name());
-
- // parcours des enfants de la definition : parties du dessin
- int parsed_elements_count = 0;
- for (QDomNode node = xml_def_elmt.firstChild() ; !node.isNull() ; node = node.nextSibling()) {
- QDomElement elmts = node.toElement();
- if (elmts.isNull()) continue;
- if (elmts.tagName() == "description") {
- // gestion de la description graphique de l'element
- // = parcours des differentes parties du dessin
- for (QDomNode n = node.firstChild() ; !n.isNull() ; n = n.nextSibling()) {
- QDomElement qde = n.toElement();
- if (qde.isNull()) continue;
- if (parseElement(qde, qp)) {
- ++ parsed_elements_count;
- QString current_tag = qde.tagName();
- if (current_tag != "terminal" && current_tag != "input") {
- forbid_antialiasing = true;
- parseElement(qde, low_zoom_qp);
- forbid_antialiasing = false;
- }
- } else {
- if (state) *state = 7;
- return(false);
- }
- }
- }
- }
-
- // fin du dessin
- qp.end();
- low_zoom_qp.end();
-
- // il doit y avoir au moins un element charge
- if (!parsed_elements_count) {
- if (state) *state = 8;
- return(false);
- } else {
- if (state) *state = 0;
- return(true);
- }
-}
-
-/**
- Destructeur
-*/
-CustomElement::~CustomElement() {
-}
-
-/// @return la liste des bornes de cet element
-QList<Terminal *> CustomElement::terminals() const {
- return(list_terminals);
-}
-
-/// @return la liste des conducteurs rattaches a cet element
-QList<Conductor *> CustomElement::conductors() const {
- QList<Conductor *> conductors;
- foreach(Terminal *t, list_terminals) conductors << t -> conductors();
- return(conductors);
-}
-
-/// @return la liste des textes de cet element
-QList<ElementTextItem *> CustomElement::texts() const {
- return(list_texts_);
-}
-
-/**
- @return Le nombre de bornes que l'element possede
-*/
-int CustomElement::terminalsCount() const {
- return(list_terminals.size());
-}
-
-/**
- Dessine le composant sur le Diagram
- @param qp Le QPainter a utiliser pour dessiner l'element
- @param options Les options graphiques
-*/
-void CustomElement::paint(QPainter *qp, const QStyleOptionGraphicsItem *options) {
- if (options && options -> levelOfDetail < 1.0) {
- low_zoom_drawing.play(qp);
- } else {
- drawing.play(qp);
- }
-}
-
-/**
- Analyse et prend en compte un element XML decrivant une partie du dessin
- de l'element perso. Si l'analyse reussit, la partie est ajoutee au dessin.
- Cette partie peut etre une borne, une ligne, une ellipse, un cercle, un arc
- de cercle ou un polygone. Cette methode renvoie false si l'analyse
- d'une de ces formes echoue. Si l'analyse reussit ou dans le cas d'une forme
- inconnue, cette methode renvoie true. A l'exception des bornes, toutes les
- formes peuvent avoir un attribut style. @see setPainterStyle
- @param e L'element XML a analyser
- @param qp Le QPainter a utiliser pour dessiner l'element perso
- @return true si l'analyse reussit, false sinon
-*/
-bool CustomElement::parseElement(QDomElement &e, QPainter &qp) {
- if (e.tagName() == "terminal") return(parseTerminal(e));
- else if (e.tagName() == "line") return(parseLine(e, qp));
- else if (e.tagName() == "rect") return(parseRect(e, qp));
- else if (e.tagName() == "ellipse") return(parseEllipse(e, qp));
- else if (e.tagName() == "circle") return(parseCircle(e, qp));
- else if (e.tagName() == "arc") return(parseArc(e, qp));
- else if (e.tagName() == "polygon") return(parsePolygon(e, qp));
- else if (e.tagName() == "text") return(parseText(e, qp));
- else if (e.tagName() == "input") return(parseInput(e));
- else return(true); // on n'est pas chiant, on ignore l'element inconnu
-}
-
-/**
- Analyse un element XML suppose representer une ligne. Si l'analyse
- reussit, la ligne est ajoutee au dessin.
- La ligne est definie par les attributs suivants :
- - x1, y1 : reels, coordonnees d'une extremite de la ligne
- - x2, y2 : reels, coordonnees de l'autre extremite de la ligne
-
- @param e L'element XML a analyser
- @param qp Le QPainter a utiliser pour dessiner l'element perso
- @return true si l'analyse reussit, false sinon
-*/
-bool CustomElement::parseLine(QDomElement &e, QPainter &qp) {
- // verifie la presence et la validite des attributs obligatoires
- qreal x1, y1, x2, y2;
- if (!QET::attributeIsAReal(e, QString("x1"), &x1)) return(false);
- if (!QET::attributeIsAReal(e, QString("y1"), &y1)) return(false);
- if (!QET::attributeIsAReal(e, QString("x2"), &x2)) return(false);
- if (!QET::attributeIsAReal(e, QString("y2"), &y2)) return(false);
-
- QET::EndType first_end = QET::endTypeFromString(e.attribute("end1"));
- QET::EndType second_end = QET::endTypeFromString(e.attribute("end2"));
- qreal length1, length2;
- if (!QET::attributeIsAReal(e, QString("length1"), &length1)) length1 = 1.5;
- if (!QET::attributeIsAReal(e, QString("length2"), &length2)) length2 = 1.5;
-
- qp.save();
- setPainterStyle(e, qp);
- QPen t = qp.pen();
- t.setJoinStyle(Qt::MiterJoin);
- qp.setPen(t);
-
- QLineF line(x1, y1, x2, y2);
- QPointF point1(line.p1());
- QPointF point2(line.p2());
-
- qreal line_length(line.length());
- qreal pen_width = qp.pen().widthF();
-
- // determine s'il faut dessiner les extremites
- bool draw_1st_end, draw_2nd_end;
- qreal reduced_line_length = line_length - (length1 * PartLine::requiredLengthForEndType(first_end));
- draw_1st_end = first_end && reduced_line_length >= 0;
- if (draw_1st_end) {
- reduced_line_length -= (length2 * PartLine::requiredLengthForEndType(second_end));
- } else {
- reduced_line_length = line_length - (length2 * PartLine::requiredLengthForEndType(second_end));
- }
- draw_2nd_end = second_end && reduced_line_length >= 0;
-
- // dessine la premiere extremite
- QPointF start_point, stop_point;
- if (draw_1st_end) {
- QList<QPointF> four_points1(PartLine::fourEndPoints(point1, point2, length1));
- if (first_end == QET::Circle) {
- qp.drawEllipse(QRectF(four_points1[0] - QPointF(length1, length1), QSizeF(length1 * 2.0, length1 * 2.0)));
- start_point = four_points1[1];
- } else if (first_end == QET::Diamond) {
- qp.drawPolygon(QPolygonF() << four_points1[1] << four_points1[2] << point1 << four_points1[3]);
- start_point = four_points1[1];
- } else if (first_end == QET::Simple) {
- qp.drawPolyline(QPolygonF() << four_points1[3] << point1 << four_points1[2]);
- start_point = point1;
-
- } else if (first_end == QET::Triangle) {
- qp.drawPolygon(QPolygonF() << four_points1[0] << four_points1[2] << point1 << four_points1[3]);
- start_point = four_points1[0];
- }
-
- // ajuste le depart selon l'epaisseur du trait
- if (pen_width && (first_end == QET::Simple || first_end == QET::Circle)) {
- start_point = QLineF(start_point, point2).pointAt(pen_width / 2.0 / line_length);
- }
- } else {
- start_point = point1;
- }
-
- // dessine la seconde extremite
- if (draw_2nd_end) {
- QList<QPointF> four_points2(PartLine::fourEndPoints(point2, point1, length2));
- if (second_end == QET::Circle) {
- qp.drawEllipse(QRectF(four_points2[0] - QPointF(length2, length2), QSizeF(length2 * 2.0, length2 * 2.0)));
- stop_point = four_points2[1];
- } else if (second_end == QET::Diamond) {
- qp.drawPolygon(QPolygonF() << four_points2[2] << point2 << four_points2[3] << four_points2[1]);
- stop_point = four_points2[1];
- } else if (second_end == QET::Simple) {
- qp.drawPolyline(QPolygonF() << four_points2[3] << point2 << four_points2[2]);
- stop_point = point2;
- } else if (second_end == QET::Triangle) {
- qp.drawPolygon(QPolygonF() << four_points2[0] << four_points2[2] << point2 << four_points2[3] << four_points2[0]);
- stop_point = four_points2[0];
- }
-
- // ajuste l'arrivee selon l'epaisseur du trait
- if (pen_width && (second_end == QET::Simple || second_end == QET::Circle)) {
- stop_point = QLineF(point1, stop_point).pointAt((line_length - (pen_width / 2.0)) / line_length);
- }
- } else {
- stop_point = point2;
- }
-
- qp.drawLine(start_point, stop_point);
-
- qp.restore();
- return(true);
-}
-
-/**
- Analyse un element XML suppose representer un rectangle. Si l'analyse
- reussit, le rectangle est ajoute au dessin.
- Le rectangle est defini par les attributs suivants :
- - x : abscisse du coin superieur gauche du rectangle
- - y : ordonnee du coin superieur gauche du rectangle
- - width : largeur du rectangle
- - height : hauteur du rectangle
-
- @param e L'element XML a analyser
- @param qp Le QPainter a utiliser pour dessiner l'element perso
- @return true si l'analyse reussit, false sinon
-*/
-bool CustomElement::parseRect(QDomElement &e, QPainter &qp) {
- // verifie la presence des attributs obligatoires
- qreal rect_x, rect_y, rect_w, rect_h;
- if (!QET::attributeIsAReal(e, QString("x"), &rect_x)) return(false);
- if (!QET::attributeIsAReal(e, QString("y"), &rect_y)) return(false);
- if (!QET::attributeIsAReal(e, QString("width"), &rect_w)) return(false);
- if (!QET::attributeIsAReal(e, QString("height"), &rect_h)) return(false);
- qp.save();
- setPainterStyle(e, qp);
-
- // force le type de jointures pour les rectangles
- QPen p = qp.pen();
- p.setJoinStyle(Qt::MiterJoin);
- qp.setPen(p);
-
- qp.drawRect(QRectF(rect_x, rect_y, rect_w, rect_h));
- qp.restore();
- return(true);
-}
-
-/**
- Analyse un element XML suppose representer un cercle. Si l'analyse
- reussit, le cercle est ajoute au dessin.
- Le cercle est defini par les attributs suivants :
- - x : abscisse du coin superieur gauche de la quadrature du cercle
- - y : ordonnee du coin superieur gauche de la quadrature du cercle
- - diameter : diametre du cercle
-
- @param e L'element XML a analyser
- @param qp Le QPainter a utiliser pour dessiner l'element perso
- @return true si l'analyse reussit, false sinon
-*/
-bool CustomElement::parseCircle(QDomElement &e, QPainter &qp) {
- // verifie la presence des attributs obligatoires
- qreal cercle_x, cercle_y, cercle_r;
- if (!QET::attributeIsAReal(e, QString("x"), &cercle_x)) return(false);
- if (!QET::attributeIsAReal(e, QString("y"), &cercle_y)) return(false);
- if (!QET::attributeIsAReal(e, QString("diameter"), &cercle_r)) return(false);
- qp.save();
- setPainterStyle(e, qp);
- qp.drawEllipse(QRectF(cercle_x, cercle_y, cercle_r, cercle_r));
- qp.restore();
- return(true);
-}
-
-/**
- Analyse un element XML suppose representer une ellipse. Si l'analyse
- reussit, l'ellipse est ajoutee au dessin.
- L'ellipse est definie par les attributs suivants :
- - x : abscisse du coin superieur gauche du rectangle dans lequel s'inscrit l'ellipse
- - y : ordonnee du coin superieur gauche du rectangle dans lequel s'inscrit l'ellipse
- - width : dimension de la diagonale horizontale de l'ellipse
- - height : dimension de la diagonale verticale de l'ellipse
-
- @param e L'element XML a analyser
- @param qp Le QPainter a utiliser pour dessiner l'element perso
- @return true si l'analyse reussit, false sinon
-*/
-bool CustomElement::parseEllipse(QDomElement &e, QPainter &qp) {
- // verifie la presence des attributs obligatoires
- qreal ellipse_x, ellipse_y, ellipse_l, ellipse_h;
- if (!QET::attributeIsAReal(e, QString("x"), &ellipse_x)) return(false);
- if (!QET::attributeIsAReal(e, QString("y"), &ellipse_y)) return(false);
- if (!QET::attributeIsAReal(e, QString("width"), &ellipse_l)) return(false);
- if (!QET::attributeIsAReal(e, QString("height"), &ellipse_h)) return(false);
- qp.save();
- setPainterStyle(e, qp);
- qp.drawEllipse(QRectF(ellipse_x, ellipse_y, ellipse_l, ellipse_h));
- qp.restore();
- return(true);
-}
-
-/**
- Analyse un element XML suppose representer un arc de cercle. Si l'analyse
- reussit, l'arc de cercle est ajoute au dessin.
- L'arc de cercle est defini par les quatres parametres d'une ellipse (en fait
- l'ellipse dans laquelle s'inscrit l'arc de cercle) auxquels s'ajoutent les
- attributs suivants :
- - start : angle de depart : l'angle "0 degre" est a trois heures
- - angle : etendue (en degres) de l'arc de cercle ; une valeur positive
- va dans le sens contraire des aiguilles d'une montre
-
- @param e L'element XML a analyser
- @param qp Le QPainter a utiliser pour dessiner l'element perso
- @return true si l'analyse reussit, false sinon
-*/
-bool CustomElement::parseArc(QDomElement &e, QPainter &qp) {
- // verifie la presence des attributs obligatoires
- qreal arc_x, arc_y, arc_l, arc_h, arc_s, arc_a;
- if (!QET::attributeIsAReal(e, QString("x"), &arc_x)) return(false);
- if (!QET::attributeIsAReal(e, QString("y"), &arc_y)) return(false);
- if (!QET::attributeIsAReal(e, QString("width"), &arc_l)) return(false);
- if (!QET::attributeIsAReal(e, QString("height"), &arc_h)) return(false);
- if (!QET::attributeIsAReal(e, QString("start"), &arc_s)) return(false);
- if (!QET::attributeIsAReal(e, QString("angle"), &arc_a)) return(false);
-
- qp.save();
- setPainterStyle(e, qp);
- qp.drawArc(QRectF(arc_x, arc_y, arc_l, arc_h), (int)(arc_s * 16), (int)(arc_a * 16));
- qp.restore();
- return(true);
-}
-
-/**
- Analyse un element XML suppose representer un polygone. Si l'analyse
- reussit, le polygone est ajoute au dessin.
- Le polygone est defini par une serie d'attributs x1, x2, ..., xn et autant
- d'attributs y1, y2, ..., yn representant les coordonnees des differents
- points du polygone.
- Il est possible d'obtenir un polygone non ferme en utilisant closed="false"
- @param e L'element XML a analyser
- @param qp Le QPainter a utiliser pour dessiner l'element perso
- @return true si l'analyse reussit, false sinon
-*/
-bool CustomElement::parsePolygon(QDomElement &e, QPainter &qp) {
- int i = 1;
- while(true) {
- if (QET::attributeIsAReal(e, QString("x%1").arg(i)) && QET::attributeIsAReal(e, QString("y%1").arg(i))) ++ i;
- else break;
- }
- if (i < 3) return(false);
- QVector<QPointF> points(i-1);
- for (int j = 1 ; j < i ; ++ j) {
- points.insert(
- j - 1,
- QPointF(
- e.attribute(QString("x%1").arg(j)).toDouble(),
- e.attribute(QString("y%1").arg(j)).toDouble()
- )
- );
- }
- qp.save();
- setPainterStyle(e, qp);
- if (e.attribute("closed") == "false") qp.drawPolyline(points.data(), i-1);
- else qp.drawPolygon(points.data(), i-1);
- qp.restore();
- return(true);
-}
-
-/**
- Analyse un element XML suppose representer un texte. Si l'analyse
- reussit, le texte est ajoute au dessin.
- Le texte est defini par une position, une chaine de caracteres et une
- taille.
- @param e L'element XML a analyser
- @param qp Le QPainter a utiliser pour dessiner l'element perso
- @return true si l'analyse reussit, false sinon
-*/
-bool CustomElement::parseText(QDomElement &e, QPainter &qp) {
- qreal pos_x, pos_y;
- int size;
- if (
- !QET::attributeIsAReal(e, "x", &pos_x) ||\
- !QET::attributeIsAReal(e, "y", &pos_y) ||\
- !QET::attributeIsAnInteger(e, "size", &size) ||\
- !e.hasAttribute("text")
- ) return(false);
-
- qp.save();
- setPainterStyle(e, qp);
-
- // determine la police a utiliser et en recupere les metriques associees
- QFont used_font = QETApp::diagramTextsFont(size);
- QFontMetrics qfm(used_font);
- QColor text_color = (e.attribute("color") != "white"? Qt::black : Qt::white);
-
- // instancie un QTextDocument (comme la classe QGraphicsTextItem) pour
- // generer le rendu graphique du texte
- QTextDocument text_document;
- text_document.setDefaultFont(used_font);
- text_document.setPlainText(e.attribute("text"));
-
- // Se positionne aux coordonnees indiquees dans la description du texte
- qp.setTransform(QTransform(), false);
- qp.translate(pos_x, pos_y);
-
- // Pivote le systeme de coordonnees du QPainter pour effectuer le rendu
- // dans le bon sens
- qreal default_rotation_angle = 0.0;
- if (QET::attributeIsAReal(e, "rotation", &default_rotation_angle)) {
- qp.rotate(default_rotation_angle);
- }
-
- /*
- Deplace le systeme de coordonnees du QPainter pour effectuer le rendu au
- bon endroit ; note : on soustrait l'ascent() de la police pour
- determiner le coin superieur gauche du texte alors que la position
- indiquee correspond a la baseline.
- */
- QPointF qpainter_offset(0.0, -qfm.ascent());
-
- // ajuste le decalage selon la marge du document texte
-#if QT_VERSION >= 0x040500
- text_document.setDocumentMargin(0.0);
-#else
- // il semblerait qu'avant Qt 4.5, le documentMargin vaille 2.0 (et pas 4.0)
- qpainter_offset.rx() -= 2.0;
- qpainter_offset.ry() -= 2.0;
-#endif
-
- qp.translate(qpainter_offset);
-
- // force the palette used to render the QTextDocument
- QAbstractTextDocumentLayout::PaintContext ctx;
- ctx.palette.setColor(QPalette::Text, text_color);
- text_document.documentLayout() -> draw(&qp, ctx);
-
- qp.restore();
- return(true);
-}
-
-/**
- Analyse un element XML suppose representer un champ de texte editable par
- l'utilisateur. Si l'analyse reussit, le champ est ajoute au dessin.
- Le texte est defini par :
- - une position
- - une chaine de caracteres facultative utilisee comme valeur par defaut
- - une taille
- - le fait de subir les rotations de l'element ou non
- @param e L'element XML a analyser
- @return Un pointeur vers l'objet ElementTextItem ainsi cree si l'analyse reussit, 0 sinon
-*/
-ElementTextItem *CustomElement::parseInput(QDomElement &e) {
- qreal pos_x, pos_y;
- int size;
- if (
- !QET::attributeIsAReal(e, "x", &pos_x) ||\
- !QET::attributeIsAReal(e, "y", &pos_y) ||\
- !QET::attributeIsAnInteger(e, "size", &size)
- ) return(0);
-
- ElementTextItem *eti = new ElementTextItem(e.attribute("text"), this);
- eti -> setFont(QETApp::diagramTextsFont(size));
-
- // position du champ de texte
- eti -> setOriginalPos(QPointF(pos_x, pos_y));
- eti -> setPos(pos_x, pos_y);
-
- // rotation du champ de texte
- qreal original_rotation_angle = 0.0;
- QET::attributeIsAReal(e, "rotation", &original_rotation_angle);
- eti -> setOriginalRotationAngle(original_rotation_angle);
- eti -> setRotationAngle(original_rotation_angle);
-
- // comportement du champ lorsque son element parent est pivote
- eti -> setFollowParentRotations(e.attribute("rotate") == "true");
-
- list_texts_ << eti;
-
- return(eti);
-}
-
-/**
- Analyse un element XML suppose representer une borne. Si l'analyse
- reussit, la borne est ajoutee a l'element.
- Une borne est definie par les attributs suivants :
- - x, y : coordonnees de la borne
- - orientation : orientation de la borne = Nord (n), Sud (s), Est (e) ou Ouest (w)
-
- @param e L'element XML a analyser
- @return Un pointeur vers l'objet Terminal ainsi cree, 0 sinon
-*/
-Terminal *CustomElement::parseTerminal(QDomElement &e) {
- // verifie la presence et la validite des attributs obligatoires
- qreal terminalx, terminaly;
- QET::Orientation terminalo;
- if (!QET::attributeIsAReal(e, QString("x"), &terminalx)) return(0);
- if (!QET::attributeIsAReal(e, QString("y"), &terminaly)) return(0);
- if (!e.hasAttribute("orientation")) return(0);
- if (e.attribute("orientation") == "n") terminalo = QET::North;
- else if (e.attribute("orientation") == "s") terminalo = QET::South;
- else if (e.attribute("orientation") == "e") terminalo = QET::East;
- else if (e.attribute("orientation") == "w") terminalo = QET::West;
- else return(0);
- Terminal *new_terminal = new Terminal(terminalx, terminaly, terminalo, this, qobject_cast<Diagram *>(scene()));
- new_terminal -> setZValue(420); // valeur arbitraire pour maintenir les bornes au-dessus des champs de texte
- list_terminals << new_terminal;
- return(new_terminal);
-}
-
-/**
- Active / desactive l'antialiasing sur un QPainter
- @param qp Le QPainter a modifier
- @param aa Booleen a true pour activer l'antialiasing, a false pour le desactiver
-*/
-void CustomElement::setQPainterAntiAliasing(QPainter &qp, bool aa) {
- if (forbid_antialiasing) aa = false;
- qp.setRenderHint(QPainter::Antialiasing, aa);
- qp.setRenderHint(QPainter::TextAntialiasing, aa);
- qp.setRenderHint(QPainter::SmoothPixmapTransform, aa);
-}
-
-/**
- Verifie si l'attribut "orientation" de l'element XML e correspond bien a la
- syntaxe decrivant les orientations possibles pour un element.
- Cette syntaxe comprend exactement 4 lettres :
- - une pour le Nord
- - une pour l'Est
- - une pour le Sud
- - une pour l'Ouest
-
- Pour chaque orientation, on indique si elle est :
- - l'orientation par defaut : d
- - une orientation autorisee : y
- - une orientation interdire : n
-
- Exemple : "dnny" represente un element par defaut oriente vers le nord et qui
- peut etre oriente vers l'ouest mais pas vers le sud ou vers l'est.
- @param e Element XML
- @return true si l'attribut "orientation" est valide, false sinon
-*/
-bool CustomElement::validOrientationAttribute(const QDomElement &e) {
- return(ori.fromString(e.attribute("orientation")));
-}
-
-/**
- Applique les parametres de style definis dans l'attribut "style" de
- l'element XML e au QPainter qp
- Les styles possibles sont :
- - line-style : style du trait
- - dashed : trait en pointilles (tirets)
- - dashdotted : Traits et points
- - dotted : trait en pointilles (points)
- - normal : trait plein [par defaut]
- - line-weight : epaiseur du trait
- - thin : trait fin
- - normal : trait d'epaisseur 1 [par defaut]
- - filling : remplissage de la forme
- - white : remplissage blanc
- - black : remplissage noir
- - red : remplissage rouge
- - blue : remplissage bleu
- - green : remplissage vert
- - none : pas de remplissage [par defaut]
- - color : couleur du trait et du texte
- - white : trait noir [par defaut]
- - black : trait blanc
- - red : trait rouge
- - blue : trait bleu
- - green : trait vert
-
- Les autres valeurs ne sont pas prises en compte.
- @param e L'element XML a parser
- @param qp Le QPainter a modifier en fonction des styles
-*/
-void CustomElement::setPainterStyle(QDomElement &e, QPainter &qp) {
- // recupere le QPen et la QBrush du QPainter
- QPen pen = qp.pen();
- QBrush brush = qp.brush();
-
- // attributs par defaut
- pen.setJoinStyle(Qt::BevelJoin);
- pen.setCapStyle(Qt::SquareCap);
-
- // recupere la liste des couples style / valeur
- QStringList styles = e.attribute("style").split(";", QString::SkipEmptyParts);
-
- // agit sur le QPen et la QBrush en fonction des valeurs rencontrees
- QRegExp rx("^\\s*([a-z-]+)\\s*:\\s*([a-z-]+)\\s*$");
- foreach (QString style, styles) {
- if (rx.exactMatch(style)) {
- QString style_name = rx.cap(1);
- QString style_value = rx.cap(2);
- if (style_name == "line-style") {
- if (style_value == "dashed") pen.setStyle(Qt::DashLine);
- else if (style_value == "dotted") pen.setStyle(Qt::DotLine);
- else if (style_value == "dashdotted") pen.setStyle(Qt::DashDotLine);
- else if (style_value == "normal") pen.setStyle(Qt::SolidLine);
- } else if (style_name == "line-weight") {
- if (style_value == "thin") pen.setWidth(0);
- else if (style_value == "normal") pen.setWidthF(1.0);
- else if (style_value == "none") pen.setColor(QColor(0, 0, 0, 0));
- } else if (style_name == "filling") {
- if (style_value == "white") {
- brush.setStyle(Qt::SolidPattern);
- brush.setColor(Qt::white);
- } else if (style_value == "black") {
- brush.setStyle(Qt::SolidPattern);
- brush.setColor(Qt::black);
- } else if (style_value == "blue") {
- brush.setStyle(Qt::SolidPattern);
- brush.setColor(Qt::blue);
- } else if (style_value == "red") {
- brush.setStyle(Qt::SolidPattern);
- brush.setColor(Qt::red);
- } else if (style_value == "green") {
- brush.setStyle(Qt::SolidPattern);
- brush.setColor(Qt::green);
- } else if (style_value == "none") {
- brush.setStyle(Qt::NoBrush);
- }
- } else if (style_name == "color") {
- if (style_value == "black") {
- pen.setColor(QColor(0, 0, 0, pen.color().alpha()));
- } else if (style_value == "white") {
- pen.setColor(QColor(255, 255, 255, pen.color().alpha()));
- } else if (style_value == "red") {
- pen.setColor(Qt::red);
- }else if (style_value == "blue") {
- pen.setColor(Qt::blue);
- }else if (style_value == "green") {
- pen.setColor(Qt::green);
- }
- }
- }
- }
-
- // affectation du QPen et de la QBrush modifies au QPainter
- qp.setPen(pen);
- qp.setBrush(brush);
-
- // mise en place (ou non) de l'antialiasing
- setQPainterAntiAliasing(qp, e.attribute("antialias") == "true");
-}
Deleted: branches/devel/sources/customelement.h
===================================================================
--- branches/devel/sources/customelement.h 2013-11-06 18:44:39 UTC (rev 2595)
+++ branches/devel/sources/customelement.h 2013-11-07 09:18:03 UTC (rev 2596)
@@ -1,132 +0,0 @@
-/*
- Copyright 2006-2013 The QElectroTech Team
- 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/>.
-*/
-#ifndef CUSTOM_ELEMENT_H
-#define CUSTOM_ELEMENT_H
-#include "fixedelement.h"
-#include <QtGui>
-#include "nameslist.h"
-#include "elementslocation.h"
-class ElementTextItem;
-class Terminal;
-/**
- This class represents an electrical element; it may be used like a fixed
- element, the difference being that the CustomElement reads its description
- (names, drawing, behavior) from an XML document.
-*/
-class CustomElement : public FixedElement {
-
- Q_OBJECT
-
- // constructors, destructor
- public:
- CustomElement(const ElementsLocation &, QGraphicsItem * = 0, Diagram * = 0, int * = 0);
- CustomElement(const QDomElement &, QGraphicsItem * = 0, Diagram * = 0, int * = 0);
- virtual ~CustomElement();
-
- private:
- CustomElement(const CustomElement &);
-
- // attributes
- protected:
- int elmt_state; // hold the error code in case the instanciation fails, or 0 if everything went well
- NamesList names;
- ElementsLocation location_;
- QPicture drawing;
- QPicture low_zoom_drawing;
- QList<Terminal *> list_terminals;
- QList<ElementTextItem *> list_texts_;
- bool forbid_antialiasing;
-
- // methods
- public:
- virtual QList<Terminal *> terminals() const;
- virtual QList<Conductor *> conductors() const;
- virtual QList<ElementTextItem *> texts() const;
- virtual int terminalsCount() const;
- virtual void paint(QPainter *, const QStyleOptionGraphicsItem *);
- QString typeId() const;
- ElementsLocation location() const;
- bool isNull() const;
- int state() const;
- QString name() const;
-
- protected:
- virtual bool buildFromXml(const QDomElement &, int * = 0);
- virtual bool parseElement(QDomElement &, QPainter &);
- virtual bool parseLine(QDomElement &, QPainter &);
- virtual bool parseRect(QDomElement &, QPainter &);
- virtual bool parseEllipse(QDomElement &, QPainter &);
- virtual bool parseCircle(QDomElement &, QPainter &);
- virtual bool parseArc(QDomElement &, QPainter &);
- virtual bool parsePolygon(QDomElement &, QPainter &);
- virtual bool parseText(QDomElement &, QPainter &);
- virtual ElementTextItem *parseInput(QDomElement &);
- virtual Terminal *parseTerminal(QDomElement &);
- virtual void setQPainterAntiAliasing(QPainter &, bool);
- virtual bool validOrientationAttribute(const QDomElement &);
- virtual void setPainterStyle(QDomElement &, QPainter &);
-};
-
-/**
- @return The element type ID; considering a CustomElement, this means the
- @location of its XML description.
- @see location()
-*/
-inline QString CustomElement::typeId() const {
- return(location_.path());
-}
-
-/**
- @return the location of the XML document describing this element.
-*/
-inline ElementsLocation CustomElement::location() const {
- return(location_);
-}
-
-/**
- @return true if this element is null, i.e. if its XML description could not
- be loaded.
-*/
-inline bool CustomElement::isNull() const {
- return(elmt_state);
-}
-
-/**
- @return An integer representing the state of this element:
- - 0: instantiation succeeded
- - 1: the file does not exist
- - 2: the file could not be opened
- - 3: The file is not a valid XML document
- - 4: The XML document does not have a "definition" root element.
- - 5: The definition attributes are missing or invalid
- - 6: The definition is empty
- - 7: The parsing of an XML element describing an element drawing primitive failed
- - 8: No primitive could be loadedAucune partie du dessin n'a pu etre chargee
-*/
-inline int CustomElement::state() const {
- return(elmt_state);
-}
-
-/**
- @return The name of this element.
-*/
-inline QString CustomElement::name() const {
- return(names.name(location_.baseName()));
-}
-
-#endif
Modified: branches/devel/sources/diagram.cpp
===================================================================
--- branches/devel/sources/diagram.cpp 2013-11-06 18:44:39 UTC (rev 2595)
+++ branches/devel/sources/diagram.cpp 2013-11-07 09:18:03 UTC (rev 2596)
@@ -16,19 +16,19 @@
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
*/
#include <math.h>
-#include "conductor.h"
-#include "conductortextitem.h"
-#include "customelement.h"
+#include "qetgraphicsitem/conductor.h"
+#include "qetgraphicsitem/conductortextitem.h"
+#include "qetgraphicsitem/customelement.h"
#include "diagram.h"
#include "diagramcommands.h"
#include "diagramcontent.h"
#include "diagramposition.h"
-#include "elementtextitem.h"
+#include "qetgraphicsitem/elementtextitem.h"
#include "elementsmover.h"
#include "elementtextsmover.h"
#include "exportdialog.h"
-#include "ghostelement.h"
-#include "independenttextitem.h"
+#include "qetgraphicsitem/ghostelement.h"
+#include "qetgraphicsitem/independenttextitem.h"
#include "qetapp.h"
#include "qetgraphicsitem/diagramimageitem.h"
@@ -547,7 +547,7 @@
// chargement de tous les textes du fichiers XML
QList<IndependentTextItem *> added_texts;
foreach (QDomElement text_xml, QET::findInDomElement(root, "inputs", "input")) {
- IndependentTextItem *iti = new IndependentTextItem(this);
+ IndependentTextItem *iti = new IndependentTextItem(this);
iti -> fromXml(text_xml);
addIndependentTextItem(iti);
added_texts << iti;
Modified: branches/devel/sources/diagramcommands.cpp
===================================================================
--- branches/devel/sources/diagramcommands.cpp 2013-11-06 18:44:39 UTC (rev 2595)
+++ branches/devel/sources/diagramcommands.cpp 2013-11-07 09:18:03 UTC (rev 2596)
@@ -16,15 +16,15 @@
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
*/
#include "diagramcommands.h"
-#include "element.h"
-#include "conductor.h"
-#include "conductortextitem.h"
+#include "qetgraphicsitem/element.h"
+#include "qetgraphicsitem/conductor.h"
+#include "qetgraphicsitem/conductortextitem.h"
#include "diagram.h"
-#include "elementtextitem.h"
-#include "independenttextitem.h"
+#include "qetgraphicsitem/elementtextitem.h"
+#include "qetgraphicsitem/independenttextitem.h"
#include "qgimanager.h"
#include "diagram.h"
-#include "diagramtextitem.h"
+#include "qetgraphicsitem/diagramtextitem.h"
#include "qetgraphicsitem/diagramimageitem.h"
/**
@@ -635,7 +635,7 @@
elements_to_rotate(elements),
texts_to_rotate(texts),
images_to_rotate(images),
- applied_rotation_angle_(-90.0)
+ applied_rotation_angle_(90.0)
{
setText(
QString(
@@ -706,7 +706,7 @@
void RotateElementsCommand::rotateElement(Element *element, QET::Orientation orientation) {
qreal rotation_value = 90.0 * (orientation - element -> orientation().current());
element -> setOrientation(orientation);
- element -> update();
+ //element -> update();
if (rotation_value) {
// repositionne les textes de l'element qui ne comportent pas l'option "FollowParentRotations"
foreach(ElementTextItem *eti, element -> texts()) {
Modified: branches/devel/sources/diagramcommands.h
===================================================================
--- branches/devel/sources/diagramcommands.h 2013-11-06 18:44:39 UTC (rev 2595)
+++ branches/devel/sources/diagramcommands.h 2013-11-07 09:18:03 UTC (rev 2596)
@@ -19,7 +19,7 @@
#define DIAGRAM_COMMANDS_H
#include <QtGui>
#include "borderproperties.h"
-#include "conductor.h"
+#include "qetgraphicsitem/conductor.h"
#include "conductorproperties.h"
#include "diagramcontent.h"
#include "titleblockproperties.h"
Modified: branches/devel/sources/diagramcontent.cpp
===================================================================
--- branches/devel/sources/diagramcontent.cpp 2013-11-06 18:44:39 UTC (rev 2595)
+++ branches/devel/sources/diagramcontent.cpp 2013-11-07 09:18:03 UTC (rev 2596)
@@ -17,9 +17,9 @@
*/
#include "diagramcontent.h"
#include <QGraphicsItem>
-#include "element.h"
-#include "independenttextitem.h"
-#include "conductor.h"
+#include "qetgraphicsitem/element.h"
+#include "qetgraphicsitem/independenttextitem.h"
+#include "qetgraphicsitem/conductor.h"
#include "qetgraphicsitem/diagramimageitem.h"
/**
Deleted: branches/devel/sources/diagramtextitem.cpp
===================================================================
--- branches/devel/sources/diagramtextitem.cpp 2013-11-06 18:44:39 UTC (rev 2595)
+++ branches/devel/sources/diagramtextitem.cpp 2013-11-07 09:18:03 UTC (rev 2596)
@@ -1,328 +0,0 @@
-/*
- Copyright 2006-2013 QElectroTech Team
- 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/>.
-*/
-#include "diagramtextitem.h"
-#include "diagramcommands.h"
-#include "qet.h"
-#include "qetapp.h"
-
-#include "richtext/richtexteditor_p.h"
-
-/**
- Constructeur
- @param parent Le QGraphicsItem parent du champ de texte
- @param parent_diagram Le schema auquel appartient le champ de texte
-*/
-DiagramTextItem::DiagramTextItem(QGraphicsItem *parent, Diagram *parent_diagram) :
- QGraphicsTextItem(parent, parent_diagram),
- previous_text_(),
- rotation_angle_(0.0)
-{
- //set Zvalue at 10 to be upper than the DiagramImageItem
- setZValue(10);
- setDefaultTextColor(Qt::black);
- setFont(QETApp::diagramTextsFont());
- setFlags(QGraphicsItem::ItemIsSelectable|QGraphicsItem::ItemIsMovable);
-#if QT_VERSION >= 0x040600
- setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
-#endif
- connect(this, SIGNAL(lostFocus()), this, SLOT(setNonFocusable()));
-}
-
-/**
- Constructeur
- @param text Le texte affiche par le champ de texte
- @param parent Le QGraphicsItem parent du champ de texte
- @param parent_diagram Le schema auquel appartient le champ de texte
-*/
-DiagramTextItem::DiagramTextItem(const QString &text, QGraphicsItem *parent, Diagram *parent_diagram) :
- QGraphicsTextItem(text, parent, parent_diagram),
- previous_text_(text),
- rotation_angle_(0.0)
-{
- //set Zvalue at 10 to be upper than the DiagramImageItem
- setZValue(10);
- setDefaultTextColor(Qt::black);
- setFont(QETApp::diagramTextsFont());
- setFlags(QGraphicsItem::ItemIsSelectable|QGraphicsItem::ItemIsMovable);
-#if QT_VERSION >= 0x040600
- setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
-#endif
- connect(this, SIGNAL(lostFocus()), this, SLOT(setNonFocusable()));
-}
-
-/// Destructeur
-DiagramTextItem::~DiagramTextItem() {
-}
-
-/**
- @return le Diagram auquel ce texte appartient, ou 0 si ce texte n'est
- rattache a aucun schema
-*/
-Diagram *DiagramTextItem::diagram() const {
- return(qobject_cast<Diagram *>(scene()));
-}
-
-/**
- @return l'angle de rotation actuel de ce texte
-*/
-qreal DiagramTextItem::rotationAngle() const {
- return(rotation_angle_);
-}
-
-/**
- Permet de tourner le texte a un angle donne de maniere absolue.
- Un angle de 0 degres correspond a un texte horizontal non retourne.
- @param rotation Nouvel angle de rotation de ce texte
- @see applyRotation
-*/
-void DiagramTextItem::setRotationAngle(const qreal &rotation) {
- qreal applied_rotation = QET::correctAngle(rotation);
- applyRotation(applied_rotation - rotation_angle_);
- rotation_angle_ = applied_rotation;
-}
-
-/**
- Permet de tourner le texte de maniere relative.
- L'angle added_rotation est ajoute a l'orientation actuelle du texte.
- @param added_rotation Angle a ajouter a la rotation actuelle
- @see applyRotation
-*/
-void DiagramTextItem::rotateBy(const qreal &added_rotation) {
- qreal applied_added_rotation = QET::correctAngle(added_rotation);
- rotation_angle_ = QET::correctAngle(rotation_angle_ + applied_added_rotation);
- applyRotation(applied_added_rotation);
-}
-
-/**
- Traduit en coordonnees de la scene un mouvement / vecteur initialement
- exprime en coordonnees locales.
- @param movement Vecteur exprime en coordonnees locales
- @return le meme vecteur, exprime en coordonnees de la scene
-*/
-QPointF DiagramTextItem::mapMovementToScene(const QPointF &movement) const {
- // on definit deux points en coordonnees locales
- QPointF local_origin(0.0, 0.0);
- QPointF local_movement_point(movement);
-
- // on les mappe sur la scene
- QPointF scene_origin(mapToScene(local_origin));
- QPointF scene_movement_point(mapToScene(local_movement_point));
-
- // on calcule le vecteur represente par ces deux points
- return(scene_movement_point - scene_origin);
-}
-
-/**
- Traduit en coordonnees locales un mouvement / vecteur initialement
- exprime en coordonnees de la scene.
- @param movement Vecteur exprime en coordonnees de la scene
- @return le meme vecteur, exprime en coordonnees locales
-*/
-QPointF DiagramTextItem::mapMovementFromScene(const QPointF &movement) const {
- // on definit deux points sur la scene
- QPointF scene_origin(0.0, 0.0);
- QPointF scene_movement_point(movement);
-
- // on les mappe sur ce QGraphicsItem
- QPointF local_origin(mapFromScene(scene_origin));
- QPointF local_movement_point(mapFromScene(scene_movement_point));
-
- // on calcule le vecteur represente par ces deux points
- return(local_movement_point - local_origin);
-}
-
-/**
- Traduit en coordonnees de l'item parent un mouvement / vecteur initialement
- exprime en coordonnees locales.
- @param movement Vecteur exprime en coordonnees locales
- @return le meme vecteur, exprime en coordonnees du parent
-*/
-QPointF DiagramTextItem::mapMovementToParent(const QPointF &movement) const {
- // on definit deux points en coordonnees locales
- QPointF local_origin(0.0, 0.0);
- QPointF local_movement_point(movement);
-
- // on les mappe sur la scene
- QPointF parent_origin(mapToParent(local_origin));
- QPointF parent_movement_point(mapToParent(local_movement_point));
-
- // on calcule le vecteur represente par ces deux points
- return(parent_movement_point - parent_origin);
-}
-
-/**
- Traduit en coordonnees locales un mouvement / vecteur initialement
- exprime en coordonnees du parent.
- @param movement Vecteur exprime en coordonnees du parent
- @return le meme vecteur, exprime en coordonnees locales
-*/
-QPointF DiagramTextItem::mapMovementFromParent(const QPointF &movement) const {
- // on definit deux points sur le parent
- QPointF parent_origin(0.0, 0.0);
- QPointF parent_movement_point(movement);
-
- // on les mappe sur ce QGraphicsItem
- QPointF local_origin(mapFromParent(parent_origin));
- QPointF local_movement_point(mapFromParent(parent_movement_point));
-
- // on calcule le vecteur represente par ces deux points
- return(local_movement_point - local_origin);
-}
-
-/**
- Dessine le champ de texte.
- Cette methode delegue simplement le travail a QGraphicsTextItem::paint apres
- avoir desactive l'antialiasing.
- @param painter Le QPainter a utiliser pour dessiner le champ de texte
- @param option Les options de style pour le champ de texte
- @param widget Le QWidget sur lequel on dessine
-*/
-void DiagramTextItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) {
- painter -> setRenderHint(QPainter::Antialiasing, false);
- QGraphicsTextItem::paint(painter, option, widget);
-}
-
-/**
- Gere la prise de focus du champ de texte
- @param e Objet decrivant la prise de focus
-*/
-void DiagramTextItem::focusInEvent(QFocusEvent *e) {
- QGraphicsTextItem::focusInEvent(e);
-
- // empeche le deplacement du texte pendant son edition
- setFlag(QGraphicsItem::ItemIsMovable, false);
-
- // memorise le texte avant que l'utilisateur n'y touche
- previous_text_ = toHtml();
- // cela permettra de determiner si l'utilisateur a modifie le texte a la fin de l'edition
-}
-
-/**
- Gere la perte de focus du champ de texte
- @param e Objet decrivant la perte de focus
-*/
-void DiagramTextItem::focusOutEvent(QFocusEvent *e) {
- QGraphicsTextItem::focusOutEvent(e);
-
- // signale la modification du texte si besoin
- if (toPlainText() != previous_text_) {
- emit(diagramTextChanged(this, previous_text_, toHtml()));
- previous_text_ = toHtml();
- }
-
- // deselectionne le texte
- QTextCursor cursor = textCursor();
- cursor.clearSelection();
- setTextCursor(cursor);
-
- // hack a la con pour etre re-entrant
- setTextInteractionFlags(Qt::NoTextInteraction);
-
- // autorise de nouveau le deplacement du texte
- setFlag(QGraphicsItem::ItemIsMovable, true);
- QTimer::singleShot(0, this, SIGNAL(lostFocus()));
-}
-
-/**
- Gere les double-clics sur ce champ de texte.
- @param event un QGraphicsSceneMouseEvent decrivant le double-clic
-*/
-void DiagramTextItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) {
- if (!(textInteractionFlags() & Qt::TextEditable)) {
- // rend le champ de texte editable
- setTextInteractionFlags(Qt::TextEditorInteraction);
-
- // edite le champ de texte
- setFocus(Qt::MouseFocusReason);
- } else {
- QGraphicsTextItem::mouseDoubleClickEvent(event);
- }
-}
-
-/**
- Effectue la rotation du texte en elle-meme
- Pour les DiagramTextItem, la rotation s'effectue autour du point (0, 0).
- Cette methode peut toutefois etre redefinie dans des classes filles
- @param angle Angle de la rotation a effectuer
-*/
-void DiagramTextItem::applyRotation(const qreal &angle) {
- setRotation(QET::correctAngle(rotation()+angle));
-}
-
-/**
- Change la position du champ de texte en veillant a ce qu'il
- reste sur la grille du schema auquel il appartient.
- @param p Nouvelles coordonnees de l'element
-*/
-void DiagramTextItem::setPos(const QPointF &p) {
- if (p == pos()) return;
- // pas la peine de positionner sur la grille si l'element n'est pas sur un Diagram
- if (scene()) {
- // arrondit l'abscisse a 10 px pres
- int p_x = qRound(p.x() / (Diagram::xGrid * 1.0)) * Diagram::xGrid;
- // arrondit l'ordonnee a 10 px pres
- int p_y = qRound(p.y() / (Diagram::yGrid * 1.0)) * Diagram::yGrid;
- QGraphicsTextItem::setPos(p_x, p_y);
- } else QGraphicsTextItem::setPos(p);
-}
-
-/**
- Change la position du champ de texte en veillant a ce que l'il
- reste sur la grille du schema auquel il appartient.
- @param x Nouvelle abscisse de l'element
- @param y Nouvelle ordonnee de l'element
-*/
-void DiagramTextItem::setPos(qreal x, qreal y) {
- setPos(QPointF(x, y));
-}
-
-/**
- @return la position du champ de texte
-*/
-QPointF DiagramTextItem::pos() const {
- return(QGraphicsTextItem::pos());
-}
-
-/// Rend le champ de texte non focusable
-void DiagramTextItem::setNonFocusable() {
- setFlag(QGraphicsTextItem::ItemIsFocusable, false);
-}
-
-
-/**
- * @brief DiagramTextItem::setHtmlText
- * @param txt
- */
-void DiagramTextItem::setHtmlText(const QString &txt) {
- setHtml( txt );
-}
-
-/**
- * @brief Edit the text with HtmlEditor
- */
-void DiagramTextItem::edit() {
- //Open the HtmlEditor
- qdesigner_internal::RichTextEditorDialog *editor = new qdesigner_internal::RichTextEditorDialog();
- // connect the in/out
- connect(editor, SIGNAL(applyEditText(const QString &)), this, SLOT(setHtmlText(const QString &)));
- // load the Html txt
- editor->setText( toHtml() );
- // show
- editor->show();
-}
-
Deleted: branches/devel/sources/diagramtextitem.h
===================================================================
--- branches/devel/sources/diagramtextitem.h 2013-11-06 18:44:39 UTC (rev 2595)
+++ branches/devel/sources/diagramtextitem.h 2013-11-07 09:18:03 UTC (rev 2596)
@@ -1,85 +0,0 @@
-/*
- Copyright 2006-2013 The QElectroTech Team
- 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/>.
-*/
-#ifndef DIAGRAM_TEXT_ITEM_H
-#define DIAGRAM_TEXT_ITEM_H
-#include <QtGui>
-#include "diagram.h"
-/**
- This class represents a selectable, movable and editable text field on a
- diagram.
- @see QGraphicsItem::GraphicsItemFlags
-*/
-class DiagramTextItem : public QGraphicsTextItem {
- Q_OBJECT
- // constructors, destructor
- public:
- DiagramTextItem(QGraphicsItem * = 0, Diagram * = 0);
- DiagramTextItem(const QString &, QGraphicsItem * = 0, Diagram * = 0);
- virtual ~DiagramTextItem();
-
- // attributes
- public:
- enum { Type = UserType + 1004 };
-
- // methods
- public:
- /**
- Enable the use of qgraphicsitem_cast to safely cast a QGraphicsItem into a
- DiagramTextItem
- @return the QGraphicsItem type
- */
- virtual int type() const { return Type; }
- Diagram *diagram() const;
- virtual void fromXml(const QDomElement &) = 0;
- virtual QDomElement toXml(QDomDocument &) const = 0;
- virtual void setPos(const QPointF &);
- virtual void setPos(qreal, qreal);
- virtual QPointF pos() const;
- qreal rotationAngle() const;
- void setRotationAngle(const qreal &);
- void rotateBy(const qreal &);
- void edit();
- QPointF mapMovementToScene(const QPointF &) const;
- QPointF mapMovementFromScene(const QPointF &) const;
- QPointF mapMovementToParent(const QPointF &) const;
- QPointF mapMovementFromParent(const QPointF &) const;
-
- protected:
- virtual void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *);
- virtual void focusInEvent(QFocusEvent *);
- virtual void focusOutEvent(QFocusEvent *);
- virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *);
- virtual void applyRotation(const qreal &);
-
- signals:
- /// signal emitted when the text field loses focus
- void lostFocus();
- /// signal emitted after text was changed
- void diagramTextChanged(DiagramTextItem *, const QString &, const QString &);
-
- public slots:
- void setNonFocusable();
- void setHtmlText(const QString &);
-
- private:
- /// Previous text value
- QString previous_text_;
- /// angle of rotation of the text field
- qreal rotation_angle_;
-};
-#endif
Modified: branches/devel/sources/diagramview.cpp
===================================================================
--- branches/devel/sources/diagramview.cpp 2013-11-06 18:44:39 UTC (rev 2595)
+++ branches/devel/sources/diagramview.cpp 2013-11-07 09:18:03 UTC (rev 2596)
@@ -17,15 +17,15 @@
*/
#include "diagramview.h"
#include "diagram.h"
-#include "customelement.h"
-#include "ghostelement.h"
-#include "conductor.h"
+#include "qetgraphicsitem/customelement.h"
+#include "qetgraphicsitem/ghostelement.h"
+#include "qetgraphicsitem/conductor.h"
#include "diagramcommands.h"
#include "diagramposition.h"
#include "conductorpropertieswidget.h"
-#include "conductortextitem.h"
-#include "elementtextitem.h"
-#include "independenttextitem.h"
+#include "qetgraphicsitem/conductortextitem.h"
+#include "qetgraphicsitem/elementtextitem.h"
+#include "qetgraphicsitem/independenttextitem.h"
#include "qetgraphicsitem/diagramimageitem.h"
#include "titleblockpropertieswidget.h"
#include "templatelocation.h"
Modified: branches/devel/sources/editor/customelementpart.cpp
===================================================================
--- branches/devel/sources/editor/customelementpart.cpp 2013-11-06 18:44:39 UTC (rev 2595)
+++ branches/devel/sources/editor/customelementpart.cpp 2013-11-07 09:18:03 UTC (rev 2596)
@@ -16,7 +16,7 @@
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
*/
#include "customelementpart.h"
-#include "customelement.h"
+#include "qetgraphicsitem/customelement.h"
#include "qetelementeditor.h"
/// @return le QETElementEditor auquel cet editeur appartient
Deleted: branches/devel/sources/element.cpp
===================================================================
--- branches/devel/sources/element.cpp 2013-11-06 18:44:39 UTC (rev 2595)
+++ branches/devel/sources/element.cpp 2013-11-07 09:18:03 UTC (rev 2596)
@@ -1,529 +0,0 @@
-/*
- Copyright 2006-2013 The QElectroTech Team
- 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/>.
-*/
-#include "element.h"
-#include "qetapp.h"
-#include "diagram.h"
-#include "conductor.h"
-#include "elementtextitem.h"
-#include "diagramcommands.h"
-#include <QtDebug>
-
-/**
- Constructeur pour un element sans scene ni parent
-*/
-Element::Element(QGraphicsItem *parent, Diagram *scene) :
- QObject(),
- QGraphicsItem(parent, scene),
- internal_connections_(false),
- must_highlight_(false),
- first_move_(true)
-{
- setZValue(10);
-}
-
-/**
- Destructeur
-*/
-Element::~Element() {
-}
-
-/**
- @return true si l'element est mis en evidence
-*/
-bool Element::isHighlighted() const {
- return(must_highlight_);
-}
-
-/**
- @param hl true pour mettre l'element en evidence, false sinon
-*/
-void Element::setHighlighted(bool hl) {
- must_highlight_ = hl;
- update();
-}
-
-/**
- Methode principale de dessin de l'element
- @param painter Le QPainter utilise pour dessiner l'elment
- @param options Les options de style a prendre en compte
- @param widget Le widget sur lequel on dessine
-*/
-void Element::paint(QPainter *painter, const QStyleOptionGraphicsItem *options, QWidget *widget) {
-
-#ifndef Q_WS_WIN
- // corrige un bug de rendu ne se produisant que lors du rendu sur QGraphicsScene sous X11 au zoom par defaut
- static bool must_correct_rendering_bug = QETApp::settings().value("correct-rendering", false).toBool();
- if (must_correct_rendering_bug) {
- Diagram *dia = diagram();
- if (dia && options -> levelOfDetail == 1.0 && widget) {
- // calcule la rotation qu'a subi l'element
- qreal applied_rotation = 90.0 * (ori.current() - ori.defaultOrientation());
- while (applied_rotation < 360.0) applied_rotation += 360.0;
- while (applied_rotation > 360.0) applied_rotation -= 360.0;
- if (applied_rotation == 90.0) painter -> translate(1.0, -1.0);
- else if (applied_rotation == 180.0) painter -> translate(-1.0, -1.0);
- else if (applied_rotation == 270.0) painter -> translate(-1.0, 1.0);
- }
- }
-#endif
- if (must_highlight_) drawHighlight(painter, options);
-
- // Dessin de l'element lui-meme
- paint(painter, options);
-
- // Dessin du cadre de selection si necessaire
- if (isSelected()) drawSelection(painter, options);
-}
-
-/**
- @return Le rectangle delimitant le contour de l'element
-*/
-QRectF Element::boundingRect() const {
- return(QRectF(QPointF(-hotspot_coord.x(), -hotspot_coord.y()), dimensions));
-}
-
-/**
- Definit la taille de l'element sur le schema. Les tailles doivent etre
- des multiples de 10 ; si ce n'est pas le cas, les dimensions indiquees
- seront arrrondies aux dizaines superieures.
- @param wid Largeur de l'element
- @param hei Hauteur de l'element
- @return La taille finale de l'element
-*/
-QSize Element::setSize(int wid, int hei) {
- prepareGeometryChange();
- // chaque dimension indiquee est arrondie a la dizaine superieure
- while (wid % 10) ++ wid;
- while (hei % 10) ++ hei;
- // les dimensions finales sont conservees et retournees
- return(dimensions = QSize(wid, hei));
-}
-
-/**
- @return la taille de l'element sur le schema
-*/
-QSize Element::size() const {
- return(dimensions);
-}
-
-/**
- Definit le hotspot de l'element par rapport au coin superieur gauche de son rectangle delimitant.
- Necessite que la taille ait deja ete definie
- @param hs Coordonnees du hotspot
-*/
-QPoint Element::setHotspot(QPoint hs) {
- // la taille doit avoir ete definie
- prepareGeometryChange();
- if (dimensions.isNull()) hotspot_coord = QPoint(0, 0);
- else {
- // les coordonnees indiquees ne doivent pas depasser les dimensions de l'element
- int hsx = qMin(hs.x(), dimensions.width());
- int hsy = qMin(hs.y(), dimensions.height());
- hotspot_coord = QPoint(hsx, hsy);
- }
- return(hotspot_coord);
-}
-
-/**
- @return Le hotspot courant de l'element
-*/
-QPoint Element::hotspot() const {
- return(hotspot_coord);
-}
-
-/**
- Selectionne l'element
-*/
-void Element::select() {
- setSelected(true);
-}
-
-/**
- Deselectionne l'element
-*/
-void Element::deselect() {
- setSelected(false);
-}
-
-/**
- @return La pixmap de l'element
-*/
-QPixmap Element::pixmap() {
- if (preview.isNull()) updatePixmap(); // on genere la pixmap si ce n'est deja fait
- return(preview);
-}
-
-/**
- Permet de specifier l'orientation de l'element
- @param o la nouvelle orientation de l'objet
- @return true si l'orientation a pu etre appliquee, false sinon
-*/
-bool Element::setOrientation(QET::Orientation o) {
- // verifie que l'orientation demandee est acceptee
- if (!ori.accept(o)) return(false);
- prepareGeometryChange();
- // rotation en consequence et rafraichissement de l'element graphique
- qreal rotation_value = 90.0 * (o - ori.current());
- rotate(rotation_value);
- ori.setCurrent(o);
- update();
- foreach(QGraphicsItem *qgi, childItems()) {
- if (Terminal *p = qgraphicsitem_cast<Terminal *>(qgi)) {
- p -> updateConductor();
- }
- }
- return(true);
-}
-
-/*** Methodes protegees ***/
-
-/**
- Dessine un petit repere (axes x et y) relatif a l'element
- @param painter Le QPainter a utiliser pour dessiner les axes
- @param options Les options de style a prendre en compte
-*/
-void Element::drawAxes(QPainter *painter, const QStyleOptionGraphicsItem *options) {
- Q_UNUSED(options);
- painter -> setPen(Qt::blue);
- painter -> drawLine(0, 0, 10, 0);
- painter -> drawLine(7,-3, 10, 0);
- painter -> drawLine(7, 3, 10, 0);
- painter -> setPen(Qt::red);
- painter -> drawLine(0, 0, 0, 10);
- painter -> drawLine(0, 10,-3, 7);
- painter -> drawLine(0, 10, 3, 7);
-}
-
-/*** Methodes privees ***/
-
-/**
- Dessine le cadre de selection de l'element de maniere systematiquement non antialiasee.
- @param painter Le QPainter a utiliser pour dessiner les bornes.
- @param options Les options de style a prendre en compte
- */
-void Element::drawSelection(QPainter *painter, const QStyleOptionGraphicsItem *options) {
- Q_UNUSED(options);
- painter -> save();
- // Annulation des renderhints
- painter -> setRenderHint(QPainter::Antialiasing, false);
- painter -> setRenderHint(QPainter::TextAntialiasing, false);
- painter -> setRenderHint(QPainter::SmoothPixmapTransform, false);
- // Dessin du cadre de selection en gris
- QPen t;
- t.setColor(Qt::gray);
- t.setStyle(Qt::DashDotLine);
- painter -> setPen(t);
- // Le dessin se fait a partir du rectangle delimitant
- painter -> drawRoundRect(boundingRect().adjusted(1, 1, -1, -1), 10, 10);
- painter -> restore();
-}
-
-/**
- Dessine le cadre de selection de l'element de maniere systematiquement non antialiasee.
- @param painter Le QPainter a utiliser pour dessiner les bornes.
- @param options Les options de style a prendre en compte
- */
-void Element::drawHighlight(QPainter *painter, const QStyleOptionGraphicsItem *options) {
- Q_UNUSED(options);
- painter -> save();
-
- qreal gradient_radius = qMin(boundingRect().width(), boundingRect().height()) / 2.0;
- QRadialGradient gradient(
- boundingRect().center(),
- gradient_radius,
- boundingRect().center()
- );
- gradient.setColorAt(0.0, QColor::fromRgb(69, 137, 255, 255));
- gradient.setColorAt(1.0, QColor::fromRgb(69, 137, 255, 0));
- QBrush brush(gradient);
-
- painter -> setPen(Qt::NoPen);
- painter -> setBrush(brush);
- // Le dessin se fait a partir du rectangle delimitant
- painter -> drawRoundRect(boundingRect().adjusted(1, 1, -1, -1), 10, 10);
- painter -> restore();
-}
-
-/**
- Fonction initialisant et dessinant la pixmap de l'element.
-*/
-void Element::updatePixmap() {
- // Pixmap transparente faisant la taille de base de l'element
- preview = QPixmap(dimensions);
- preview.fill(QColor(255, 255, 255, 0));
- // QPainter sur la pixmap, avec antialiasing
- QPainter p(&preview);
- p.setRenderHint(QPainter::Antialiasing, true);
- p.setRenderHint(QPainter::SmoothPixmapTransform, true);
- // Translation de l'origine du repere de la pixmap
- p.translate(hotspot_coord);
- // L'element se dessine sur la pixmap
- paint(&p, 0);
-}
-
-/**
- Change la position de l'element en veillant a ce que l'element
- reste sur la grille du Diagram auquel il appartient.
- @param p Nouvelles coordonnees de l'element
-*/
-void Element::setPos(const QPointF &p) {
- if (p == pos()) return;
- // pas la peine de positionner sur la grille si l'element n'est pas sur un Diagram
- if (scene()) {
- // arrondit l'abscisse a 10 px pres
- int p_x = qRound(p.x() / (Diagram::xGrid * 1.0)) * Diagram::xGrid;
- // arrondit l'ordonnee a 10 px pres
- int p_y = qRound(p.y() / (Diagram::yGrid * 1.0)) * Diagram::yGrid;
- QGraphicsItem::setPos(p_x, p_y);
- } else QGraphicsItem::setPos(p);
-}
-
-/**
- Change la position de l'element en veillant a ce que l'element
- reste sur la grille du Diagram auquel il appartient.
- @param x Nouvelle abscisse de l'element
- @param y Nouvelle ordonnee de l'element
-*/
-void Element::setPos(qreal x, qreal y) {
- setPos(QPointF(x, y));
-}
-
-/**
- Gere le clic sur l'element
- @param e Objet decrivant l'evenement souris
-*/
-void Element::mousePressEvent(QGraphicsSceneMouseEvent *e) {
- first_move_ = true;
- if (e -> modifiers() & Qt::ControlModifier) {
- setSelected(!isSelected());
- }
- QGraphicsItem::mousePressEvent(e);
-}
-
-/**
- Gere les mouvements de souris lies a l'element
- @param e Objet decrivant l'evenement souris
-*/
-void Element::mouseMoveEvent(QGraphicsSceneMouseEvent *e) {
- if (isSelected() && e -> buttons() & Qt::LeftButton) {
- // l'element est en train d'etre deplace
- Diagram *diagram_ptr = diagram();
- if (diagram_ptr) {
- if (first_move_) {
- // il s'agit du premier mouvement du deplacement, on le signale
- // au schema parent
- diagram_ptr -> beginMoveElements(this);
- }
- }
-
- // on applique le mouvement impose par la souris
- QPointF old_pos = pos();
- setPos(mapToParent(e -> pos()) - matrix().map(e -> buttonDownPos(Qt::LeftButton)));
-
- // on calcule le mouvement reellement applique par setPos()
- QPointF effective_movement = pos() - old_pos;
-
- if (diagram_ptr) {
- // on signale le mouvement ainsi applique au schema parent, qui
- // l'appliquera aux autres items selectionnes selon son bon vouloir
- diagram_ptr -> continueMoveElements(effective_movement);
- }
- } else e -> ignore();
-
- if (first_move_) {
- first_move_ = false;
- }
-}
-
-/**
- Gere le relachement de souris
- Cette methode a ete reimplementee pour tenir a jour la liste des elements
- et conducteurs a deplacer au niveau du schema.
-*/
-void Element::mouseReleaseEvent(QGraphicsSceneMouseEvent *e) {
- if (Diagram *diagram_ptr = diagram()) {
- diagram_ptr -> endMoveElements();
- }
-
- if (!(e -> modifiers() & Qt::ControlModifier)) {
- QGraphicsItem::mouseReleaseEvent(e);
- }
-}
-
-/**
- Permet de savoir si un element XML (QDomElement) represente bien un element
- @param e Le QDomElement a valide
- @return true si l'element XML est un Element, false sinon
-*/
-bool Element::valideXml(QDomElement &e) {
- // verifie le nom du tag
- if (e.tagName() != "element") return(false);
-
- // verifie la presence des attributs minimaux
- if (!e.hasAttribute("type")) return(false);
- if (!e.hasAttribute("x")) return(false);
- if (!e.hasAttribute("y")) return(false);
-
- bool conv_ok;
- // parse l'abscisse
- e.attribute("x").toDouble(&conv_ok);
- if (!conv_ok) return(false);
-
- // parse l'ordonnee
- e.attribute("y").toDouble(&conv_ok);
- if (!conv_ok) return(false);
- return(true);
-}
-
-/**
- Methode d'import XML. Cette methode est appelee lors de l'import de contenu
- XML (coller, import, ouverture de fichier...) afin que l'element puisse
- gerer lui-meme l'importation de ses bornes. Ici, comme cette classe est
- caracterisee par un nombre fixe de bornes, l'implementation exige de
- retrouver exactement ses bornes dans le fichier XML.
- @param e L'element XML a analyser.
- @param table_id_adr Reference vers la table de correspondance entre les IDs
- du fichier XML et les adresses en memoire. Si l'import reussit, il faut y
- ajouter les bons couples (id, adresse).
- @return true si l'import a reussi, false sinon
-
-*/
-bool Element::fromXml(QDomElement &e, QHash<int, Terminal *> &table_id_adr, bool handle_inputs_rotation) {
- /*
- les bornes vont maintenant etre recensees pour associer leurs id a leur adresse reelle
- ce recensement servira lors de la mise en place des fils
- */
- QList<QDomElement> liste_terminals;
- foreach(QDomElement qde, QET::findInDomElement(e, "terminals", "terminal")) {
- if (Terminal::valideXml(qde)) liste_terminals << qde;
- }
-
- QHash<int, Terminal *> priv_id_adr;
- int terminals_non_trouvees = 0;
- foreach(QGraphicsItem *qgi, childItems()) {
- if (Terminal *p = qgraphicsitem_cast<Terminal *>(qgi)) {
- bool terminal_trouvee = false;
- foreach(QDomElement qde, liste_terminals) {
- if (p -> fromXml(qde)) {
- priv_id_adr.insert(qde.attribute("id").toInt(), p);
- terminal_trouvee = true;
- // We used to break here, because we did not expect
- // several terminals to share the same position.
- // Of course, it finally happened.
- }
- }
- if (!terminal_trouvee) ++ terminals_non_trouvees;
- }
- }
-
- if (terminals_non_trouvees > 0) {
- return(false);
- } else {
- // verifie que les associations id / adr n'entrent pas en conflit avec table_id_adr
- foreach(int id_trouve, priv_id_adr.keys()) {
- if (table_id_adr.contains(id_trouve)) {
- // cet element possede un id qui est deja reference (= conflit)
- return(false);
- }
- }
- // copie des associations id / adr
- foreach(int id_trouve, priv_id_adr.keys()) {
- table_id_adr.insert(id_trouve, priv_id_adr.value(id_trouve));
- }
- }
-
- // importe les valeurs des champs de texte
- QList<QDomElement> inputs = QET::findInDomElement(e, "inputs", "input");
- foreach(QGraphicsItem *qgi, childItems()) {
- if (ElementTextItem *eti = qgraphicsitem_cast<ElementTextItem *>(qgi)) {
- foreach(QDomElement input, inputs) eti -> fromXml(input);
- }
- }
-
- // position, selection
- setPos(e.attribute("x").toDouble(), e.attribute("y").toDouble());
- setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
-
- // orientation
- bool conv_ok;
- int read_ori = e.attribute("orientation").toInt(&conv_ok);
- if (!conv_ok || read_ori < 0 || read_ori > 3) read_ori = ori.defaultOrientation();
- if (handle_inputs_rotation) {
- RotateElementsCommand::rotateElement(this, (QET::Orientation)read_ori);
- } else {
- setOrientation((QET::Orientation)read_ori);
- }
- return(true);
-}
-
-/**
- Permet d'exporter l'element en XML
- @param document Document XML a utiliser
- @param table_adr_id Table de correspondance entre les adresses des bornes
- et leur id dans la representation XML ; cette table completee par cette
- methode
- @return L'element XML representant cet element electrique
-*/
-QDomElement Element::toXml(QDomDocument &document, QHash<Terminal *, int> &table_adr_id) const {
- QDomElement element = document.createElement("element");
-
- // type
- element.setAttribute("type", typeId());
-
- // position, selection et orientation
- element.setAttribute("x", QString("%1").arg(pos().x()));
- element.setAttribute("y", QString("%1").arg(pos().y()));
- element.setAttribute("orientation", QString("%1").arg(ori.current()));
-
- /* recupere le premier id a utiliser pour les bornes de cet element */
- int id_terminal = 0;
- if (!table_adr_id.isEmpty()) {
- // trouve le plus grand id
- int max_id_t = -1;
- foreach (int id_t, table_adr_id.values()) {
- if (id_t > max_id_t) max_id_t = id_t;
- }
- id_terminal = max_id_t + 1;
- }
-
- // enregistrement des bornes de l'appareil
- QDomElement xml_terminals = document.createElement("terminals");
- // pour chaque enfant de l'element
- foreach(Terminal *t, terminals()) {
- // alors on enregistre la borne
- QDomElement terminal = t -> toXml(document);
- terminal.setAttribute("id", id_terminal);
- table_adr_id.insert(t, id_terminal ++);
- xml_terminals.appendChild(terminal);
- }
- element.appendChild(xml_terminals);
-
- // enregistrement des champ de texte de l'appareil
- QDomElement inputs = document.createElement("inputs");
- foreach(ElementTextItem *eti, texts()) {
- inputs.appendChild(eti -> toXml(document));
- }
- element.appendChild(inputs);
-
- return(element);
-}
-
-/// @return le Diagram auquel cet element appartient, ou 0 si cet element est independant
-Diagram *Element::diagram() const {
- return(qobject_cast<Diagram *>(scene()));
-}
Deleted: branches/devel/sources/element.h
===================================================================
--- branches/devel/sources/element.h 2013-11-06 18:44:39 UTC (rev 2595)
+++ branches/devel/sources/element.h 2013-11-07 09:18:03 UTC (rev 2596)
@@ -1,166 +0,0 @@
-/*
- Copyright 2006-2013 The QElectroTech Team
- 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/>.
-*/
-#ifndef ELEMENT_H
-#define ELEMENT_H
-#include <QtGui>
-#include "terminal.h"
-#include "orientationset.h"
-class Diagram;
-class ElementTextItem;
-/**
- This is the base class for electrical elements.
-*/
-class Element : public QObject, public QGraphicsItem {
-
- Q_OBJECT
- Q_INTERFACES(QGraphicsItem)
-
- // constructors, destructor
- public:
- Element(QGraphicsItem * = 0, Diagram * = 0);
- virtual ~Element();
-
- private:
- Element(const Element &);
-
- // attributes
- public:
- enum { Type = UserType + 1000 };
-
- protected:
- /**
- Hold orientations for the element :
- * allowed orientations
- * current orientation
- * default orientation
- @see OrientationSet
- */
- OrientationSet ori;
-
- private:
- QSize dimensions;
- QPoint hotspot_coord;
- QPixmap preview;
-
- // methods
- public:
- /**
- Enable the use of qgraphicsitem_cast to safely cast a QGraphicsItem into an
- Element.
- @return the QGraphicsItem type
- */
- virtual int type() const { return Type; }
-
- // pure virtual methods to be defined in derived classes
- /// @return the list of terminals for this element
- virtual QList<Terminal *> terminals() const = 0;
- /// @return the list of conductors attached to this element
- virtual QList<Conductor *> conductors() const = 0;
- /// @return the list of text items attached to this element
- virtual QList<ElementTextItem *> texts() const = 0;
- /// @return the current number of terminals of this element
- virtual int terminalsCount() const = 0;
- /// @return the minimum number of terminals for this element
- virtual int minTerminalsCount() const = 0;
- /// @return the maximum number of terminals for this element
- virtual int maxTerminalsCount() const = 0;
- /**
- Draw this element
- */
- virtual void paint(QPainter *, const QStyleOptionGraphicsItem *) = 0;
- /// @return This element type ID
- virtual QString typeId() const = 0;
- /// @return the human name for this element
- virtual QString name() const = 0;
- Diagram *diagram() const;
-
- virtual bool isHighlighted() const;
- virtual void setHighlighted(bool);
- void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *);
- QRectF boundingRect() const;
- QSize setSize(int, int);
- QSize size() const;
- QPixmap pixmap();
-
- // methods related to the hotspot
- QPoint setHotspot(QPoint);
- QPoint hotspot() const;
-
- // selection-related methods
- void select();
- void deselect();
-
- // position-related methods
- void setPos(const QPointF &);
- void setPos(qreal, qreal);
-
- // methods related to internal connections
- bool internalConnections();
- void setInternalConnections(bool);
-
- // methods related to XML import/export
- static bool valideXml(QDomElement &);
- virtual bool fromXml(QDomElement &, QHash<int, Terminal *> &, bool = false);
- virtual QDomElement toXml(QDomDocument &, QHash<Terminal *, int> &) const;
-
- // orientation-related methods
- bool setOrientation(QET::Orientation o);
- const OrientationSet &orientation() const;
-
- protected:
- void drawAxes(QPainter *, const QStyleOptionGraphicsItem *);
- void mousePressEvent(QGraphicsSceneMouseEvent *);
- void mouseMoveEvent(QGraphicsSceneMouseEvent *);
- void mouseReleaseEvent(QGraphicsSceneMouseEvent *);
-
- private:
- bool internal_connections_;
- bool must_highlight_;
- bool first_move_;
- void drawSelection(QPainter *, const QStyleOptionGraphicsItem *);
- void drawHighlight(QPainter *, const QStyleOptionGraphicsItem *);
- void updatePixmap();
-};
-
-/**
- Indicate whether this element allows internal connections, i.e. whether its
- terminals can be linked together using a conductor.
- @return true if internal connections are accepted, false otherwise
-*/
-inline bool Element::internalConnections() {
- return(internal_connections_);
-}
-
-/**
- Specify whether this element allows internal connections, i.e. whether its
- terminals can be linked together using a conductor.
- @return true for internal connections to be accepted, false otherwise
-*/
-inline void Element::setInternalConnections(bool ic) {
- internal_connections_ = ic;
-}
-
-/**
- Indicate the current orientation of this element
- @return the current orientation of this element
-*/
-inline const OrientationSet & Element::orientation() const {
- return(ori);
-}
-
-#endif
Modified: branches/devel/sources/elementscategorieslist.cpp
===================================================================
--- branches/devel/sources/elementscategorieslist.cpp 2013-11-06 18:44:39 UTC (rev 2595)
+++ branches/devel/sources/elementscategorieslist.cpp 2013-11-07 09:18:03 UTC (rev 2596)
@@ -17,7 +17,7 @@
*/
#include "elementscategorieslist.h"
#include "qetapp.h"
-#include "customelement.h"
+#include "qetgraphicsitem/customelement.h"
#include "elementscollection.h"
#include "elementscategory.h"
#include "elementdefinition.h"
Modified: branches/devel/sources/elementscollectioncache.cpp
===================================================================
--- branches/devel/sources/elementscollectioncache.cpp 2013-11-06 18:44:39 UTC (rev 2595)
+++ branches/devel/sources/elementscollectioncache.cpp 2013-11-07 09:18:03 UTC (rev 2596)
@@ -2,7 +2,7 @@
#include "elementscollection.h"
#include "elementscategory.h"
#include "elementdefinition.h"
-#include "customelement.h"
+#include "qetgraphicsitem/customelement.h"
/**
Construct a cache for elements collections.
Modified: branches/devel/sources/elementsmover.cpp
===================================================================
--- branches/devel/sources/elementsmover.cpp 2013-11-06 18:44:39 UTC (rev 2595)
+++ branches/devel/sources/elementsmover.cpp 2013-11-07 09:18:03 UTC (rev 2596)
@@ -16,12 +16,12 @@
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
*/
#include "elementsmover.h"
-#include "conductor.h"
-#include "conductortextitem.h"
+#include "qetgraphicsitem/conductor.h"
+#include "qetgraphicsitem/conductortextitem.h"
#include "diagram.h"
#include "diagramcommands.h"
-#include "element.h"
-#include "independenttextitem.h"
+#include "qetgraphicsitem/element.h"
+#include "qetgraphicsitem/independenttextitem.h"
#include "qetgraphicsitem/diagramimageitem.h"
/**
Modified: branches/devel/sources/elementspanel.cpp
===================================================================
--- branches/devel/sources/elementspanel.cpp 2013-11-06 18:44:39 UTC (rev 2595)
+++ branches/devel/sources/elementspanel.cpp 2013-11-07 09:18:03 UTC (rev 2596)
@@ -21,7 +21,7 @@
#include "diagram.h"
#include "elementscategory.h"
#include "elementscollectioncache.h"
-#include "customelement.h"
+#include "qetgraphicsitem/customelement.h"
#include "fileelementscollection.h"
#include "fileelementdefinition.h"
#include "qeticons.h"
Deleted: branches/devel/sources/elementtextitem.cpp
===================================================================
--- branches/devel/sources/elementtextitem.cpp 2013-11-06 18:44:39 UTC (rev 2595)
+++ branches/devel/sources/elementtextitem.cpp 2013-11-07 09:18:03 UTC (rev 2596)
@@ -1,310 +0,0 @@
-/*
- Copyright 2006-2012 Xavier Guerrin
- 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/>.
-*/
-#include "elementtextitem.h"
-#include "diagram.h"
-#include "diagramcommands.h"
-#include "element.h"
-
-/**
- Constructeur
- @param parent_element Le QGraphicsItem parent du champ de texte
- @param parent_diagram Le schema auquel appartient le champ de texte
-*/
-ElementTextItem::ElementTextItem(Element *parent_element, Diagram *parent_diagram) :
- DiagramTextItem(parent_element, parent_diagram),
- parent_element_(parent_element),
- follow_parent_rotations(false),
- original_rotation_angle_(0.0),
- first_move_(true)
-{
- // par defaut, les DiagramTextItem sont Selectable et Movable
- // cela nous convient, on ne touche pas a ces flags
-
- adjustItemPosition(1);
- // ajuste la position du QGraphicsItem lorsque le QTextDocument change
- connect(document(), SIGNAL(blockCountChanged(int)), this, SLOT(adjustItemPosition(int)));
- connect(document(), SIGNAL(contentsChanged()), this, SLOT(adjustItemPosition()));
-}
-
-/**
- Constructeur
- @param parent_element L'element parent du champ de texte
- @param parent_diagram Le schema auquel appartient le champ de texte
- @param text Le texte affiche par le champ de texte
-*/
-ElementTextItem::ElementTextItem(const QString &text, Element *parent_element, Diagram *parent_diagram) :
- DiagramTextItem(text, parent_element, parent_diagram),
- parent_element_(parent_element),
- follow_parent_rotations(false),
- original_rotation_angle_(0.0),
- first_move_(true)
-{
- // par defaut, les DiagramTextItem sont Selectable et Movable
- // cela nous convient, on ne touche pas a ces flags
-
- adjustItemPosition(1);
- // ajuste la position du QGraphicsItem lorsque le QTextDocument change
- connect(document(), SIGNAL(blockCountChanged(int)), this, SLOT(adjustItemPosition(int)));
- connect(document(), SIGNAL(contentsChanged()), this, SLOT(adjustItemPosition()));
-}
-
-/// Destructeur
-ElementTextItem::~ElementTextItem() {
-}
-
-/**
- @return L'element parent de ce champ de texte, ou 0 si celui-ci n'en a pas.
-*/
-Element *ElementTextItem::parentElement() const {
- return(parent_element_);
-}
-
-/**
- Modifie la position du champ de texte
- @param pos La nouvelle position du champ de texte
-*/
-void ElementTextItem::setPos(const QPointF &pos) {
- QGraphicsTextItem::setPos(pos);
-}
-
-/**
- Modifie la position du champ de texte
- @param x La nouvelle abscisse du champ de texte
- @param y La nouvelle ordonnee du champ de texte
-*/
-void ElementTextItem::setPos(qreal x, qreal y) {
- setPos(QPointF(x, y));
-}
-
-/**
- @return La position (bidouillee) du champ de texte
-*/
-QPointF ElementTextItem::pos() const {
- return(QGraphicsTextItem::pos());
-}
-
-/**
- Permet de lire le texte a mettre dans le champ a partir d'un element XML.
- Cette methode se base sur la position du champ pour assigner ou non la
- valeur a ce champ.
- @param e L'element XML representant le champ de texte
-*/
-void ElementTextItem::fromXml(const QDomElement &e) {
- QPointF _pos = pos();
- if (
- qFuzzyCompare(qreal(e.attribute("x").toDouble()), _pos.x()) &&
- qFuzzyCompare(qreal(e.attribute("y").toDouble()), _pos.y())
- ) {
- setPlainText(e.attribute("text"));
-
- qreal user_pos_x, user_pos_y;
- if (
- QET::attributeIsAReal(e, "userx", &user_pos_x) &&
- QET::attributeIsAReal(e, "usery", &user_pos_y)
- ) {
- setPos(user_pos_x, user_pos_y);
- }
-
- qreal xml_rotation_angle;
- if (QET::attributeIsAReal(e, "userrotation", &xml_rotation_angle)) {
- setRotationAngle(xml_rotation_angle);
- }
- }
-}
-
-/**
- @param document Le document XML a utiliser
- @return L'element XML representant ce champ de texte
-*/
-QDomElement ElementTextItem::toXml(QDomDocument &document) const {
- QDomElement result = document.createElement("input");
-
- result.setAttribute("x", QString("%1").arg(originalPos().x()));
- result.setAttribute("y", QString("%1").arg(originalPos().y()));
-
- if (pos() != originalPos()) {
- result.setAttribute("userx", QString("%1").arg(pos().x()));
- result.setAttribute("usery", QString("%1").arg(pos().y()));
- }
-
- result.setAttribute("text", toPlainText());
-
- if (rotationAngle() != originalRotationAngle()) {
- result.setAttribute("userrotation", QString("%1").arg(rotationAngle()));
- }
-
- return(result);
-}
-
-/**
- @param p Position originale / de reference pour ce champ
- Cette position est utilisee lors de l'export en XML
-*/
-void ElementTextItem::setOriginalPos(const QPointF &p) {
- original_position = p;
-}
-
-/**
- @return la position originale / de reference pour ce champ
-*/
-QPointF ElementTextItem::originalPos() const {
- return(original_position);
-}
-
-/**
- Definit l'angle de rotation original de ce champ de texte
- @param rotation_angle un angle de rotation
-*/
-void ElementTextItem::setOriginalRotationAngle(const qreal &rotation_angle) {
- original_rotation_angle_ = QET::correctAngle(rotation_angle);
-}
-
-/**
- @return l'angle de rotation original de ce champ de texte
-*/
-qreal ElementTextItem::originalRotationAngle() const {
- return(original_rotation_angle_);
-}
-
-/**
- Set the font used to render the text item to \a font.
-*/
-void ElementTextItem::setFont(const QFont &font) {
- DiagramTextItem::setFont(font);
- adjustItemPosition(1);
-}
-
-/**
- Cette methode s'assure que la position de l'ElementTextItem est coherente
- en ajustant :
- * la transformation de base qui permet de considerer que l'origine
- correspond au milieu du bord gauche du champ de texte
- * l'origine utilisee lors des appels a setRotation et setScale
- @param new_block_count Nombre de blocs dans l'ElementTextItem
-*/
-void ElementTextItem::adjustItemPosition(int new_block_count) {
- Q_UNUSED(new_block_count);
- qreal origin_offset = boundingRect().bottom() / 2.0;
-
- QTransform base_translation;
- base_translation.translate(0.0, -origin_offset);
- setTransform(base_translation, false);
- setTransformOriginPoint(0.0, origin_offset);
-}
-
-/**
- Effetue la rotation du texte en elle-meme
- Pour les ElementTextItem, la rotation s'effectue autour du milieu du bord
- gauche du champ de texte.
- @param angle Angle de la rotation a effectuer
-*/
-void ElementTextItem::applyRotation(const qreal &angle) {
- QGraphicsTextItem::setRotation(QGraphicsTextItem::rotation() + angle);
-}
-
-/**
- Gere le clic sur le champ de texte
- @param e Objet decrivant l'evenement souris
-*/
-void ElementTextItem::mousePressEvent(QGraphicsSceneMouseEvent *e) {
- first_move_ = true;
- if (e -> modifiers() & Qt::ControlModifier) {
- setSelected(!isSelected());
- }
- DiagramTextItem::mousePressEvent(e);
-}
-
-/**
- Gere les mouvements de souris lies au champ de texte
- @param e Objet decrivant l'evenement souris
-*/
-void ElementTextItem::mouseMoveEvent(QGraphicsSceneMouseEvent *e) {
- if (textInteractionFlags() & Qt::TextEditable) {
- DiagramTextItem::mouseMoveEvent(e);
- } else if ((flags() & QGraphicsItem::ItemIsMovable) && (e -> buttons() & Qt::LeftButton)) {
- QPointF old_pos = pos();
- /*
- Utiliser e -> pos() directement aurait pour effet de positionner
- l'origine du champ de texte a la position indiquee par le curseur,
- ce qui n'est pas l'effet recherche
- Au lieu de cela, on applique a la position actuelle le vecteur
- definissant le mouvement effectue depuis la derniere position
- cliquee avec le bouton gauche
- */
- QPointF movement = e -> pos() - e -> buttonDownPos(Qt::LeftButton);
-
- /*
- Les methodes pos() et setPos() travaillent toujours avec les
- coordonnees de l'item parent (ou de la scene s'il n'y a pas d'item
- parent). On n'oublie donc pas de mapper le mouvement fraichement
- calcule sur l'item parent avant de l'appliquer.
- */
- QPointF parent_movement = mapMovementToParent(movement);
- setPos(pos() + parent_movement);
-
- Diagram *diagram_ptr = diagram();
- if (diagram_ptr) {
- if (first_move_) {
- // on signale le debut d'un deplacement d'ElementTextItems au schema parent
- int moved_texts_count = diagram_ptr -> beginMoveElementTexts(this);
-
- // s'il n'y a qu'un seul texte deplace, on met en valeur l'element parent
- if (moved_texts_count == 1 && parent_element_) {
- parent_element_ -> setHighlighted(true);
- parent_element_ -> update();
- }
- }
-
- /*
- Comme setPos() n'est pas oblige d'appliquer exactement la
- valeur qu'on lui fournit, on calcule le mouvement reellement
- applique.
- */
- QPointF effective_movement = pos() - old_pos;
- QPointF scene_effective_movement = mapMovementToScene(mapMovementFromParent(effective_movement));
-
- // on applique le mouvement subi aux autres textes a deplacer
- diagram_ptr -> continueMoveElementTexts(scene_effective_movement);
- }
- } else e -> ignore();
-
- if (first_move_) {
- first_move_ = false;
- }
-}
-
-/**
- Gere le relachement de souris
- Cette methode cree un objet d'annulation pour le deplacement
- @param e Objet decrivant l'evenement souris
-*/
-void ElementTextItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *e) {
- if (Diagram *diagram_ptr = diagram()) {
- // on arrete de mettre en valeur l'element parent
- if (parent_element_) {
- if (parent_element_ -> isHighlighted()) {
- parent_element_ -> setHighlighted(false);
- }
- }
-
- diagram_ptr -> endMoveElementTexts();
- }
- if (!(e -> modifiers() & Qt::ControlModifier)) {
- QGraphicsTextItem::mouseReleaseEvent(e);
- }
-}
Deleted: branches/devel/sources/elementtextitem.h
===================================================================
--- branches/devel/sources/elementtextitem.h 2013-11-06 18:44:39 UTC (rev 2595)
+++ branches/devel/sources/elementtextitem.h 2013-11-07 09:18:03 UTC (rev 2596)
@@ -1,96 +0,0 @@
-/*
- Copyright 2006-2012 Xavier Guerrin
- 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/>.
-*/
-#ifndef ELEMENT_TEXT_ITEM_H
-#define ELEMENT_TEXT_ITEM_H
-#include "diagramtextitem.h"
-#include <QtXml>
-class Diagram;
-class Element;
-/**
- This class represents a text item attached to an element. Users can change its
- value, adjust its position (defined relatively to its parent element), and
- direct it to any angle.
-*/
-class ElementTextItem : public DiagramTextItem {
- Q_OBJECT
- // constructors, destructor
- public:
- ElementTextItem(Element * = 0, Diagram * = 0);
- ElementTextItem(const QString &, Element * = 0, Diagram * = 0);
- virtual ~ElementTextItem();
-
- // attributes
- public:
- enum { Type = UserType + 1003 };
-
- private:
- Element *parent_element_;
- bool follow_parent_rotations;
- QPointF original_position;
- qreal original_rotation_angle_;
- bool first_move_;
-
- // methods
- public:
- virtual int type() const { return Type; }
- Element *parentElement() const;
- /// @return the rectangle defining the bounds of this text item
- virtual QRectF boundingRect() const { return(QGraphicsTextItem::boundingRect().adjusted(0.0, -1.1, 0.0, 0.0)); }
- bool followParentRotations() const;
- void setFollowParentRotations(bool);
- void fromXml(const QDomElement &);
- QDomElement toXml(QDomDocument &) const;
- void setPos(const QPointF &);
- void setPos(qreal, qreal);
- virtual QPointF pos() const;
- void setOriginalPos(const QPointF &);
- QPointF originalPos() const;
- void setOriginalRotationAngle(const qreal &);
- qreal originalRotationAngle() const;
- virtual void setFont(const QFont &);
-
- public slots:
- void adjustItemPosition(int = 0);
-
- protected:
- virtual void applyRotation(const qreal &);
- virtual void mousePressEvent(QGraphicsSceneMouseEvent *);
- virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *);
- virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *);
-};
-
-/**
- Element text items can optionally be applied a counter-rotation when their
- parent element is rotated, thus preserving their readability.
- @return whether this text item follows the rotations of its parent element.
-*/
-inline bool ElementTextItem::followParentRotations() const {
- return(follow_parent_rotations);
-}
-
-/**
- Element text items can optionally be applied a counter-rotation when their
- parent element is rotated, thus preserving their readability.
- @param frp whether this text item should follow the rotations of its parent
- element.
-*/
-inline void ElementTextItem::setFollowParentRotations(bool frp) {
- follow_parent_rotations = frp;
-}
-
-#endif
Modified: branches/devel/sources/elementtextsmover.cpp
===================================================================
--- branches/devel/sources/elementtextsmover.cpp 2013-11-06 18:44:39 UTC (rev 2595)
+++ branches/devel/sources/elementtextsmover.cpp 2013-11-07 09:18:03 UTC (rev 2596)
@@ -16,12 +16,12 @@
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
*/
#include "elementtextsmover.h"
-#include "conductor.h"
-#include "elementtextitem.h"
+#include "qetgraphicsitem/conductor.h"
+#include "qetgraphicsitem/elementtextitem.h"
#include "diagram.h"
#include "diagramcommands.h"
-#include "element.h"
-#include "independenttextitem.h"
+#include "qetgraphicsitem/element.h"
+#include "qetgraphicsitem/independenttextitem.h"
/**
Constructeur
Deleted: branches/devel/sources/fixedelement.cpp
===================================================================
--- branches/devel/sources/fixedelement.cpp 2013-11-06 18:44:39 UTC (rev 2595)
+++ branches/devel/sources/fixedelement.cpp 2013-11-07 09:18:03 UTC (rev 2596)
@@ -1,43 +0,0 @@
-/*
- Copyright 2006-2012 Xavier Guerrin
- 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/>.
-*/
-#include "fixedelement.h"
-/**
- Constructeur
-*/
-FixedElement::FixedElement(QGraphicsItem *parent, Diagram *scene) : Element(parent, scene) {
-}
-
-/**
- Destructeur
-*/
-FixedElement::~FixedElement() {
-}
-
-/**
- @return Le nombre minimal de bornes que l'element peut avoir
-*/
-int FixedElement::minTerminalsCount() const {
- return(terminalsCount());
-}
-
-/**
- @return Le nombre maximal de bornes que l'element peut avoir
-*/
-int FixedElement::maxTerminalsCount() const {
- return(terminalsCount());
-}
Deleted: branches/devel/sources/fixedelement.h
===================================================================
--- branches/devel/sources/fixedelement.h 2013-11-06 18:44:39 UTC (rev 2595)
+++ branches/devel/sources/fixedelement.h 2013-11-07 09:18:03 UTC (rev 2596)
@@ -1,42 +0,0 @@
-/*
- Copyright 2006-2012 Xavier Guerrin
- 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/>.
-*/
-#ifndef ELEMENTFIXE_H
-#define ELEMENTFIXE_H
-#include "element.h"
-/**
- This class represents an element having a fixed number of terminals.
-*/
-class FixedElement : public Element {
-
- Q_OBJECT
-
- // constructors, destructor
- public:
- FixedElement(QGraphicsItem * = 0, Diagram * = 0);
- virtual ~FixedElement();
-
- // methods
- public:
- int minTerminalsCount() const;
- int maxTerminalsCount() const;
- virtual int terminalsCount() const = 0;
- virtual void paint(QPainter *, const QStyleOptionGraphicsItem *) = 0;
- virtual QString typeId() const = 0;
- virtual QString name() const = 0;
-};
-#endif
Deleted: branches/devel/sources/ghostelement.cpp
===================================================================
--- branches/devel/sources/ghostelement.cpp 2013-11-06 18:44:39 UTC (rev 2595)
+++ branches/devel/sources/ghostelement.cpp 2013-11-07 09:18:03 UTC (rev 2596)
@@ -1,191 +0,0 @@
-/*
- Copyright 2006-2012 Xavier Guerrin
- 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/>.
-*/
-#include "ghostelement.h"
-#include "qet.h"
-#include "terminal.h"
-#include "elementtextitem.h"
-#include "diagramcommands.h"
-
-/**
- Constructeur
- @param location Emplacement de la definition d'element a utiliser
- @param qgi Le QGraphicsItem parent de cet element
- @param d Le schema affichant cet element
-*/
-GhostElement::GhostElement(
- const ElementsLocation &location,
- QGraphicsItem *qgi,
- Diagram *d
-) :
- CustomElement(location, qgi, d)
-{
- QString tooltip_string = QString(
- tr("<u>\311l\351ment manquant\240:</u> %1")
- ).arg(location_.toString());
- setToolTip(tooltip_string);
-}
-
-/**
- Destructeur
-*/
-GhostElement::~GhostElement() {
-}
-
-
-/**
- @param e L'element XML a analyser.
- @param table_id_adr Reference vers la table de correspondance entre les IDs
- du fichier XML et les adresses en memoire. Si l'import reussit, il faut y
- ajouter les bons couples (id, adresse).
- @return true si l'import a reussi, false sinon
-*/
-bool GhostElement::fromXml(QDomElement &e, QHash<int, Terminal *> &table_id_adr, bool handle_inputs_rotation) {
- // instancie les bornes decrites dans l'element XML
- terminalsFromXml(e, table_id_adr);
-
- // instancie les champs de texte decrits dans l'element XML
- foreach(QDomElement qde, QET::findInDomElement(e, "inputs", "input")) {
- qde.setAttribute("size", 9); // arbitraire
- if (ElementTextItem *new_input = CustomElement::parseInput(qde)) {
- new_input -> fromXml(qde);
- }
- qde.removeAttribute("size");
- }
-
- /*
- maintenant que l'element fantome connait toutes les bornes et tous les
- champs de texte, on peut determiner une taille appropriee
- */
- QRect final_bounding_rect = minimalBoundingRect().united(childrenBoundingRect()).toAlignedRect();
- setSize(final_bounding_rect.width(), final_bounding_rect.height());
- setHotspot(QPoint() - final_bounding_rect.topLeft());
- setInternalConnections(true);
-
- // on peut desormais confectionner le rendu de l'element
- generateDrawings();
-
- // position, selection
- setPos(e.attribute("x").toDouble(), e.attribute("y").toDouble());
- setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
-
- // orientation
- bool conv_ok;
- int read_ori = e.attribute("orientation").toInt(&conv_ok);
- if (!conv_ok || read_ori < 0 || read_ori > 3) read_ori = ori.defaultOrientation();
- if (handle_inputs_rotation) {
- RotateElementsCommand::rotateElement(this, (QET::Orientation)read_ori);
- } else {
- setOrientation((QET::Orientation)read_ori);
- }
- return(true);
-}
-
-/**
- @return le bounding rect minimum, utilise si l'element fantome n'a ni champ
- de texte ni borne.
-*/
-QRectF GhostElement::minimalBoundingRect() const {
- return(
- QRectF(
- QPointF(-10.0, -10.0),
- QSizeF(20.0, 20.0)
- )
- );
-}
-
-/**
- Gere l'import des bornes
- @param e L'element XML a analyser.
- @param table_id_adr Reference vers la table de correspondance entre les IDs
- du fichier XML et les adresses en memoire. Si l'import reussit, il faut y
- ajouter les bons couples (id, adresse).
- @return true si l'import a reussi, false sinon
-*/
-bool GhostElement::terminalsFromXml(QDomElement &e, QHash<int, Terminal *> &table_id_adr) {
- // instancie les bornes decrites dans l'element XML
- foreach(QDomElement qde, QET::findInDomElement(e, "terminals", "terminal")) {
- if (!Terminal::valideXml(qde)) continue;
-
- // modifie certains attributs pour que l'analyse par la classe CustomElement reussisse
- int previous_x_value = qde.attribute("x").toInt();
- int previous_y_value = qde.attribute("y").toInt();
- int previous_ori_value = qde.attribute("orientation").toInt();
-
- qreal x_add = 0.0, y_add = 0.0;
- if (previous_ori_value == QET::North) y_add = -Terminal::terminalSize;
- else if (previous_ori_value == QET::East) x_add = Terminal::terminalSize;
- else if (previous_ori_value == QET::South) y_add = Terminal::terminalSize;
- else if (previous_ori_value == QET::West) x_add = -Terminal::terminalSize;
- qde.setAttribute("x", previous_x_value + x_add);
- qde.setAttribute("y", previous_y_value + y_add);
- qde.setAttribute("orientation", QET::orientationToString(static_cast<QET::Orientation>(previous_ori_value)));
-
- if (Terminal *new_terminal = CustomElement::parseTerminal(qde)) {
- table_id_adr.insert(qde.attribute("id").toInt(), new_terminal);
- }
-
- // restaure les attributs modifies
- qde.setAttribute("x", previous_x_value);
- qde.setAttribute("y", previous_y_value);
- qde.setAttribute("orientation", previous_ori_value);
- }
- return(true);
-}
-
-/**
- Genere les rendus de l'element fantome : il s'agit d'un rectangle
- representant grosso modo l'espace que devait prendre l'element initial.
- En son centre est dessine un point d'interrogation. Une petite croix indique
- le point de saisie de l'element.
-*/
-void GhostElement::generateDrawings() {
- // style de dessin
- QPen t(QBrush(Qt::black), 1.0);
-
- // rendu normal
- QPainter qp;
- qp.begin(&drawing);
- qp.setPen(t);
- qp.setRenderHint(QPainter::Antialiasing, false);
- generateDrawing(&qp);
- qp.end();
-
- // rendu low_zoom
- QPainter low_zoom_qp;
- low_zoom_qp.begin(&low_zoom_drawing);
- t.setCosmetic(true);
- low_zoom_qp.setRenderHint(QPainter::Antialiasing, false);
- low_zoom_qp.setPen(t);
- generateDrawing(&low_zoom_qp);
- low_zoom_qp.end();
-}
-
-/**
- Genere un rendu de l'element fantome
- @see generateDrawings
-*/
-void GhostElement::generateDrawing(QPainter *painter) {
- // une petite croix indique le point de saisie de l'element
- painter -> drawLine(QLineF(-1.0, 0.0, 1.0, 0.0));
- painter -> drawLine(QLineF(0.0, -1.0, 0.0, 1.0));
-
- // rectangle avec un point d'interrogation au centre
- QRectF drawn_rect = boundingRect().adjusted(4.0, 4.0, -4.0, -4.0);
- painter -> drawRect(drawn_rect);
- painter -> drawText(drawn_rect, Qt::AlignHCenter | Qt::AlignVCenter, "?");
-}
Deleted: branches/devel/sources/ghostelement.h
===================================================================
--- branches/devel/sources/ghostelement.h 2013-11-06 18:44:39 UTC (rev 2595)
+++ branches/devel/sources/ghostelement.h 2013-11-07 09:18:03 UTC (rev 2596)
@@ -1,53 +0,0 @@
-/*
- Copyright 2006-2012 Xavier Guerrin
- 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/>.
-*/
-#ifndef GHOST_ELEMENT_H
-#define GHOST_ELEMENT_H
-#include "customelement.h"
-class Diagram;
-class QGraphicsItem;
-class ElementsLocation;
-class Terminal;
-/**
- The GhostElement class inherits CustomElement. A GhostElement aims at
- visually replacing a CustomElement whose definition could not be loaded.
- This way, instead of not loading an element, thus potentially losing its
- position, its orientation, its child text items and conductors, one can
- substitute a GhostElement. The GhostElement will extrapolate the position
- of terminals and text items from the rest of the diagram. It is visually
- rendered using a simple rectangle.
-*/
-class GhostElement : public CustomElement {
-
- Q_OBJECT
-
- // constructor, destructor
- public:
- GhostElement(const ElementsLocation &, QGraphicsItem * = 0, Diagram * = 0);
- virtual ~GhostElement();
-
- // methods
- public:
- virtual bool fromXml(QDomElement &, QHash<int, Terminal *> &, bool = false);
-
- protected:
- QRectF minimalBoundingRect() const;
- bool terminalsFromXml(QDomElement &, QHash<int, Terminal *> &);
- void generateDrawings();
- void generateDrawing(QPainter *);
-};
-#endif
Deleted: branches/devel/sources/independenttextitem.cpp
===================================================================
--- branches/devel/sources/independenttextitem.cpp 2013-11-06 18:44:39 UTC (rev 2595)
+++ branches/devel/sources/independenttextitem.cpp 2013-11-07 09:18:03 UTC (rev 2596)
@@ -1,140 +0,0 @@
-/*
- Copyright 2006-2012 Xavier Guerrin
- 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/>.
-*/
-#include "independenttextitem.h"
-#include "diagram.h"
-
-/**
- Constructeur
- @param parent_diagram Le schema auquel est rattache le champ de texte
-*/
-IndependentTextItem::IndependentTextItem(Diagram *parent_diagram) :
- DiagramTextItem(0, parent_diagram),
- first_move_(true)
-{
-}
-
-/**
- Constructeur
- @param text Le texte affiche par le champ de texte
- @param parent_diagram Le schema auquel est rattache le champ de texte
-*/
-IndependentTextItem::IndependentTextItem(const QString &text, Diagram *parent_diagram) :
- DiagramTextItem(text, 0, parent_diagram),
- first_move_(true)
-{
-}
-
-/// Destructeur
-IndependentTextItem::~IndependentTextItem() {
-}
-
-/**
- Permet de lire le texte a mettre dans le champ a partir d'un element XML.
- Cette methode se base sur la position du champ pour assigner ou non la
- valeur a ce champ.
- @param e L'element XML representant le champ de texte
-*/
-void IndependentTextItem::fromXml(const QDomElement &e) {
- setPos(e.attribute("x").toDouble(), e.attribute("y").toDouble());
- setHtml(e.attribute("text"));
- setRotationAngle(e.attribute("rotation").toDouble());
-}
-
-/**
- @param document Le document XML a utiliser
- @return L'element XML representant ce champ de texte
-*/
-QDomElement IndependentTextItem::toXml(QDomDocument &document) const {
- QDomElement result = document.createElement("input");
- result.setAttribute("x", QString("%1").arg(pos().x()));
- result.setAttribute("y", QString("%1").arg(pos().y()));
- result.setAttribute("text", toHtml());
- if (rotationAngle()) {
- result.setAttribute("rotation", QString("%1").arg(rotationAngle()));
- }
- return(result);
-}
-
-/**
- Gere le clic sur le champ de texte
- @param e Objet decrivant l'evenement souris
-*/
-void IndependentTextItem::mousePressEvent(QGraphicsSceneMouseEvent *e) {
- first_move_ = true;
- if (e -> modifiers() & Qt::ControlModifier) {
- setSelected(!isSelected());
- }
- DiagramTextItem::mousePressEvent(e);
-}
-
-/**
- Gere les mouvements de souris lies au champ de texte
- @param e Objet decrivant l'evenement souris
-*/
-void IndependentTextItem::mouseMoveEvent(QGraphicsSceneMouseEvent *e) {
- if (textInteractionFlags() & Qt::TextEditable) {
- DiagramTextItem::mouseMoveEvent(e);
- } else if ((flags() & QGraphicsItem::ItemIsMovable) && isSelected() && (e -> buttons() & Qt::LeftButton)) {
- // le champ de texte est en train d'etre deplace
- Diagram *diagram_ptr = diagram();
- if (diagram_ptr) {
- if (first_move_) {
- // il s'agit du premier mouvement du deplacement, on le signale
- // au schema parent
- diagram_ptr -> beginMoveElements(this);
- }
- }
-
- // on applique le mouvement impose par la souris
- QPointF old_pos = pos();
- if (first_move_) {
- mouse_to_origin_movement_ = old_pos - e -> buttonDownScenePos(Qt::LeftButton);
- }
- QPointF expected_pos = e-> scenePos() + mouse_to_origin_movement_;
- setPos(expected_pos); // setPos() will snap the expected position to the grid
-
- // on calcule le mouvement reellement applique par setPos()
- QPointF effective_movement = pos() - old_pos;
- if (diagram_ptr) {
- // on signale le mouvement ainsi applique au schema parent, qui
- // l'appliquera aux autres items selectionnes selon son bon vouloir
- diagram_ptr -> continueMoveElements(effective_movement);
- }
- } else e -> ignore();
-
- if (first_move_) {
- first_move_ = false;
- }
-}
-
-/**
- Gere le relachement de souris
- Cette methode a ete reimplementee pour tenir a jour la liste des elements
- et conducteurs a deplacer au niveau du schema.
- @param e Objet decrivant l'evenement souris
-*/
-void IndependentTextItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *e) {
- if (flags() & QGraphicsItem::ItemIsMovable) {
- if (Diagram *diagram_ptr = diagram()) {
- diagram_ptr -> endMoveElements();
- }
- }
- if (!(e -> modifiers() & Qt::ControlModifier)) {
- DiagramTextItem::mouseReleaseEvent(e);
- }
-}
Deleted: branches/devel/sources/independenttextitem.h
===================================================================
--- branches/devel/sources/independenttextitem.h 2013-11-06 18:44:39 UTC (rev 2595)
+++ branches/devel/sources/independenttextitem.h 2013-11-07 09:18:03 UTC (rev 2596)
@@ -1,58 +0,0 @@
-/*
- Copyright 2006-2012 Xavier Guerrin
- 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/>.
-*/
-#ifndef INDEPENDENT_TEXT_ITEM_H
-#define INDEPENDENT_TEXT_ITEM_H
-#include <QtGui>
-#include "diagramtextitem.h"
-/**
- This class represents an independent text field on a particular diagram.
- It may be moved, edited, and rotated.
-*/
-class IndependentTextItem : public DiagramTextItem {
- Q_OBJECT
- // constructors, destructor
- public:
- IndependentTextItem(Diagram * = 0);
- IndependentTextItem(const QString &, Diagram* = 0);
- virtual ~IndependentTextItem();
-
- // attributes
- public:
- enum { Type = UserType + 1005 };
-
- // methods
- public:
- /**
- Enable the use of qgraphicsitem_cast to safely cast a QGraphicsItem into an
- IndependentTextItem.
- @return le type de QGraphicsItem
- */
- virtual int type() const { return Type; }
- virtual void fromXml(const QDomElement &);
- virtual QDomElement toXml(QDomDocument &) const;
-
- protected:
- virtual void mousePressEvent(QGraphicsSceneMouseEvent *);
- virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *);
- virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *);
-
- private:
- bool first_move_;
- QPointF mouse_to_origin_movement_;
-};
-#endif
Modified: branches/devel/sources/newelementwizard.cpp
===================================================================
--- branches/devel/sources/newelementwizard.cpp 2013-11-06 18:44:39 UTC (rev 2595)
+++ branches/devel/sources/newelementwizard.cpp 2013-11-07 09:18:03 UTC (rev 2596)
@@ -21,7 +21,7 @@
#include "elementscategorieslist.h"
#include "nameslistwidget.h"
#include "orientationsetwidget.h"
-#include "element.h"
+#include "qetgraphicsitem/element.h"
#include "qetelementeditor.h"
#include "qet.h"
#include "qetapp.h"
Modified: branches/devel/sources/nomenclature.h
===================================================================
--- branches/devel/sources/nomenclature.h 2013-11-06 18:44:39 UTC (rev 2595)
+++ branches/devel/sources/nomenclature.h 2013-11-07 09:18:03 UTC (rev 2596)
@@ -22,9 +22,9 @@
#include "qetproject.h"
#include "diagram.h"
-#include "element.h"
+#include "qetgraphicsitem/element.h"
#include "diagramcontent.h"
-#include "customelement.h"
+#include "qetgraphicsitem/customelement.h"
class QETProject;
class Diagram;
Modified: branches/devel/sources/qetdiagrameditor.cpp
===================================================================
--- branches/devel/sources/qetdiagrameditor.cpp 2013-11-06 18:44:39 UTC (rev 2595)
+++ branches/devel/sources/qetdiagrameditor.cpp 2013-11-07 09:18:03 UTC (rev 2596)
@@ -20,10 +20,10 @@
#include "diagramcontent.h"
#include "diagramview.h"
#include "diagram.h"
-#include "element.h"
+#include "qetgraphicsitem/element.h"
#include "elementspanelwidget.h"
#include "conductorpropertieswidget.h"
-#include "customelement.h"
+#include "qetgraphicsitem/customelement.h"
#include "qetproject.h"
#include "projectview.h"
#include "recentfiles.h"
Added: branches/devel/sources/qetgraphicsitem/conductor.cpp
===================================================================
--- branches/devel/sources/qetgraphicsitem/conductor.cpp (rev 0)
+++ branches/devel/sources/qetgraphicsitem/conductor.cpp 2013-11-07 09:18:03 UTC (rev 2596)
@@ -0,0 +1,1631 @@
+/*
+ Copyright 2006-2013 The QElectroTech Team
+ 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/>.
+*/
+#include <QtDebug>
+#include "conductor.h"
+#include "conductorsegment.h"
+#include "conductorsegmentprofile.h"
+#include "conductortextitem.h"
+#include "element.h"
+#include "diagram.h"
+#include "diagramcommands.h"
+#include "conductorautonumerotation.h"
+#define PR(x) qDebug() << #x " = " << x;
+
+bool Conductor::pen_and_brush_initialized = false;
+QPen Conductor::conductor_pen = QPen();
+QBrush Conductor::conductor_brush = QBrush();
+QBrush Conductor::square_brush = QBrush(Qt::darkGreen);
+/**
+ Constructeur
+ @param p1 Premiere Borne a laquelle le conducteur est lie
+ @param p2 Seconde Borne a laquelle le conducteur est lie
+ @param parent_diagram QGraphicsScene a laquelle appartient le conducteur
+*/
+Conductor::Conductor(Terminal *p1, Terminal* p2, Diagram *parent_diagram) :
+ QObject(),
+ QGraphicsPathItem(0, parent_diagram),
+ terminal1(p1),
+ terminal2(p2),
+ destroyed_(false),
+ text_item(0),
+ segments(NULL),
+ moving_point(false),
+ moving_segment(false),
+ modified_path(false),
+ has_to_save_profile(false),
+ segments_squares_scale_(1.0),
+ must_highlight_(Conductor::None)
+{
+ //set Zvalue at 9 to be upper than the DiagramImageItem and bottom of element(10)
+ setZValue(9);
+ previous_z_value = zValue();
+
+ // ajout du conducteur a la liste de conducteurs de chacune des deux bornes
+ bool ajout_p1 = terminal1 -> addConductor(this);
+ bool ajout_p2 = terminal2 -> addConductor(this);
+
+ // en cas d'echec de l'ajout (conducteur deja existant notamment)
+ if (!ajout_p1 || !ajout_p2) return;
+
+ // attributs de dessin par defaut (communs a tous les conducteurs)
+ if (!pen_and_brush_initialized) {
+ conductor_pen.setJoinStyle(Qt::MiterJoin);
+ conductor_pen.setCapStyle(Qt::SquareCap);
+ conductor_pen.setColor(Qt::black);
+ conductor_pen.setStyle(Qt::SolidLine);
+ conductor_pen.setWidthF(1.0);
+ conductor_brush.setColor(Qt::white);
+ conductor_brush.setStyle(Qt::NoBrush);
+ pen_and_brush_initialized = true;
+ }
+
+ // par defaut, les 4 profils sont des profils nuls = il faut utiliser priv_calculeConductor
+ conductor_profiles.insert(Qt::TopLeftCorner, ConductorProfile());
+ conductor_profiles.insert(Qt::TopRightCorner, ConductorProfile());
+ conductor_profiles.insert(Qt::BottomLeftCorner, ConductorProfile());
+ conductor_profiles.insert(Qt::BottomRightCorner, ConductorProfile());
+
+ // calcul du rendu du conducteur
+ generateConductorPath(terminal1 -> dockConductor(), terminal1 -> orientation(), terminal2 -> dockConductor(), terminal2 -> orientation());
+ setFlags(QGraphicsItem::ItemIsSelectable);
+ setAcceptsHoverEvents(true);
+
+ // ajout du champ de texte editable
+ text_item = new ConductorTextItem(properties_.text, this);
+ calculateTextItemPosition();
+ connect(
+ text_item,
+ SIGNAL(diagramTextChanged(DiagramTextItem *, const QString &, const QString &)),
+ this,
+ SLOT(displayedTextChanged())
+ );
+}
+
+/**
+ Destructeur
+ Detruit le conducteur ainsi que ses segments. Il ne detruit pas les bornes
+ mais s'en detache
+*/
+Conductor::~Conductor() {
+ // se detache des bornes
+ if (!isDestroyed()) destroy();
+
+ // supprime les segments
+ deleteSegments();
+}
+
+/**
+ Met a jour la representation graphique du conducteur en recalculant son
+ trace. Cette fonction est typiquement appelee lorsqu'une seule des bornes du
+ conducteur a change de position.
+ @param rect Rectangle a mettre a jour
+ @see QGraphicsPathItem::update()
+*/
+void Conductor::updatePath(const QRectF &rect) {
+ QPointF p1, p2;
+ p1 = terminal1 -> dockConductor();
+ p2 = terminal2 -> dockConductor();
+ if (segmentsCount() && !conductor_profiles[currentPathType()].isNull())
+ updateConductorPath(p1, terminal1 -> orientation(), p2, terminal2 -> orientation());
+ else
+ generateConductorPath(p1, terminal1 -> orientation(), p2, terminal2 -> orientation());
+ calculateTextItemPosition();
+ QGraphicsPathItem::update(rect);
+}
+
+/**
+ Genere le QPainterPath a partir de la liste des points
+*/
+void Conductor::segmentsToPath() {
+ // chemin qui sera dessine
+ QPainterPath path;
+
+ // s'il n'y a pa des segments, on arrete la
+ if (segments == NULL) setPath(path);
+
+ // demarre le chemin
+ path.moveTo(segments -> firstPoint());
+
+ // parcourt les segments pour dessiner le chemin
+ ConductorSegment *segment = segments;
+ while(segment -> hasNextSegment()) {
+ path.lineTo(segment -> secondPoint());
+ segment = segment -> nextSegment();
+ }
+
+ // termine le chemin
+ path.lineTo(segment -> secondPoint());
+
+ // affecte le chemin au conducteur
+ setPath(path);
+}
+
+/**
+ Gere les updates
+ @param p1 Coordonnees du point d'amarrage de la borne 1
+ @param o1 Orientation de la borne 1
+ @param p2 Coordonnees du point d'amarrage de la borne 2
+ @param o2 Orientation de la borne 2
+*/
+void Conductor::updateConductorPath(const QPointF &p1, QET::Orientation o1, const QPointF &p2, QET::Orientation o2) {
+ Q_UNUSED(o1);
+ Q_UNUSED(o2);
+
+ ConductorProfile &conductor_profile = conductor_profiles[currentPathType()];
+
+ Q_ASSERT_X(conductor_profile.segmentsCount(QET::Both) > 1, "Conductor::priv_modifieConductor", "pas de points a modifier");
+ Q_ASSERT_X(!conductor_profile.isNull(), "Conductor::priv_modifieConductor", "pas de profil utilisable");
+
+ // recupere les coordonnees fournies des bornes
+ QPointF new_p1 = mapFromScene(p1);
+ QPointF new_p2 = mapFromScene(p2);
+ QRectF new_rect = QRectF(new_p1, new_p2);
+
+ // recupere la largeur et la hauteur du profil
+ qreal profile_width = conductor_profile.width();
+ qreal profile_height = conductor_profile.height();
+
+ // calcule les differences verticales et horizontales a appliquer
+ qreal h_diff = (qAbs(new_rect.width()) - qAbs(profile_width) ) * getSign(profile_width);
+ qreal v_diff = (qAbs(new_rect.height()) - qAbs(profile_height)) * getSign(profile_height);
+
+ // applique les differences aux segments
+ QHash<ConductorSegmentProfile *, qreal> segments_lengths;
+ segments_lengths.unite(shareOffsetBetweenSegments(h_diff, conductor_profile.horizontalSegments()));
+ segments_lengths.unite(shareOffsetBetweenSegments(v_diff, conductor_profile.verticalSegments()));
+
+ // en deduit egalement les coefficients d'inversion (-1 pour une inversion, +1 pour conserver le meme sens)
+ int horiz_coeff = getCoeff(new_rect.width(), profile_width);
+ int verti_coeff = getCoeff(new_rect.height(), profile_height);
+
+ // genere les nouveaux points
+ QList<QPointF> points;
+ points << new_p1;
+ int limit = conductor_profile.segments.count() - 1;
+ for (int i = 0 ; i < limit ; ++ i) {
+ // dernier point
+ QPointF previous_point = points.last();
+
+ // profil de segment de conducteur en cours
+ ConductorSegmentProfile *csp = conductor_profile.segments.at(i);
+
+ // coefficient et offset a utiliser pour ce point
+ qreal coeff = csp -> isHorizontal ? horiz_coeff : verti_coeff;
+ qreal offset_applied = segments_lengths[csp];
+
+ // applique l'offset et le coeff au point
+ if (csp -> isHorizontal) {
+ points << QPointF (
+ previous_point.x() + (coeff * offset_applied),
+ previous_point.y()
+ );
+ } else {
+ points << QPointF (
+ previous_point.x(),
+ previous_point.y() + (coeff * offset_applied)
+ );
+ }
+ }
+ points << new_p2;
+ pointsToSegments(points);
+ segmentsToPath();
+}
+
+/**
+ @param offset Longueur a repartir entre les segments
+ @param segments_list Segments sur lesquels il faut repartir la longueur
+ @param precision seuil en-deca duquel on considere qu'il ne reste rien a repartir
+*/
+QHash<ConductorSegmentProfile *, qreal> Conductor::shareOffsetBetweenSegments(
+ const qreal &offset,
+ const QList<ConductorSegmentProfile *> &segments_list,
+ const qreal &precision
+) const {
+ // construit le QHash qui sera retourne
+ QHash<ConductorSegmentProfile *, qreal> segments_hash;
+ foreach(ConductorSegmentProfile *csp, segments_list) {
+ segments_hash.insert(csp, csp -> length);
+ }
+
+ // memorise le signe de la longueur de chaque segement
+ QHash<ConductorSegmentProfile *, int> segments_signs;
+ foreach(ConductorSegmentProfile *csp, segments_hash.keys()) {
+ segments_signs.insert(csp, getSign(csp -> length));
+ }
+
+ //qDebug() << "repartition d'un offset de" << offset << "px sur" << segments_list.count() << "segments";
+
+ // repartit l'offset sur les segments
+ qreal remaining_offset = offset;
+ while (remaining_offset > precision || remaining_offset < -precision) {
+ // recupere le nombre de segments differents ayant une longueur non nulle
+ uint segments_count = 0;
+ foreach(ConductorSegmentProfile *csp, segments_hash.keys()) if (segments_hash[csp]) ++ segments_count;
+ //qDebug() << " remaining_offset =" << remaining_offset;
+ qreal local_offset = remaining_offset / segments_count;
+ //qDebug() << " repartition d'un offset local de" << local_offset << "px sur" << segments_count << "segments";
+ remaining_offset = 0.0;
+ foreach(ConductorSegmentProfile *csp, segments_hash.keys()) {
+ // ignore les segments de longueur nulle
+ if (!segments_hash[csp]) continue;
+ // applique l'offset au segment
+ //qreal segment_old_length = segments_hash[csp];
+ segments_hash[csp] += local_offset;
+
+ // (la longueur du segment change de signe) <=> (le segment n'a pu absorbe tout l'offset)
+ if (segments_signs[csp] != getSign(segments_hash[csp])) {
+
+ // on remet le trop-plein dans la reserve d'offset
+ remaining_offset += qAbs(segments_hash[csp]) * getSign(local_offset);
+ //qDebug() << " trop-plein de" << qAbs(segments_hash[csp]) * getSign(local_offset) << "remaining_offset =" << remaining_offset;
+ segments_hash[csp] = 0.0;
+ } else {
+ //qDebug() << " offset local de" << local_offset << "accepte";
+ }
+ }
+ }
+
+ return(segments_hash);
+}
+
+/**
+ Calcule un trajet "par defaut" pour le conducteur
+ @param p1 Coordonnees du point d'amarrage de la borne 1
+ @param o1 Orientation de la borne 1
+ @param p2 Coordonnees du point d'amarrage de la borne 2
+ @param o2 Orientation de la borne 2
+*/
+void Conductor::generateConductorPath(const QPointF &p1, QET::Orientation o1, const QPointF &p2, QET::Orientation o2) {
+ QPointF sp1, sp2, depart, newp1, newp2, arrivee, depart0, arrivee0;
+ QET::Orientation ori_depart, ori_arrivee;
+
+ // s'assure qu'il n'y a ni points
+ QList<QPointF> points;
+
+ // mappe les points par rapport a la scene
+ sp1 = mapFromScene(p1);
+ sp2 = mapFromScene(p2);
+
+ // prolonge les bornes
+ newp1 = extendTerminal(sp1, o1);
+ newp2 = extendTerminal(sp2, o2);
+
+ // distingue le depart de l'arrivee : le trajet se fait toujours de gauche a droite (apres prolongation)
+ if (newp1.x() <= newp2.x()) {
+ depart = newp1;
+ arrivee = newp2;
+ depart0 = sp1;
+ arrivee0 = sp2;
+ ori_depart = o1;
+ ori_arrivee = o2;
+ } else {
+ depart = newp2;
+ arrivee = newp1;
+ depart0 = sp2;
+ arrivee0 = sp1;
+ ori_depart = o2;
+ ori_arrivee = o1;
+ }
+
+ // debut du trajet
+ points << depart0;
+
+ // prolongement de la borne de depart
+ points << depart;
+
+ // commence le vrai trajet
+ if (depart.y() < arrivee.y()) {
+ // trajet descendant
+ if ((ori_depart == QET::North && (ori_arrivee == QET::South || ori_arrivee == QET::West)) || (ori_depart == QET::East && ori_arrivee == QET::West)) {
+ // cas "3"
+ int ligne_inter_x = qRound(depart.x() + arrivee.x()) / 2;
+ while (ligne_inter_x % Diagram::xGrid) -- ligne_inter_x;
+ points << QPointF(ligne_inter_x, depart.y());
+ points << QPointF(ligne_inter_x, arrivee.y());
+ } else if ((ori_depart == QET::South && (ori_arrivee == QET::North || ori_arrivee == QET::East)) || (ori_depart == QET::West && ori_arrivee == QET::East)) {
+ // cas "4"
+ int ligne_inter_y = qRound(depart.y() + arrivee.y()) / 2;
+ while (ligne_inter_y % Diagram::yGrid) -- ligne_inter_y;
+ points << QPointF(depart.x(), ligne_inter_y);
+ points << QPointF(arrivee.x(), ligne_inter_y);
+ } else if ((ori_depart == QET::North || ori_depart == QET::East) && (ori_arrivee == QET::North || ori_arrivee == QET::East)) {
+ points << QPointF(arrivee.x(), depart.y()); // cas "2"
+ } else {
+ points << QPointF(depart.x(), arrivee.y()); // cas "1"
+ }
+ } else {
+ // trajet montant
+ if ((ori_depart == QET::West && (ori_arrivee == QET::East || ori_arrivee == QET::South)) || (ori_depart == QET::North && ori_arrivee == QET::South)) {
+ // cas "3"
+ int ligne_inter_y = qRound(depart.y() + arrivee.y()) / 2;
+ while (ligne_inter_y % Diagram::yGrid) -- ligne_inter_y;
+ points << QPointF(depart.x(), ligne_inter_y);
+ points << QPointF(arrivee.x(), ligne_inter_y);
+ } else if ((ori_depart == QET::East && (ori_arrivee == QET::West || ori_arrivee == QET::North)) || (ori_depart == QET::South && ori_arrivee == QET::North)) {
+ // cas "4"
+ int ligne_inter_x = qRound(depart.x() + arrivee.x()) / 2;
+ while (ligne_inter_x % Diagram::xGrid) -- ligne_inter_x;
+ points << QPointF(ligne_inter_x, depart.y());
+ points << QPointF(ligne_inter_x, arrivee.y());
+ } else if ((ori_depart == QET::West || ori_depart == QET::North) && (ori_arrivee == QET::West || ori_arrivee == QET::North)) {
+ points << QPointF(depart.x(), arrivee.y()); // cas "2"
+ } else {
+ points << QPointF(arrivee.x(), depart.y()); // cas "1"
+ }
+ }
+
+ // fin du vrai trajet
+ points << arrivee;
+
+ // prolongement de la borne d'arrivee
+ points << arrivee0;
+
+ // inverse eventuellement l'ordre des points afin que le trajet soit exprime de la borne 1 vers la borne 2
+ if (newp1.x() > newp2.x()) {
+ QList<QPointF> points2;
+ for (int i = points.size() - 1 ; i >= 0 ; -- i) points2 << points.at(i);
+ points = points2;
+ }
+
+ pointsToSegments(points);
+ segmentsToPath();
+}
+
+/**
+ Prolonge une borne.
+ @param terminal Le point correspondant a la borne
+ @param terminal_orientation L'orientation de la borne
+ @param ext_size la taille de la prolongation
+ @return le point correspondant a la borne apres prolongation
+*/
+QPointF Conductor::extendTerminal(const QPointF &terminal, QET::Orientation terminal_orientation, qreal ext_size) {
+ QPointF extended_terminal;
+ switch(terminal_orientation) {
+ case QET::North:
+ extended_terminal = QPointF(terminal.x(), terminal.y() - ext_size);
+ break;
+ case QET::East:
+ extended_terminal = QPointF(terminal.x() + ext_size, terminal.y());
+ break;
+ case QET::South:
+ extended_terminal = QPointF(terminal.x(), terminal.y() + ext_size);
+ break;
+ case QET::West:
+ extended_terminal = QPointF(terminal.x() - ext_size, terminal.y());
+ break;
+ default: extended_terminal = terminal;
+ }
+ return(extended_terminal);
+}
+
+/**
+ Dessine le conducteur sans antialiasing.
+ @param qp Le QPainter a utiliser pour dessiner le conducteur
+ @param options Les options de style pour le conducteur
+ @param qw Le QWidget sur lequel on dessine
+*/
+void Conductor::paint(QPainter *qp, const QStyleOptionGraphicsItem *options, QWidget *qw) {
+ Q_UNUSED(qw);
+ qp -> save();
+ qp -> setRenderHint(QPainter::Antialiasing, false);
+
+ // determine la couleur du conducteur
+ QColor final_conductor_color(properties_.color);
+ if (must_highlight_ == Normal) {
+ final_conductor_color = QColor::fromRgb(69, 137, 255, 255);
+ } else if (must_highlight_ == Alert) {
+ final_conductor_color =QColor::fromRgb(255, 69, 0, 255);
+ } else if (isSelected()) {
+ final_conductor_color = Qt::red;
+ } else {
+ if (Diagram *parent_diagram = diagram()) {
+ if (!parent_diagram -> drawColoredConductors()) {
+ final_conductor_color = Qt::black;
+ }
+ }
+ }
+
+ // affectation du QPen et de la QBrush modifies au QPainter
+ qp -> setBrush(conductor_brush);
+ QPen final_conductor_pen = conductor_pen;
+
+ // modification du QPen generique pour lui affecter la couleur et le style adequats
+ final_conductor_pen.setColor(final_conductor_color);
+ final_conductor_pen.setStyle(properties_.style);
+ final_conductor_pen.setJoinStyle(Qt::SvgMiterJoin); // meilleur rendu des pointilles
+
+ // utilisation d'un trait "cosmetique" en-dessous d'un certain zoom
+ if (options && options -> levelOfDetail < 1.0) {
+ final_conductor_pen.setCosmetic(true);
+ }
+
+ qp -> setPen(final_conductor_pen);
+
+ // dessin du conducteur
+ qp -> drawPath(path());
+ if (properties_.type == ConductorProperties::Single) {
+ qp -> setBrush(final_conductor_color);
+ properties_.singleLineProperties.draw(
+ qp,
+ middleSegment() -> isHorizontal() ? QET::Horizontal : QET::Vertical,
+ QRectF(middleSegment() -> middle() - QPointF(12.0, 12.0), QSizeF(24.0, 24.0))
+ );
+ if (isSelected()) qp -> setBrush(Qt::NoBrush);
+ }
+
+ // decalage ideal pour le rendu centre d'un carre / cercle de 2.0 px de cote / diametre
+ qreal pretty_offset = (options -> levelOfDetail == 1 ? 1.0 : 1.0);
+
+ // dessin des points d'accroche du conducteur si celui-ci est selectionne
+ if (isSelected()) {
+ QList<QPointF> points = segmentsToPoints();
+ QPointF previous_point;
+ for (int i = 1 ; i < (points.size() -1) ; ++ i) {
+ QPointF point = points.at(i);
+
+ // dessine le carre de saisie du segment
+ if (i > 1) {
+ qp -> fillRect(
+ QRectF(
+ ((previous_point.x() + point.x()) / 2.0 ) - pretty_offset * segments_squares_scale_,
+ ((previous_point.y() + point.y()) / 2.0 ) - pretty_offset * segments_squares_scale_,
+ 2.0 * segments_squares_scale_,
+ 2.0 * segments_squares_scale_
+ ),
+ square_brush
+ );
+ }
+ previous_point = point;
+ }
+ }
+
+ // dessine les eventuelles jonctions
+ QList<QPointF> junctions_list = junctions();
+ if (!junctions_list.isEmpty()) {
+ final_conductor_pen.setStyle(Qt::SolidLine);
+ QBrush junction_brush(final_conductor_color, Qt::SolidPattern);
+ qp -> setPen(final_conductor_pen);
+ qp -> setBrush(junction_brush);
+ qp -> setRenderHint(QPainter::Antialiasing, true);
+ foreach(QPointF point, junctions_list) {
+ qp -> drawEllipse(QRectF(point.x() - pretty_offset, point.y() - pretty_offset, 2.0, 2.0));
+ }
+ }
+ qp -> restore();
+}
+
+/**
+ Methode de preparation a la destruction du conducteur ; le conducteur se detache de ses deux bornes
+*/
+void Conductor::destroy() {
+ destroyed_ = true;
+ terminal1 -> removeConductor(this);
+ terminal2 -> removeConductor(this);
+}
+
+/// @return le Diagram auquel ce conducteur appartient, ou 0 si ce conducteur est independant
+Diagram *Conductor::diagram() const {
+ return(qobject_cast<Diagram *>(scene()));
+}
+
+/**
+ @return le champ de texte associe a ce conducteur
+*/
+ConductorTextItem *Conductor::textItem() const {
+ return(text_item);
+}
+
+/**
+ Methode de validation d'element XML
+ @param e Un element XML sense represente un Conducteur
+ @return true si l'element XML represente bien un Conducteur ; false sinon
+*/
+bool Conductor::valideXml(QDomElement &e){
+ // verifie le nom du tag
+ if (e.tagName() != "conductor") return(false);
+
+ // verifie la presence des attributs minimaux
+ if (!e.hasAttribute("terminal1")) return(false);
+ if (!e.hasAttribute("terminal2")) return(false);
+
+ bool conv_ok;
+ // parse l'abscisse
+ e.attribute("terminal1").toInt(&conv_ok);
+ if (!conv_ok) return(false);
+
+ // parse l'ordonnee
+ e.attribute("terminal2").toInt(&conv_ok);
+ if (!conv_ok) return(false);
+ return(true);
+}
+
+/**
+ Gere les clics sur le conducteur.
+ @param e L'evenement decrivant le clic.
+*/
+void Conductor::mousePressEvent(QGraphicsSceneMouseEvent *e) {
+ // clic gauche
+ if (e -> buttons() & Qt::LeftButton) {
+ // recupere les coordonnees du clic
+ press_point = e -> pos();
+
+ /*
+ parcourt les segments pour determiner si le clic a eu lieu
+ - sur l'extremite d'un segment
+ - sur le milieu d'un segment
+ - ailleurs
+ */
+ ConductorSegment *segment = segments;
+ while (segment -> hasNextSegment()) {
+ if (hasClickedOn(press_point, segment -> secondPoint())) {
+ moving_point = true;
+ moving_segment = false;
+ moved_segment = segment;
+ break;
+ } else if (hasClickedOn(press_point, segment -> middle())) {
+ moving_point = false;
+ moving_segment = true;
+ moved_segment = segment;
+ break;
+ }
+ segment = segment -> nextSegment();
+ }
+ if (moving_segment || moving_point) {
+ // en cas de debut de modification de conducteur, on memorise la position du champ de texte
+ before_mov_text_pos_ = text_item -> pos();
+ }
+ }
+ QGraphicsPathItem::mousePressEvent(e);
+ if (e -> modifiers() & Qt::ControlModifier) {
+ setSelected(!isSelected());
+ }
+}
+
+/**
+ Gere les deplacements de souris sur le conducteur.
+ @param e L'evenement decrivant le deplacement de souris.
+*/
+void Conductor::mouseMoveEvent(QGraphicsSceneMouseEvent *e) {
+ // clic gauche
+ if (e -> buttons() & Qt::LeftButton) {
+ // position pointee par la souris
+ qreal mouse_x = e -> pos().x();
+ qreal mouse_y = e -> pos().y();
+
+ bool snap_conductors_to_grid = e -> modifiers() ^ Qt::ShiftModifier;
+ if (snap_conductors_to_grid) {
+ mouse_x = qRound(mouse_x / (Diagram::xGrid * 1.0)) * Diagram::xGrid;
+ mouse_y = qRound(mouse_y / (Diagram::yGrid * 1.0)) * Diagram::yGrid;
+ }
+
+ if (moving_point) {
+ // la modification par points revient bientot
+ /*
+ // position precedente du point
+ QPointF p = moved_segment -> secondPoint();
+ qreal p_x = p.x();
+ qreal p_y = p.y();
+
+ // calcul du deplacement
+ moved_segment -> moveX(mouse_x - p_x());
+ moved_segment -> moveY(mouse_y - p_y());
+
+ // application du deplacement
+ modified_path = true;
+ updatePoints();
+ segmentsToPath();
+ */
+ } else if (moving_segment) {
+ // position precedente du point
+ QPointF p = moved_segment -> middle();
+
+ // calcul du deplacement
+ moved_segment -> moveX(mouse_x - p.x());
+ moved_segment -> moveY(mouse_y - p.y());
+
+ // application du deplacement
+ modified_path = true;
+ has_to_save_profile = true;
+ segmentsToPath();
+ calculateTextItemPosition();
+ }
+ }
+ QGraphicsPathItem::mouseMoveEvent(e);
+}
+
+/**
+ Gere les relachements de boutons de souris sur le conducteur
+ @param e L'evenement decrivant le lacher de bouton.
+*/
+void Conductor::mouseReleaseEvent(QGraphicsSceneMouseEvent *e) {
+ // clic gauche
+ moving_point = false;
+ moving_segment = false;
+ if (has_to_save_profile) {
+ saveProfile();
+ has_to_save_profile = false;
+ }
+ if (!(e -> modifiers() & Qt::ControlModifier)) {
+ QGraphicsPathItem::mouseReleaseEvent(e);
+ }
+ calculateTextItemPosition();
+}
+
+/**
+ Gere l'entree de la souris dans la zone du conducteur
+ @param e Le QGraphicsSceneHoverEvent decrivant l'evenement
+*/
+void Conductor::hoverEnterEvent(QGraphicsSceneHoverEvent *e) {
+ Q_UNUSED(e);
+ segments_squares_scale_ = 2.0;
+ if (isSelected()) {
+ update();
+ }
+}
+
+/**
+ Gere la sortie de la souris de la zone du conducteur
+ @param e Le QGraphicsSceneHoverEvent decrivant l'evenement
+*/
+void Conductor::hoverLeaveEvent(QGraphicsSceneHoverEvent *e) {
+ Q_UNUSED(e);
+ segments_squares_scale_ = 1.0;
+ if (isSelected()) {
+ update();
+ }
+}
+
+/**
+ Gere les mouvements de souris au dessus du conducteur
+ @param e Le QGraphicsSceneHoverEvent decrivant l'evenement
+*/
+void Conductor::hoverMoveEvent(QGraphicsSceneHoverEvent *e) {
+ /*
+ if (isSelected()) {
+ QPointF hover_point = mapFromScene(e -> pos());
+ ConductorSegment *segment = segments;
+ bool cursor_set = false;
+ while (segment -> hasNextSegment()) {
+ if (hasClickedOn(hover_point, segment -> secondPoint())) {
+ setCursor(Qt::CrossCursor);
+ cursor_set = true;
+ } else if (hasClickedOn(hover_point, segment -> middle())) {
+ setCursor(segment -> isVertical() ? Qt::SplitHCursor : Qt::SplitVCursor);
+ cursor_set = true;
+ }
+ segment = segment -> nextSegment();
+ }
+ if (!cursor_set) setCursor(Qt::ArrowCursor);
+ }
+ */
+ QGraphicsPathItem::hoverMoveEvent(e);
+}
+
+/**
+ Gere les changements relatifs au conducteur
+ Reimplemente ici pour :
+ * positionner le conducteur en avant-plan lorsqu'il est selectionne
+ @param change Type de changement
+ @param value Valeur relative au changement
+*/
+QVariant Conductor::itemChange(GraphicsItemChange change, const QVariant &value) {
+ if (change == QGraphicsItem::ItemSelectedChange) {
+ if (value.toBool()) {
+ // le conducteur vient de se faire selectionner
+ previous_z_value = zValue();
+ setZValue(qAbs(previous_z_value) + 10000);
+ } else {
+ // le conducteur vient de se faire deselectionner
+ setZValue(previous_z_value);
+ }
+ } else if (change == QGraphicsItem::ItemSceneHasChanged) {
+ // permet de positionner correctement le texte du conducteur lors de son ajout a un schema
+ calculateTextItemPosition();
+ } else if (change == QGraphicsItem::ItemVisibleHasChanged) {
+ // permet de positionner correctement le texte du conducteur lors de son ajout a un schema
+ calculateTextItemPosition();
+ }
+ return(QGraphicsPathItem::itemChange(change, value));
+}
+
+/**
+ @return Le rectangle delimitant l'espace de dessin du conducteur
+*/
+QRectF Conductor::boundingRect() const {
+ QRectF retour = QGraphicsPathItem::boundingRect();
+ retour.adjust(-11.0, -11.0, 11.0, 11.0);
+ return(retour);
+}
+
+/**
+ @return La forme / zone "cliquable" du conducteur (epaisseur : 5.0px).
+ @see variableShape()
+*/
+QPainterPath Conductor::shape() const {
+ return(variableShape(5.0));
+}
+
+/**
+ @return la distance en dessous de laquelle on considere qu'un point est a
+ proximite du trajet du conducteur. La valeur est actuellement fixee a
+ 60.0px.
+*/
+qreal Conductor::nearDistance() const {
+ return(60.0);
+}
+
+/**
+ @return la zone dans laquelle dont on considere que tous les points sont a
+ proximite du trajet du conducteur.
+ @see nearDistance()
+ @see variableShape()
+*/
+QPainterPath Conductor::nearShape() const {
+ return(variableShape(nearDistance()));
+}
+
+/**
+ @return la forme du conducteur
+ @param thickness la moitie de l'epaisseur voulue pour cette forme
+*/
+QPainterPath Conductor::variableShape(const qreal &thickness) const {
+ qreal my_thickness = qAbs(thickness);
+
+ QList<QPointF> points = segmentsToPoints();
+ QPainterPath area;
+ QPointF previous_point;
+ QPointF *point1, *point2;
+ foreach(QPointF point, points) {
+ if (!previous_point.isNull()) {
+ if (point.x() == previous_point.x()) {
+ if (point.y() <= previous_point.y()) {
+ point1 = &point;
+ point2 = &previous_point;
+ } else {
+ point1 = &previous_point;
+ point2 = &point;
+ }
+ } else {
+ if (point.x() <= previous_point.x()) {
+ point1 = &point;
+ point2 = &previous_point;
+ } else {
+ point1 = &previous_point;
+ point2 = &point;
+ }
+ }
+ qreal p1_x = point1 -> x();
+ qreal p1_y = point1 -> y();
+ qreal p2_x = point2 -> x();
+ qreal p2_y = point2 -> y();
+ area.setFillRule(Qt::OddEvenFill);
+ area.addRect(p1_x - my_thickness, p1_y - my_thickness, my_thickness * 2.0 + p2_x - p1_x, my_thickness * 2.0 + p2_y - p1_y);
+ }
+ previous_point = point;
+ area.setFillRule(Qt::WindingFill);
+ area.addRect(point.x() - my_thickness, point.y() - my_thickness, my_thickness * 2.0, my_thickness * 2.0 );
+ }
+ return(area);
+}
+
+/**
+ @param point un point, exprime dans les coordonnees du conducteur
+ @return true si le point est a proximite du conducteur, c-a-d a moins de
+ 60px du conducteur.
+*/
+bool Conductor::isNearConductor(const QPointF &point) {
+ return(variableShape(60.1).contains(point));
+}
+
+/**
+ Renvoie une valeur donnee apres l'avoir bornee entre deux autres valeurs,
+ en y ajoutant une marge interne.
+ @param tobound valeur a borner
+ @param bound1 borne 1
+ @param bound2 borne 2
+ @param space marge interne ajoutee
+ @return La valeur bornee
+*/
+qreal Conductor::conductor_bound(qreal tobound, qreal bound1, qreal bound2, qreal space) {
+ qDebug() << "will bound" << tobound << "between" << bound1 << "and" << bound2 ;
+ if (bound1 < bound2) {
+ return(qBound(bound1 + space, tobound, bound2 - space));
+ } else {
+ return(qBound(bound2 + space, tobound, bound1 - space));
+ }
+}
+
+/**
+ Renvoie une valeur donnee apres l'avoir bornee avant ou apres une valeur.
+ @param tobound valeur a borner
+ @param bound borne
+ @param positive true pour borner la valeur avant la borne, false sinon
+ @return La valeur bornee
+*/
+qreal Conductor::conductor_bound(qreal tobound, qreal bound, bool positive) {
+ qreal space = 5.0;
+ return(positive ? qMax(tobound, bound + space) : qMin(tobound, bound - space));
+}
+
+/**
+ @param type Type de Segments
+ @return Le nombre de segments composant le conducteur.
+*/
+uint Conductor::segmentsCount(QET::ConductorSegmentType type) const {
+ QList<ConductorSegment *> segments_list = segmentsList();
+ if (type == QET::Both) return(segments_list.count());
+ uint nb_seg = 0;
+ foreach(ConductorSegment *conductor_segment, segments_list) {
+ if (conductor_segment -> type() == type) ++ nb_seg;
+ }
+ return(nb_seg);
+}
+
+/**
+ Genere une liste de points a partir des segments de ce conducteur
+ @return La liste de points representant ce conducteur
+*/
+QList<QPointF> Conductor::segmentsToPoints() const {
+ // liste qui sera retournee
+ QList<QPointF> points_list;
+
+ // on retourne la liste tout de suite s'il n'y a pas de segments
+ if (segments == NULL) return(points_list);
+
+ // recupere le premier point
+ points_list << segments -> firstPoint();
+
+ // parcourt les segments pour recuperer les autres points
+ ConductorSegment *segment = segments;
+ while(segment -> hasNextSegment()) {
+ points_list << segment -> secondPoint();
+ segment = segment -> nextSegment();
+ }
+
+ // recupere le dernier point
+ points_list << segment -> secondPoint();
+
+ //retourne la liste
+ return(points_list);
+}
+
+/**
+ Regenere les segments de ce conducteur a partir de la liste de points passee en parametre
+ @param points_list Liste de points a utiliser pour generer les segments
+*/
+void Conductor::pointsToSegments(QList<QPointF> points_list) {
+ // supprime les segments actuels
+ deleteSegments();
+
+ // cree les segments a partir de la liste de points
+ ConductorSegment *last_segment = NULL;
+ for (int i = 0 ; i < points_list.size() - 1 ; ++ i) {
+ last_segment = new ConductorSegment(points_list.at(i), points_list.at(i + 1), last_segment);
+ if (!i) segments = last_segment;
+ }
+}
+
+/**
+ Permet de savoir si un point est tres proche d'un autre. Cela sert surtout
+ pour determiner si un clic a ete effectue pres d'un point donne.
+ @param press_point Point effectivement clique
+ @param point point cliquable
+ @return true si l'on peut considerer que le point a ete clique, false sinon
+*/
+bool Conductor::hasClickedOn(QPointF press_point, QPointF point) const {
+ return (
+ press_point.x() >= point.x() - 5.0 &&\
+ press_point.x() < point.x() + 5.0 &&\
+ press_point.y() >= point.y() - 5.0 &&\
+ press_point.y() < point.y() + 5.0
+ );
+}
+
+/**
+ Charge les caracteristiques du conducteur depuis un element XML.
+ @param e Un element XML
+ @return true si le chargement a reussi, false sinon
+*/
+bool Conductor::fromXml(QDomElement &e) {
+ // recupere la "configuration" du conducteur
+ properties_.fromXml(e);
+ readProperties();
+ qreal user_pos_x, user_pos_y;
+ if (
+ QET::attributeIsAReal(e, "userx", &user_pos_x) &&
+ QET::attributeIsAReal(e, "usery", &user_pos_y)
+ ) {
+ text_item -> forceMovedByUser(true);
+ text_item -> setPos(user_pos_x, user_pos_y);
+ }
+ if (e.hasAttribute("rotation")) {
+ text_item -> setRotationAngle(e.attribute("rotation").toDouble());
+ text_item -> forceRotateByUser(true);
+ }
+
+ // parcourt les elements XML "segment" et en extrait deux listes de longueurs
+ // les segments non valides sont ignores
+ QList<qreal> segments_x, segments_y;
+ for (QDomNode node = e.firstChild() ; !node.isNull() ; node = node.nextSibling()) {
+ // on s'interesse aux elements XML "segment"
+ QDomElement current_segment = node.toElement();
+ if (current_segment.isNull() || current_segment.tagName() != "segment") continue;
+
+ // le segment doit avoir une longueur
+ if (!current_segment.hasAttribute("length")) continue;
+
+ // cette longueur doit etre un reel
+ bool ok;
+ qreal segment_length = current_segment.attribute("length").toDouble(&ok);
+ if (!ok) continue;
+
+ if (current_segment.attribute("orientation") == "horizontal") {
+ segments_x << segment_length;
+ segments_y << 0.0;
+ } else {
+ segments_x << 0.0;
+ segments_y << segment_length;
+ }
+ }
+
+ // s'il n'y a pas de segments, on renvoie true
+ if (!segments_x.size()) return(true);
+ // les longueurs recueillies doivent etre coherentes avec les positions des bornes
+ qreal width = 0.0, height = 0.0;
+ foreach (qreal t, segments_x) width += t;
+ foreach (qreal t, segments_y) height += t;
+ QPointF t1 = terminal1 -> dockConductor();
+ QPointF t2 = terminal2 -> dockConductor();
+ qreal expected_width = t2.x() - t1.x();
+ qreal expected_height = t2.y() - t1.y();
+
+ // on considere que le trajet est incoherent a partir d'une unite de difference avec l'espacement entre les bornes
+ if (
+ qAbs(expected_width - width) > 1.0 ||
+ qAbs(expected_height - height) > 1.0
+ ) {
+ qDebug() << "Conductor::fromXml : les segments du conducteur ne semblent pas coherents - utilisation d'un trajet automatique";
+ return(false);
+ }
+
+ /* on recree les segments a partir des donnes XML */
+ // cree la liste de points
+ QList<QPointF> points_list;
+ points_list << t1;
+ for (int i = 0 ; i < segments_x.size() ; ++ i) {
+ points_list << QPointF(
+ points_list.last().x() + segments_x.at(i),
+ points_list.last().y() + segments_y.at(i)
+ );
+ }
+
+ pointsToSegments(points_list);
+
+ // initialise divers parametres lies a la modification des conducteurs
+ modified_path = true;
+ saveProfile(false);
+
+ segmentsToPath();
+ return(true);
+}
+
+/**
+ Exporte les caracteristiques du conducteur sous forme d'une element XML.
+ @param d Le document XML a utiliser pour creer l'element XML
+ @param table_adr_id Hash stockant les correspondances entre les ids des
+ bornes dans le document XML et leur adresse en memoire
+ @return Un element XML representant le conducteur
+*/
+QDomElement Conductor::toXml(QDomDocument &d, QHash<Terminal *, int> &table_adr_id) const {
+ QDomElement e = d.createElement("conductor");
+ e.setAttribute("terminal1", table_adr_id.value(terminal1));
+ e.setAttribute("terminal2", table_adr_id.value(terminal2));
+
+ // on n'exporte les segments du conducteur que si ceux-ci ont
+ // ete modifies par l'utilisateur
+ if (modified_path) {
+ // parcours et export des segments
+ QDomElement current_segment;
+ foreach(ConductorSegment *segment, segmentsList()) {
+ current_segment = d.createElement("segment");
+ current_segment.setAttribute("orientation", segment -> isHorizontal() ? "horizontal" : "vertical");
+ current_segment.setAttribute("length", QString("%1").arg(segment -> length()));
+ e.appendChild(current_segment);
+ }
+ }
+
+ // exporte la "configuration" du conducteur
+ properties_.toXml(e);
+ if (text_item -> wasRotateByUser()) {
+ e.setAttribute("rotation", QString("%1").arg(text_item -> rotationAngle()));
+ }
+ if (text_item -> wasMovedByUser()) {
+ e.setAttribute("userx", QString("%1").arg(text_item -> pos().x()));
+ e.setAttribute("usery", QString("%1").arg(text_item -> pos().y()));
+ }
+ return(e);
+}
+
+/// @return les segments de ce conducteur
+const QList<ConductorSegment *> Conductor::segmentsList() const {
+ if (segments == NULL) return(QList<ConductorSegment *>());
+
+ QList<ConductorSegment *> segments_vector;
+ ConductorSegment *segment = segments;
+
+ while (segment -> hasNextSegment()) {
+ segments_vector << segment;
+ segment = segment -> nextSegment();
+ }
+ segments_vector << segment;
+ return(segments_vector);
+}
+
+/**
+ @return La longueur totale du conducteur
+*/
+qreal Conductor::length() {
+ qreal length = 0.0;
+
+ ConductorSegment *s = segments;
+ while (s -> hasNextSegment()) {
+ length += qAbs(s -> length());
+ s = s -> nextSegment();
+ }
+
+ return(length);
+}
+
+/**
+ @return Le segment qui contient le point au milieu du conducteur
+*/
+ConductorSegment *Conductor::middleSegment() {
+ if (segments == NULL) return(NULL);
+
+ qreal half_length = length() / 2.0;
+
+ ConductorSegment *s = segments;
+ qreal l = 0;
+
+ while (s -> hasNextSegment()) {
+ l += qAbs(s -> length());
+ if (l >= half_length) break;
+ s = s -> nextSegment();
+ }
+ // s est le segment qui contient le point au milieu du conducteur
+ return(s);
+}
+
+/**
+ Positionne le texte du conducteur au milieu du segment qui contient le
+ point au milieu du conducteur
+ @see middleSegment()
+*/
+void Conductor::calculateTextItemPosition() {
+ if (!text_item) return;
+
+ //position
+ if (text_item -> wasMovedByUser()) {
+ // le champ de texte a ete deplace par l'utilisateur :
+ // on verifie qu'il est encore a proximite du conducteur
+ QPointF text_item_pos = text_item -> pos();
+ QPainterPath near_shape = nearShape();
+ if (!near_shape.contains(text_item_pos)) {
+ text_item -> setPos(movePointIntoPolygon(text_item_pos, near_shape));
+ }
+ } else {
+ // positionnement automatique basique
+ text_item -> setPos(middleSegment() -> middle());
+ //rotation
+ if (!text_item -> wasRotateByUser()) {
+ middleSegment() -> isVertical()? text_item -> setRotationAngle(properties_.verti_rotate_text):
+ text_item -> setRotationAngle(properties_.horiz_rotate_text);
+ }
+ }
+}
+
+/**
+ Sauvegarde le profil courant du conducteur pour l'utiliser ulterieurement
+ dans priv_modifieConductor.
+*/
+void Conductor::saveProfile(bool undo) {
+ Qt::Corner current_path_type = currentPathType();
+ ConductorProfile old_profile(conductor_profiles[current_path_type]);
+ conductor_profiles[current_path_type].fromConductor(this);
+ Diagram *dia = diagram();
+ if (undo && dia) {
+ ChangeConductorCommand *undo_object = new ChangeConductorCommand(
+ this,
+ old_profile,
+ conductor_profiles[current_path_type],
+ current_path_type
+ );
+ undo_object -> setConductorTextItemMove(before_mov_text_pos_, text_item -> pos());
+ dia -> undoStack().push(undo_object);
+ }
+}
+
+/**
+ @param value1 Premiere valeur
+ @param value2 Deuxieme valeur
+ @return 1 si les deux valeurs sont de meme signe, -1 sinon
+*/
+int Conductor::getCoeff(const qreal &value1, const qreal &value2) {
+ return(getSign(value1) * getSign(value2));
+}
+
+/**
+ @param value valeur
+ @return 1 si valeur est negatif, 1 s'il est positif ou nul
+*/
+int Conductor::getSign(const qreal &value) {
+ return(value < 0 ? -1 : 1);
+}
+
+/**
+ Applique un nouveau profil a ce conducteur
+ @param cp Profil a appliquer a ce conducteur
+ @param path_type Type de trajet pour lequel ce profil convient
+*/
+void Conductor::setProfile(const ConductorProfile &cp, Qt::Corner path_type) {
+ conductor_profiles[path_type] = cp;
+ // si le type de trajet correspond a l'actuel
+ if (currentPathType() == path_type) {
+ if (conductor_profiles[path_type].isNull()) {
+ generateConductorPath(terminal1 -> dockConductor(), terminal1 -> orientation(), terminal2 -> dockConductor(), terminal2 -> orientation());
+ modified_path = false;
+ } else {
+ updateConductorPath(terminal1 -> dockConductor(), terminal1 -> orientation(), terminal2 -> dockConductor(), terminal2 -> orientation());
+ modified_path = true;
+ }
+ if (type() == ConductorProperties::Multi) {
+ calculateTextItemPosition();
+ }
+ }
+}
+
+/// @return le profil de ce conducteur
+ConductorProfile Conductor::profile(Qt::Corner path_type) const {
+ return(conductor_profiles[path_type]);
+}
+
+/// @return le texte du conducteur
+QString Conductor::text() const {
+ return(text_item -> toPlainText());
+}
+
+/**
+ @param t Nouveau texte du conducteur
+*/
+void Conductor::setText(const QString &t) {
+ text_item -> setPlainText(t);
+}
+
+/// @param p les proprietes de ce conducteur
+void Conductor::setProperties(const ConductorProperties &p) {
+ properties_ = p;
+ readProperties();
+}
+
+/// @return les proprietes de ce conducteur
+ConductorProperties Conductor::properties() const {
+ return(properties_);
+}
+
+/**
+ Relit les proprietes et les applique
+*/
+void Conductor::readProperties() {
+ // la couleur n'est vraiment applicable que lors du rendu du conducteur
+ setText(properties_.text);
+ calculateTextItemPosition();
+ text_item -> setVisible(properties_.type == ConductorProperties::Multi);
+}
+
+/**
+ S'assure que le texte du conducteur est a une position raisonnable
+ Cette methode ne fait rien si ce conducteur n'affiche pas son champ de
+ texte.
+*/
+void Conductor::adjustTextItemPosition() {
+ calculateTextItemPosition();
+}
+
+/**
+ @return true si le conducteur est mis en evidence
+*/
+Conductor::Highlight Conductor::highlight() const {
+ return(must_highlight_);
+}
+
+/**
+ @param hl true pour mettre le conducteur en evidence, false sinon
+*/
+void Conductor::setHighlighted(Conductor::Highlight hl) {
+ must_highlight_ = hl;
+ update();
+}
+
+/**
+ * @brief Conductor::autoText
+ *lance l'autoNumerotation sur ce conducteur
+ */
+void Conductor::autoText() {
+ ConductorAutoNumerotation can(this);
+ can.numerate();
+}
+
+/**
+ Met a jour les proprietes du conducteur apres modification du champ de texte affiche
+*/
+void Conductor::displayedTextChanged() {
+ // verifie que le texte a reellement change
+ if (text_item -> toPlainText() == properties_.text) return;
+
+ if (Diagram *my_diagram = diagram()) {
+ int qmbreturn=0;
+ //if conductor isn't alone at this potential
+ //ask user to apply text on every conductors of this potential
+ if (relatedPotentialConductors().size() >= 1){
+ qmbreturn = QMessageBox::question(diagramEditor(), tr("Textes de conducteurs"),
+ tr("Voulez-vous appliquer le nouveau texte \n"
+ "\340 l'ensemble des conducteurs de ce potentiel ?"),
+ QMessageBox::No| QMessageBox::Yes, QMessageBox::Yes);
+ if (qmbreturn == QMessageBox::Yes){
+ ConductorAutoNumerotation can(this);
+ can.applyText(text_item -> toPlainText());
+ }
+ }
+ if (qmbreturn == 0 || qmbreturn == QMessageBox::No) {
+ // initialise l'objet UndoCommand correspondant
+ ConductorProperties new_properties(properties_);
+ new_properties.text = text_item -> toPlainText();
+
+ ChangeConductorPropertiesCommand *ccpc = new ChangeConductorPropertiesCommand(this);
+ ccpc -> setOldSettings(properties_);
+ ccpc -> setNewSettings(new_properties);
+ my_diagram -> undoStack().push(ccpc);
+ }
+ }
+}
+
+/**
+ @return les conducteurs avec lesquels ce conducteur partage des bornes
+ communes
+*/
+QSet<Conductor *> Conductor::relatedConductors() const {
+ QList<Conductor *> other_conductors_list = terminal1 -> conductors();
+ other_conductors_list += terminal2 -> conductors();
+ QSet<Conductor *> other_conductors = other_conductors_list.toSet();
+ other_conductors.remove(const_cast<Conductor *>(this));
+ return(other_conductors);
+}
+
+/**
+ * @param t_list terminaux a ne pas inclure dans la recherche
+ * @return les conducteurs avec lesquels ce conducteur partage
+ * le meme potentiel electrique a l'exception de lui même
+ */
+QSet<Conductor *> Conductor::relatedPotentialConductors(QList <Terminal *> *t_list) {
+ bool declar_t_list = false;
+ if (t_list == 0) {
+ declar_t_list = true;
+ t_list = new QList <Terminal *>;
+ }
+
+ QSet <Conductor *> other_conductors;
+ //renvoie tous les conducteurs du terminal 1
+ if (!t_list -> contains(terminal1)) {
+ t_list -> append(terminal1);
+ QList <Conductor *> other_conductors_list_t1 = terminal1 -> conductors();
+ other_conductors_list_t1.removeAll(this);
+ //recherche les conducteurs connecté au conducteur déjà trouvé
+ foreach (Conductor *c, other_conductors_list_t1) {
+ other_conductors += c -> relatedPotentialConductors(t_list);
+ }
+ other_conductors += other_conductors_list_t1.toSet();
+ }
+ //renvoie tous les conducteurs du terminal 2
+ if (!t_list -> contains(terminal2)) {
+ t_list -> append(terminal2);
+ QList <Conductor *> other_conductors_list_t2 = terminal2 -> conductors();
+ other_conductors_list_t2.removeAll(this);
+ //recherche les conducteurs connecté au conducteur déjà trouvé
+ foreach (Conductor *c, other_conductors_list_t2) {
+ other_conductors += c -> relatedPotentialConductors(t_list);
+ }
+ other_conductors += other_conductors_list_t2.toSet();
+ }
+ other_conductors.remove(const_cast<Conductor *>(this));
+
+ if (declar_t_list) delete t_list;
+ return(other_conductors);
+}
+
+/**
+ * @return l'editeur de schemas parent ou 0
+ */
+QETDiagramEditor* Conductor::diagramEditor() const {
+ QWidget *w = const_cast<QGraphicsView *>(diagram() -> views().at(0));
+ while (w -> parentWidget() && !w -> isWindow()) {
+ w = w -> parentWidget();
+ }
+ return(qobject_cast<QETDiagramEditor *>(w));
+}
+
+/**
+ @param a reel
+ @param b reel
+ @param c reel
+ @return true si a est entre b et c ou est egal a l'un des deux
+*/
+bool isBetween(qreal a, qreal b, qreal c) {
+ if (b <= c) {
+ return(a >= b && a <= c);
+ } else {
+ return(a <= b && a >= c);
+ }
+}
+
+/**
+ @param a point
+ @param b point
+ @param c point
+ @return true si le point a est contenu dans le rectangle delimite par les points b et c
+*/
+bool isContained(const QPointF &a, const QPointF &b, const QPointF &c) {
+ return(
+ isBetween(a.x(), b.x(), c.x()) &&
+ isBetween(a.y(), b.y(), c.y())
+ );
+}
+
+/**
+ @return la liste des positions des jonctions avec d'autres conducteurs
+*/
+QList<QPointF> Conductor::junctions() const {
+ QList<QPointF> junctions_list;
+
+ // pour qu'il y ait des jonctions, il doit y avoir d'autres conducteurs et des bifurcations
+ QSet<Conductor *> other_conductors = relatedConductors();
+ QList<ConductorBend> bends_list = bends();
+ if (other_conductors.isEmpty() || bends_list.isEmpty()) {
+ return(junctions_list);
+ }
+
+ QList<QPointF> points = segmentsToPoints();
+ for (int i = 1 ; i < (points.size() -1) ; ++ i) {
+ QPointF point = points.at(i);
+
+ // determine si le point est une bifurcation ou non
+ bool is_bend = false;
+ Qt::Corner current_bend_type = Qt::TopLeftCorner;
+ foreach(ConductorBend cb, bends_list) {
+ if (cb.first == point) {
+ is_bend = true;
+ current_bend_type = cb.second;
+ break;
+ }
+ }
+ // si le point n'est pas une bifurcation, il ne peut etre une jonction (enfin pas au niveau de ce conducteur)
+ if (!is_bend) continue;
+
+ bool is_junction = false;
+ QPointF scene_point = mapToScene(point);
+ foreach(Conductor *c, other_conductors) {
+ // exprime le point dans les coordonnees de l'autre conducteur
+ QPointF conductor_point = c -> mapFromScene(scene_point);
+ // recupere les segments de l'autre conducteur
+ QList<ConductorSegment *> c_segments = c -> segmentsList();
+ if (c_segments.isEmpty()) continue;
+ // parcoure les segments a la recherche d'un point commun
+ for (int j = 0 ; j < c_segments.count() ; ++ j) {
+ ConductorSegment *segment = c_segments[j];
+ // un point commun a ete trouve sur ce segment
+ if (isContained(conductor_point, segment -> firstPoint(), segment -> secondPoint())) {
+ is_junction = true;
+ // ce point commun ne doit pas etre une bifurcation identique a celle-ci
+ QList<ConductorBend> other_conductor_bends = c -> bends();
+ foreach(ConductorBend cb, other_conductor_bends) {
+ if (cb.first == conductor_point && cb.second == current_bend_type) {
+ is_junction = false;
+ }
+ }
+ }
+ if (is_junction) junctions_list << point;
+ }
+ }
+ }
+ return(junctions_list);
+}
+
+/**
+ @return la liste des bifurcations de ce conducteur ; ConductorBend est un
+ typedef pour une QPair\<QPointF, Qt::Corner\>. Le point indique la position
+ (en coordonnees locales) de la bifurcation tandis que le Corner indique le
+ type de bifurcation.
+*/
+QList<ConductorBend> Conductor::bends() const {
+ QList<ConductorBend> points;
+ if (!segments) return(points);
+
+ // recupere la liste des segments de taille non nulle
+ QList<ConductorSegment *> visible_segments;
+ ConductorSegment *segment = segments;
+ while (segment -> hasNextSegment()) {
+ if (!segment -> isPoint()) visible_segments << segment;
+ segment = segment -> nextSegment();
+ }
+ if (!segment -> isPoint()) visible_segments << segment;
+
+ ConductorSegment *next_segment;
+ for (int i = 0 ; i < visible_segments.count() -1 ; ++ i) {
+ segment = visible_segments[i];
+ next_segment = visible_segments[i + 1];
+ if (!segment -> isPoint() && !next_segment -> isPoint()) {
+ // si les deux segments ne sont pas dans le meme sens, on a une bifurcation
+ if (next_segment -> type() != segment -> type()) {
+ Qt::Corner bend_type;
+ qreal sl = segment -> length();
+ qreal nsl = next_segment -> length();
+
+ if (segment -> isHorizontal()) {
+ if (sl < 0 && nsl < 0) {
+ bend_type = Qt::BottomLeftCorner;
+ } else if (sl < 0 && nsl > 0) {
+ bend_type = Qt::TopLeftCorner;
+ } else if (sl > 0 && nsl < 0) {
+ bend_type = Qt::BottomRightCorner;
+ } else {
+ bend_type = Qt::TopRightCorner;
+ }
+ } else {
+ if (sl < 0 && nsl < 0) {
+ bend_type = Qt::TopRightCorner;
+ } else if (sl < 0 && nsl > 0) {
+ bend_type = Qt::TopLeftCorner;
+ } else if (sl > 0 && nsl < 0) {
+ bend_type = Qt::BottomRightCorner;
+ } else {
+ bend_type = Qt::BottomLeftCorner;
+ }
+ }
+ points << qMakePair(segment -> secondPoint(), bend_type);
+ }
+ }
+ }
+ return(points);
+}
+
+/**
+ @param p Point, en coordonnees locales
+ @return true si le point p appartient au trajet du conducteur
+*/
+bool Conductor::containsPoint(const QPointF &p) const {
+ if (!segments) return(false);
+ ConductorSegment *segment = segments;
+ while (segment -> hasNextSegment()) {
+ QRectF rect(segment -> firstPoint(), segment -> secondPoint());
+ if (rect.contains(p)) return(true);
+ segment = segment -> nextSegment();
+ }
+ return(false);
+}
+
+/**
+ @param start Point de depart
+ @param end Point d'arrivee
+ @return le coin vers lequel se dirige le trajet de start vers end
+*/
+Qt::Corner Conductor::movementType(const QPointF &start, const QPointF &end) {
+ Qt::Corner result = Qt::BottomRightCorner;
+ if (start.x() <= end.x()) {
+ result = start.y() <= end.y() ? Qt::BottomRightCorner : Qt::TopRightCorner;
+ } else {
+ result = start.y() <= end.y() ? Qt::BottomLeftCorner : Qt::TopLeftCorner;
+ }
+ return(result);
+}
+
+/// @return le type de trajet actuel de ce conducteur
+Qt::Corner Conductor::currentPathType() const {
+ return(movementType(terminal1 -> dockConductor(), terminal2 -> dockConductor()));
+}
+
+/// @return les profils de ce conducteur
+ConductorProfilesGroup Conductor::profiles() const {
+ return(conductor_profiles);
+}
+
+/**
+ @param cpg Les nouveaux profils de ce conducteur
+*/
+void Conductor::setProfiles(const ConductorProfilesGroup &cpg) {
+ conductor_profiles = cpg;
+ if (conductor_profiles[currentPathType()].isNull()) {
+ generateConductorPath(terminal1 -> dockConductor(), terminal1 -> orientation(), terminal2 -> dockConductor(), terminal2 -> orientation());
+ modified_path = false;
+ } else {
+ updateConductorPath(terminal1 -> dockConductor(), terminal1 -> orientation(), terminal2 -> dockConductor(), terminal2 -> orientation());
+ modified_path = true;
+ }
+ if (type() == ConductorProperties::Multi) {
+ calculateTextItemPosition();
+ }
+}
+
+/// Supprime les segments
+void Conductor::deleteSegments() {
+ if (segments != NULL) {
+ while (segments -> hasNextSegment()) delete segments -> nextSegment();
+ delete segments;
+ segments = NULL;
+ }
+}
+
+/**
+ @param point Un point situe a l'exterieur du polygone
+ @param polygon Le polygone dans lequel on veut rapatrier le point
+ @return la position du point, une fois ramene dans le polygone, ou plus
+ exactement sur le bord du polygone
+*/
+QPointF Conductor::movePointIntoPolygon(const QPointF &point, const QPainterPath &polygon) {
+ // decompose le polygone en lignes et points
+ QList<QPolygonF> polygons = polygon.simplified().toSubpathPolygons();
+ QList<QLineF> lines;
+ QList<QPointF> points;
+ foreach(QPolygonF polygon, polygons) {
+ if (polygon.count() <= 1) continue;
+
+ // on recense les lignes et les points
+ for (int i = 1 ; i < polygon.count() ; ++ i) {
+ lines << QLineF(polygon.at(i - 1), polygon.at(i));
+ points << polygon.at(i -1);
+ }
+ }
+
+ // on fait des projetes orthogonaux du point sur les differents segments du
+ // polygone, en les triant par longueur croissante
+ QMap<qreal, QPointF> intersections;
+ foreach (QLineF line, lines) {
+ QPointF intersection_point;
+ if (QET::orthogonalProjection(point, line, &intersection_point)) {
+ intersections.insert(QLineF(intersection_point, point).length(), intersection_point);
+ }
+ }
+ if (intersections.count()) {
+ // on determine la plus courte longueur pour un projete orthogonal
+ QPointF the_point = intersections[intersections.keys().first()];
+ return(the_point);
+ } else {
+ // determine le coin du polygone le plus proche du point exterieur
+ qreal minimum_length = -1;
+ int point_index = -1;
+ for (int i = 0 ; i < points.count() ; ++ i) {
+ qreal length = qAbs(QLineF(points.at(i), point).length());
+ if (minimum_length < 0 || length < minimum_length) {
+ minimum_length = length;
+ point_index = i;
+ }
+ }
+ // on connait desormais le coin le plus proche du texte
+
+ // aucun projete orthogonal n'a donne quoi que ce soit, on met le texte sur un des coins du polygone
+ return(points.at(point_index));
+ }
+}
Added: branches/devel/sources/qetgraphicsitem/conductor.h
===================================================================
--- branches/devel/sources/qetgraphicsitem/conductor.h (rev 0)
+++ branches/devel/sources/qetgraphicsitem/conductor.h 2013-11-07 09:18:03 UTC (rev 2596)
@@ -0,0 +1,170 @@
+/*
+ Copyright 2006-2013 The QElectroTech Team
+ 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/>.
+*/
+#ifndef CONDUCTOR_H
+#define CONDUCTOR_H
+#include <QtGui>
+#include "terminal.h"
+#include "conductorprofile.h"
+#include "conductorproperties.h"
+#include "qetdiagrameditor.h"
+class ConductorSegment;
+class ConductorTextItem;
+class Element;
+typedef QPair<QPointF, Qt::Corner> ConductorBend;
+typedef QHash<Qt::Corner, ConductorProfile> ConductorProfilesGroup;
+/**
+ This class represents a conductor, i.e. a wire between two element
+ terminals.
+*/
+class Conductor : public QObject, public QGraphicsPathItem {
+
+ Q_OBJECT
+
+ // constructors, destructor
+ public:
+ Conductor(Terminal *, Terminal *, Diagram * = 0);
+ virtual ~Conductor();
+
+ private:
+ Conductor(const Conductor &);
+
+ // attributes
+ public:
+ enum { Type = UserType + 1001 };
+ enum Highlight { None, Normal, Alert };
+
+ /// First terminal the wire is attached to
+ Terminal *terminal1;
+ /// Second terminal the wire is attached to
+ Terminal *terminal2;
+
+ // methods
+ public:
+ /**
+ Enable the use of qgraphicsitem_cast to safely cast a QGraphicsItem into a
+ Conductor.
+ @return the QGraphicsItem type
+ */
+ virtual int type() const { return Type; }
+ void destroy();
+ /// @return true if this conductor is destroyed
+ bool isDestroyed() const { return(destroyed_); }
+ Diagram *diagram() const;
+ ConductorTextItem *textItem() const;
+ void updatePath(const QRectF & = QRectF());
+ void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *);
+ QRectF boundingRect() const;
+ virtual QPainterPath shape() const;
+ virtual qreal nearDistance() const;
+ virtual QPainterPath nearShape() const;
+ virtual QPainterPath variableShape(const qreal &) const;
+ virtual bool isNearConductor(const QPointF &);
+ qreal length();
+ ConductorSegment *middleSegment();
+ bool containsPoint(const QPointF &) const;
+ QString text() const;
+ void setText(const QString &);
+ static bool valideXml(QDomElement &);
+ bool fromXml(QDomElement &);
+ QDomElement toXml(QDomDocument &, QHash<Terminal *, int> &) const;
+ const QList<ConductorSegment *> segmentsList() const;
+ void setProperties(const ConductorProperties &);
+ ConductorProperties properties() const;
+ void setProfile(const ConductorProfile &, Qt::Corner);
+ ConductorProfile profile(Qt::Corner) const;
+ void setProfiles(const ConductorProfilesGroup &);
+ ConductorProfilesGroup profiles() const;
+ void readProperties();
+ void adjustTextItemPosition();
+ virtual Highlight highlight() const;
+ virtual void setHighlighted(Highlight);
+ void autoText();
+ QSet<Conductor *> relatedPotentialConductors(QList <Terminal *> *t_list=0);
+ QETDiagramEditor* diagramEditor() const;
+
+ public slots:
+ void displayedTextChanged();
+
+ protected:
+ virtual void mousePressEvent(QGraphicsSceneMouseEvent *);
+ virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *);
+ virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *);
+ virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *);
+ virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent *);
+ virtual void hoverMoveEvent(QGraphicsSceneHoverEvent *);
+ virtual QVariant itemChange(GraphicsItemChange, const QVariant &);
+
+ private:
+ /// Functional properties
+ ConductorProperties properties_;
+ /// Whether this conductor is still valid
+ bool destroyed_;
+ /// Text input for non simple, non-singleline conductors
+ ConductorTextItem *text_item;
+ /// Segments composing the conductor
+ ConductorSegment *segments;
+ /// Attributs related to mouse interaction
+ QPointF press_point;
+ bool moving_point;
+ bool moving_segment;
+ int moved_point;
+ qreal previous_z_value;
+ ConductorSegment *moved_segment;
+ QPointF before_mov_text_pos_;
+ /// Whether the conductor was manually modified by users
+ bool modified_path;
+ /// Whether the current profile should be saved as soon as possible
+ bool has_to_save_profile;
+ /// conductor profile: "photography" of what the conductor is supposed to look
+ /// like - there is one profile per kind of traject
+ ConductorProfilesGroup conductor_profiles;
+ /// QPen et QBrush objects used to draw conductors
+ static QPen conductor_pen;
+ static QBrush conductor_brush;
+ static QBrush square_brush;
+ static bool pen_and_brush_initialized;
+ /// Scale factor to render square used to move segments
+ qreal segments_squares_scale_;
+ /// Define whether and how the conductor should be highlighted
+ Highlight must_highlight_;
+
+ private:
+ void segmentsToPath();
+ void saveProfile(bool = true);
+ void generateConductorPath(const QPointF &, QET::Orientation, const QPointF &, QET::Orientation);
+ void updateConductorPath(const QPointF &, QET::Orientation, const QPointF &, QET::Orientation);
+ uint segmentsCount(QET::ConductorSegmentType = QET::Both) const;
+ QList<QPointF> segmentsToPoints() const;
+ QSet<Conductor *> relatedConductors() const;
+ QList<ConductorBend> bends() const;
+ QList<QPointF> junctions() const;
+ void pointsToSegments(QList<QPointF>);
+ bool hasClickedOn(QPointF, QPointF) const;
+ void calculateTextItemPosition();
+ Qt::Corner currentPathType() const;
+ void deleteSegments();
+ static int getCoeff(const qreal &, const qreal &);
+ static int getSign(const qreal &);
+ QHash<ConductorSegmentProfile *, qreal> shareOffsetBetweenSegments(const qreal &offset, const QList<ConductorSegmentProfile *> &, const qreal & = 0.01) const;
+ static QPointF extendTerminal(const QPointF &, QET::Orientation, qreal = 9.0);
+ static qreal conductor_bound(qreal, qreal, qreal, qreal = 0.0);
+ static qreal conductor_bound(qreal, qreal, bool);
+ static Qt::Corner movementType(const QPointF &, const QPointF &);
+ static QPointF movePointIntoPolygon(const QPointF &, const QPainterPath &);
+};
+#endif
Added: branches/devel/sources/qetgraphicsitem/conductortextitem.cpp
===================================================================
--- branches/devel/sources/qetgraphicsitem/conductortextitem.cpp (rev 0)
+++ branches/devel/sources/qetgraphicsitem/conductortextitem.cpp 2013-11-07 09:18:03 UTC (rev 2596)
@@ -0,0 +1,223 @@
+/*
+ Copyright 2006-2013 The QElectroTech Team
+ 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/>.
+*/
+#include "conductortextitem.h"
+#include "conductor.h"
+#include "diagramcommands.h"
+
+/**
+ Constructeur
+ @param parent_conductor Conducteur auquel ce texte est rattache
+ @param parent_diagram Schema auquel ce texte et son conducteur parent sont rattaches
+*/
+ConductorTextItem::ConductorTextItem(Conductor *parent_conductor, Diagram *parent_diagram) :
+ DiagramTextItem(parent_conductor, parent_diagram),
+ parent_conductor_(parent_conductor),
+ moved_by_user_(false),
+ rotate_by_user_(false),
+ first_move_(true)
+{
+ // par defaut, les DiagramTextItem sont Selectable et Movable
+ // cela nous convient, on ne touche pas a ces flags
+}
+
+/**
+ Constructeur
+ @param text Le texte affiche par le champ de texte
+ @param parent_conductor Conducteur auquel ce texte est rattache
+ @param parent_diagram Schema auquel ce texte et son conducteur parent sont rattaches
+*/
+ConductorTextItem::ConductorTextItem(const QString &text, Conductor *parent_conductor, Diagram *parent_diagram) :
+ DiagramTextItem(text, parent_conductor, parent_diagram),
+ parent_conductor_(parent_conductor),
+ moved_by_user_(false),
+ rotate_by_user_(false),
+ first_move_(true)
+{
+ // par defaut, les DiagramTextItem sont Selectable et Movable
+ // cela nous convient, on ne touche pas a ces flags
+}
+
+/**
+ Destructeur
+*/
+ConductorTextItem::~ConductorTextItem() {
+}
+
+/**
+ @return le conducteur parent de ce champ de texte, ou 0 si celui-ci n'en a
+ pas
+*/
+Conductor *ConductorTextItem::parentConductor() const {
+ return(parent_conductor_);
+}
+
+/**
+ Permet de lire le texte a mettre dans le champ a partir d'un element XML.
+ Cette methode se base sur la position du champ pour assigner ou non la
+ valeur a ce champ.
+ @param e L'element XML representant le champ de texte
+*/
+void ConductorTextItem::fromXml(const QDomElement &e) {
+ setPlainText(e.attribute("text"));
+
+ qreal user_pos_x, user_pos_y;
+ if (
+ QET::attributeIsAReal(e, "userx", &user_pos_x) &&
+ QET::attributeIsAReal(e, "usery", &user_pos_y)
+ ) {
+ setPos(user_pos_x, user_pos_y);
+ }
+
+ setRotationAngle(e.attribute("rotation").toDouble());
+}
+
+/**
+ @param document Le document XML a utiliser
+ @return L'element XML representant ce champ de texte
+*/
+QDomElement ConductorTextItem::toXml(QDomDocument &document) const {
+ QDomElement result = document.createElement("input");
+ result.setAttribute("userx", QString("%1").arg(pos().x()));
+ result.setAttribute("usery", QString("%1").arg(pos().y()));
+ result.setAttribute("text", toPlainText());
+ if (rotationAngle()) {
+ result.setAttribute("rotation", QString("%1").arg(rotationAngle()));
+ }
+ return(result);
+}
+
+/**
+ @return true si ce champ de texte a ete explictement deplace par
+ l'utilisateur, false sinon
+*/
+bool ConductorTextItem::wasMovedByUser() const {
+ return(moved_by_user_);
+}
+
+/**
+ * @brief ConductorTextItem::wasRotateByUser
+ * @return true if text was explicit moved by user else false
+ */
+bool ConductorTextItem::wasRotateByUser() const {
+ return(rotate_by_user_);
+}
+
+/**
+ @param moved_by_user true pour que la position du texte soit consideree
+ comme ayant ete definie par l'utilisateur (et donc soit sauvegardee), false
+ pour remettre le texte a sa position originelle
+*/
+void ConductorTextItem::forceMovedByUser(bool moved_by_user) {
+ if (moved_by_user == moved_by_user_) return;
+
+ moved_by_user_ = moved_by_user;
+ if (!moved_by_user && parent_conductor_) {
+ parent_conductor_ -> adjustTextItemPosition();
+ }
+
+}
+
+/**
+ * @brief ConductorTextItem::forceRotateByUser
+ * @param rotate_by_user true pour que la rotation du texte soit consideree
+ comme ayant ete definie par l'utilisateur (et donc soit sauvegardee), false
+ pour remettre le texte a sont angle originelle
+ */
+void ConductorTextItem::forceRotateByUser(bool rotate_by_user) {
+ if (rotate_by_user == rotate_by_user_) return;
+
+ rotate_by_user_ = rotate_by_user;
+ if (!rotate_by_user && parent_conductor_) {
+ parent_conductor_ -> adjustTextItemPosition();
+ }
+}
+
+/**
+ Gere les clics de souris lies au champ de texte
+ @param e Objet decrivant l'evenement souris
+*/
+void ConductorTextItem::mousePressEvent(QGraphicsSceneMouseEvent *e) {
+ if ((flags() & QGraphicsItem::ItemIsMovable) && (e -> buttons() & Qt::LeftButton)) {
+ before_mov_pos_ = pos();
+ }
+ first_move_ = true;
+ DiagramTextItem::mousePressEvent(e);
+}
+
+/**
+ Gere les mouvements de souris lies au champ de texte
+ @param e Objet decrivant l'evenement souris
+*/
+void ConductorTextItem::mouseMoveEvent(QGraphicsSceneMouseEvent *e) {
+ if (textInteractionFlags() & Qt::TextEditable) {
+ QGraphicsTextItem::mouseMoveEvent(e);
+ } else if ((flags() & QGraphicsItem::ItemIsMovable) && (e -> buttons() & Qt::LeftButton)) {
+ if (first_move_) {
+ mouse_to_origin_movement_ = before_mov_pos_ - mapToParent(e -> buttonDownPos(Qt::LeftButton));
+ }
+
+ QPointF intended_pos = mapToParent(e -> pos()) + mouse_to_origin_movement_;
+ // si ce texte est attache a un conducteur, alors ses mouvements seront
+ // limites a une certaine distance du trace de ce conducteur
+ if (parent_conductor_) {
+ if (parent_conductor_ -> isNearConductor(intended_pos)) {
+ setPos(intended_pos);
+ parent_conductor_ -> setHighlighted(Conductor::Normal);
+ } else {
+ parent_conductor_ -> setHighlighted(Conductor::Alert);
+ }
+ }
+
+ } else e -> ignore();
+
+ if (first_move_) {
+ first_move_ = false;
+ }
+}
+
+/**
+ Gere le relachement de souris
+ Cette methode cree un objet d'annulation pour le deplacement
+ @param e Objet decrivant l'evenement souris
+*/
+void ConductorTextItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *e) {
+ if (flags() & QGraphicsItem::ItemIsMovable) {
+ if (Diagram *diagram_ptr = diagram()) {
+ // on cree un objet d'annulation correspondant au deplacement qui s'acheve
+ QPointF applied_movement = pos() - before_mov_pos_;
+
+ if (!applied_movement.isNull()) {
+ // on cree un objet d'annulation seulement pour ce champ de texte
+ MoveConductorsTextsCommand *undo_object = new MoveConductorsTextsCommand(diagram_ptr);
+ undo_object -> addTextMovement(this, before_mov_pos_, pos(), moved_by_user_);
+
+ // on active le flag indiquant que ce champ de texte a ete explicitement repositionne par l'utilisateur
+ moved_by_user_ = true;
+
+ diagram_ptr -> undoStack().push(undo_object);
+ }
+
+ if (parent_conductor_) {
+ parent_conductor_ -> setHighlighted(Conductor::None);
+ }
+ }
+ }
+ if (!(e -> modifiers() & Qt::ControlModifier)) {
+ QGraphicsTextItem::mouseReleaseEvent(e);
+ }
+}
Added: branches/devel/sources/qetgraphicsitem/conductortextitem.h
===================================================================
--- branches/devel/sources/qetgraphicsitem/conductortextitem.h (rev 0)
+++ branches/devel/sources/qetgraphicsitem/conductortextitem.h 2013-11-07 09:18:03 UTC (rev 2596)
@@ -0,0 +1,69 @@
+/*
+ Copyright 2006-2013 The QElectroTech Team
+ 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/>.
+*/
+#ifndef CONDUCTOR_TEXT_ITEM_H
+#define CONDUCTOR_TEXT_ITEM_H
+#include "diagramtextitem.h"
+class Conductor;
+/**
+ This class represents a text item attached to a parent conductor.
+ It may be moved and edited by users.
+ It may also be rotated to any angle.
+ Its movements are however limited to a particular distance around its
+ parent conductor.
+*/
+class ConductorTextItem : public DiagramTextItem {
+ Q_OBJECT
+
+ // constructors, destructor
+ public:
+ ConductorTextItem(Conductor * = 0, Diagram * = 0);
+ ConductorTextItem(const QString &, Conductor * = 0, Diagram * = 0);
+ virtual ~ConductorTextItem();
+ private:
+ ConductorTextItem(const ConductorTextItem &);
+
+ // attributes
+ public:
+ enum { Type = UserType + 1006 };
+ Conductor *parentConductor() const;
+ virtual void fromXml(const QDomElement &);
+ virtual QDomElement toXml(QDomDocument &) const;
+
+ // methods
+ public:
+ virtual int type() const { return Type; }
+ virtual bool wasMovedByUser() const;
+ virtual bool wasRotateByUser() const;
+ virtual void forceMovedByUser(bool);
+ virtual void forceRotateByUser(bool);
+
+ protected:
+ virtual void mousePressEvent(QGraphicsSceneMouseEvent *);
+ virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *);
+ virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *);
+
+ // attributes
+ private:
+ Conductor *parent_conductor_;
+ bool moved_by_user_;
+ bool rotate_by_user_;
+ QPointF before_mov_pos_;
+ bool first_move_;
+ QPointF mouse_to_origin_movement_;
+};
+#endif
Added: branches/devel/sources/qetgraphicsitem/customelement.cpp
===================================================================
--- branches/devel/sources/qetgraphicsitem/customelement.cpp (rev 0)
+++ branches/devel/sources/qetgraphicsitem/customelement.cpp 2013-11-07 09:18:03 UTC (rev 2596)
@@ -0,0 +1,806 @@
+/*
+ Copyright 2006-2013 The QElectroTech Team
+ 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/>.
+*/
+#include "customelement.h"
+#include "elementtextitem.h"
+#include "diagram.h"
+#include "qetapp.h"
+#include "partline.h"
+#include "elementdefinition.h"
+#include <iostream>
+
+/**
+ Constructeur de la classe CustomElement. Permet d'instancier un element
+ utilisable comme un element fixe a la difference que l'element perso est
+ construit a partir d'une description au format XML. Celle-ci est recuperee
+ a l'emplacement indique.
+ @param location Emplacement de la definition d'element a utiliser
+ @param qgi Le QGraphicsItem parent de cet element
+ @param s Le Schema affichant cet element
+ @param state Un pointeur facultatif vers un entier. La valeur de cet entier
+ sera changee de maniere a refleter le deroulement de l'instanciation :
+ - 0 : L'instanciation a reussi
+ - 1 : l'emplacement n'a pas permis d'acceder a une definition d'element
+ - 2 : la definition n'etait pas lisible
+ - 3 : la definition n'etait pas valide / exploitable / utilisable
+ - 4 : Le document XML n'est pas un element "definition"
+ - 5 : Les attributs de la definition ne sont pas presents et / ou valides
+ - 6 : La definition est vide
+ - 7 : L'analyse d'un element XML decrivant une partie du dessin de l'element a echoue
+ - 8 : Aucune partie du dessin n'a pu etre chargee
+*/
+CustomElement::CustomElement(const ElementsLocation &location, QGraphicsItem *qgi, Diagram *s, int *state) :
+ FixedElement(qgi, s),
+ elmt_state(-1),
+ location_(location),
+ forbid_antialiasing(false)
+{
+ // recupere la definition de l'element
+ ElementsCollectionItem *element_item = QETApp::collectionItem(location);
+ ElementDefinition *element_definition;
+ if (
+ !element_item ||\
+ !element_item -> isElement() ||\
+ !(element_definition = qobject_cast<ElementDefinition *>(element_item))
+ ) {
+ if (state) *state = 1;
+ elmt_state = 1;
+ return;
+ }
+
+ if (!element_definition -> isReadable()) {
+ if (state) *state = 2;
+ elmt_state = 2;
+ return;
+ }
+
+ if (element_definition -> isNull()) {
+ if (state) *state = 3;
+ elmt_state = 3;
+ return;
+ }
+
+ buildFromXml(element_definition -> xml(), &elmt_state);
+ if (state) *state = elmt_state;
+ if (elmt_state) return;
+
+ if (state) *state = 0;
+ elmt_state = 0;
+}
+
+CustomElement::CustomElement(const QDomElement &xml_def_elmt, QGraphicsItem *qgi, Diagram *s, int *state) : FixedElement(qgi, s) {
+ int elmt_state = -1;
+ buildFromXml(xml_def_elmt, &elmt_state);
+ if (state) *state = elmt_state;
+}
+
+/**
+ Construit l'element personnalise a partir d'un element XML representant sa
+ definition.
+ @param xml_def_elmt
+ @param state Un pointeur facultatif vers un entier. La valeur de cet entier
+ sera changee de maniere a refleter le deroulement de l'instanciation :
+ - 0 : La construction s'est bien passee
+ - 4 : Le document XML n'est pas un element "definition"
+ - 5 : Les attributs de la definition ne sont pas presents et / ou valides
+ - 6 : La definition est vide
+ - 7 : L'analyse d'un element XML decrivant une partie du dessin de l'element a echoue
+ - 8 : Aucune partie du dessin n'a pu etre chargee
+ @return true si le chargement a reussi, false sinon
+*/
+bool CustomElement::buildFromXml(const QDomElement &xml_def_elmt, int *state) {
+
+ if (xml_def_elmt.tagName() != "definition" || xml_def_elmt.attribute("type") != "element") {
+ if (state) *state = 4;
+ return(false);
+ }
+
+ // verifie basiquement que la version actuelle est capable de lire ce fichier
+ if (xml_def_elmt.hasAttribute("version")) {
+ bool conv_ok;
+ qreal element_version = xml_def_elmt.attribute("version").toDouble(&conv_ok);
+ if (conv_ok && QET::version.toDouble() < element_version) {
+ std::cerr << qPrintable(
+ QObject::tr("Avertissement : l'\351l\351ment "
+ " a \351t\351 enregistr\351 avec une version"
+ " ult\351rieure de QElectroTech.")
+ ) << std::endl;
+ }
+ }
+
+ // ces attributs doivent etre presents et valides
+ int w, h, hot_x, hot_y;
+ if (
+ !QET::attributeIsAnInteger(xml_def_elmt, QString("width"), &w) ||\
+ !QET::attributeIsAnInteger(xml_def_elmt, QString("height"), &h) ||\
+ !QET::attributeIsAnInteger(xml_def_elmt, QString("hotspot_x"), &hot_x) ||\
+ !QET::attributeIsAnInteger(xml_def_elmt, QString("hotspot_y"), &hot_y) ||\
+ !validOrientationAttribute(xml_def_elmt)
+ ) {
+ if (state) *state = 5;
+ return(false);
+ }
+
+ // on peut d'ores et deja specifier la taille et le hotspot
+ setSize(w, h);
+ setHotspot(QPoint(hot_x, hot_y));
+ setInternalConnections(xml_def_elmt.attribute("ic") == "true");
+
+ // la definition est supposee avoir des enfants
+ if (xml_def_elmt.firstChild().isNull()) {
+ if (state) *state = 6;
+ return(false);
+ }
+
+ // initialisation du QPainter (pour dessiner l'element)
+ QPainter qp;
+ qp.begin(&drawing);
+
+ QPainter low_zoom_qp;
+ low_zoom_qp.begin(&low_zoom_drawing);
+ QPen tmp;
+ tmp.setWidthF(1.0); // ligne vaudou pour prise en compte du setCosmetic - ne pas enlever
+ tmp.setCosmetic(true);
+ low_zoom_qp.setPen(tmp);
+
+ // extrait les noms de la definition XML
+ names.fromXml(xml_def_elmt);
+ setToolTip(name());
+
+ // parcours des enfants de la definition : parties du dessin
+ int parsed_elements_count = 0;
+ for (QDomNode node = xml_def_elmt.firstChild() ; !node.isNull() ; node = node.nextSibling()) {
+ QDomElement elmts = node.toElement();
+ if (elmts.isNull()) continue;
+ if (elmts.tagName() == "description") {
+ // gestion de la description graphique de l'element
+ // = parcours des differentes parties du dessin
+ for (QDomNode n = node.firstChild() ; !n.isNull() ; n = n.nextSibling()) {
+ QDomElement qde = n.toElement();
+ if (qde.isNull()) continue;
+ if (parseElement(qde, qp)) {
+ ++ parsed_elements_count;
+ QString current_tag = qde.tagName();
+ if (current_tag != "terminal" && current_tag != "input") {
+ forbid_antialiasing = true;
+ parseElement(qde, low_zoom_qp);
+ forbid_antialiasing = false;
+ }
+ } else {
+ if (state) *state = 7;
+ return(false);
+ }
+ }
+ }
+ }
+
+ // fin du dessin
+ qp.end();
+ low_zoom_qp.end();
+
+ // il doit y avoir au moins un element charge
+ if (!parsed_elements_count) {
+ if (state) *state = 8;
+ return(false);
+ } else {
+ if (state) *state = 0;
+ return(true);
+ }
+}
+
+/**
+ Destructeur
+*/
+CustomElement::~CustomElement() {
+}
+
+/// @return la liste des bornes de cet element
+QList<Terminal *> CustomElement::terminals() const {
+ return(list_terminals);
+}
+
+/// @return la liste des conducteurs rattaches a cet element
+QList<Conductor *> CustomElement::conductors() const {
+ QList<Conductor *> conductors;
+ foreach(Terminal *t, list_terminals) conductors << t -> conductors();
+ return(conductors);
+}
+
+/// @return la liste des textes de cet element
+QList<ElementTextItem *> CustomElement::texts() const {
+ return(list_texts_);
+}
+
+/**
+ @return Le nombre de bornes que l'element possede
+*/
+int CustomElement::terminalsCount() const {
+ return(list_terminals.size());
+}
+
+/**
+ Dessine le composant sur le Diagram
+ @param qp Le QPainter a utiliser pour dessiner l'element
+ @param options Les options graphiques
+*/
+void CustomElement::paint(QPainter *qp, const QStyleOptionGraphicsItem *options) {
+ if (options && options -> levelOfDetail < 1.0) {
+ low_zoom_drawing.play(qp);
+ } else {
+ drawing.play(qp);
+ }
+}
+
+/**
+ Analyse et prend en compte un element XML decrivant une partie du dessin
+ de l'element perso. Si l'analyse reussit, la partie est ajoutee au dessin.
+ Cette partie peut etre une borne, une ligne, une ellipse, un cercle, un arc
+ de cercle ou un polygone. Cette methode renvoie false si l'analyse
+ d'une de ces formes echoue. Si l'analyse reussit ou dans le cas d'une forme
+ inconnue, cette methode renvoie true. A l'exception des bornes, toutes les
+ formes peuvent avoir un attribut style. @see setPainterStyle
+ @param e L'element XML a analyser
+ @param qp Le QPainter a utiliser pour dessiner l'element perso
+ @return true si l'analyse reussit, false sinon
+*/
+bool CustomElement::parseElement(QDomElement &e, QPainter &qp) {
+ if (e.tagName() == "terminal") return(parseTerminal(e));
+ else if (e.tagName() == "line") return(parseLine(e, qp));
+ else if (e.tagName() == "rect") return(parseRect(e, qp));
+ else if (e.tagName() == "ellipse") return(parseEllipse(e, qp));
+ else if (e.tagName() == "circle") return(parseCircle(e, qp));
+ else if (e.tagName() == "arc") return(parseArc(e, qp));
+ else if (e.tagName() == "polygon") return(parsePolygon(e, qp));
+ else if (e.tagName() == "text") return(parseText(e, qp));
+ else if (e.tagName() == "input") return(parseInput(e));
+ else return(true); // on n'est pas chiant, on ignore l'element inconnu
+}
+
+/**
+ Analyse un element XML suppose representer une ligne. Si l'analyse
+ reussit, la ligne est ajoutee au dessin.
+ La ligne est definie par les attributs suivants :
+ - x1, y1 : reels, coordonnees d'une extremite de la ligne
+ - x2, y2 : reels, coordonnees de l'autre extremite de la ligne
+
+ @param e L'element XML a analyser
+ @param qp Le QPainter a utiliser pour dessiner l'element perso
+ @return true si l'analyse reussit, false sinon
+*/
+bool CustomElement::parseLine(QDomElement &e, QPainter &qp) {
+ // verifie la presence et la validite des attributs obligatoires
+ qreal x1, y1, x2, y2;
+ if (!QET::attributeIsAReal(e, QString("x1"), &x1)) return(false);
+ if (!QET::attributeIsAReal(e, QString("y1"), &y1)) return(false);
+ if (!QET::attributeIsAReal(e, QString("x2"), &x2)) return(false);
+ if (!QET::attributeIsAReal(e, QString("y2"), &y2)) return(false);
+
+ QET::EndType first_end = QET::endTypeFromString(e.attribute("end1"));
+ QET::EndType second_end = QET::endTypeFromString(e.attribute("end2"));
+ qreal length1, length2;
+ if (!QET::attributeIsAReal(e, QString("length1"), &length1)) length1 = 1.5;
+ if (!QET::attributeIsAReal(e, QString("length2"), &length2)) length2 = 1.5;
+
+ qp.save();
+ setPainterStyle(e, qp);
+ QPen t = qp.pen();
+ t.setJoinStyle(Qt::MiterJoin);
+ qp.setPen(t);
+
+ QLineF line(x1, y1, x2, y2);
+ QPointF point1(line.p1());
+ QPointF point2(line.p2());
+
+ qreal line_length(line.length());
+ qreal pen_width = qp.pen().widthF();
+
+ // determine s'il faut dessiner les extremites
+ bool draw_1st_end, draw_2nd_end;
+ qreal reduced_line_length = line_length - (length1 * PartLine::requiredLengthForEndType(first_end));
+ draw_1st_end = first_end && reduced_line_length >= 0;
+ if (draw_1st_end) {
+ reduced_line_length -= (length2 * PartLine::requiredLengthForEndType(second_end));
+ } else {
+ reduced_line_length = line_length - (length2 * PartLine::requiredLengthForEndType(second_end));
+ }
+ draw_2nd_end = second_end && reduced_line_length >= 0;
+
+ // dessine la premiere extremite
+ QPointF start_point, stop_point;
+ if (draw_1st_end) {
+ QList<QPointF> four_points1(PartLine::fourEndPoints(point1, point2, length1));
+ if (first_end == QET::Circle) {
+ qp.drawEllipse(QRectF(four_points1[0] - QPointF(length1, length1), QSizeF(length1 * 2.0, length1 * 2.0)));
+ start_point = four_points1[1];
+ } else if (first_end == QET::Diamond) {
+ qp.drawPolygon(QPolygonF() << four_points1[1] << four_points1[2] << point1 << four_points1[3]);
+ start_point = four_points1[1];
+ } else if (first_end == QET::Simple) {
+ qp.drawPolyline(QPolygonF() << four_points1[3] << point1 << four_points1[2]);
+ start_point = point1;
+
+ } else if (first_end == QET::Triangle) {
+ qp.drawPolygon(QPolygonF() << four_points1[0] << four_points1[2] << point1 << four_points1[3]);
+ start_point = four_points1[0];
+ }
+
+ // ajuste le depart selon l'epaisseur du trait
+ if (pen_width && (first_end == QET::Simple || first_end == QET::Circle)) {
+ start_point = QLineF(start_point, point2).pointAt(pen_width / 2.0 / line_length);
+ }
+ } else {
+ start_point = point1;
+ }
+
+ // dessine la seconde extremite
+ if (draw_2nd_end) {
+ QList<QPointF> four_points2(PartLine::fourEndPoints(point2, point1, length2));
+ if (second_end == QET::Circle) {
+ qp.drawEllipse(QRectF(four_points2[0] - QPointF(length2, length2), QSizeF(length2 * 2.0, length2 * 2.0)));
+ stop_point = four_points2[1];
+ } else if (second_end == QET::Diamond) {
+ qp.drawPolygon(QPolygonF() << four_points2[2] << point2 << four_points2[3] << four_points2[1]);
+ stop_point = four_points2[1];
+ } else if (second_end == QET::Simple) {
+ qp.drawPolyline(QPolygonF() << four_points2[3] << point2 << four_points2[2]);
+ stop_point = point2;
+ } else if (second_end == QET::Triangle) {
+ qp.drawPolygon(QPolygonF() << four_points2[0] << four_points2[2] << point2 << four_points2[3] << four_points2[0]);
+ stop_point = four_points2[0];
+ }
+
+ // ajuste l'arrivee selon l'epaisseur du trait
+ if (pen_width && (second_end == QET::Simple || second_end == QET::Circle)) {
+ stop_point = QLineF(point1, stop_point).pointAt((line_length - (pen_width / 2.0)) / line_length);
+ }
+ } else {
+ stop_point = point2;
+ }
+
+ qp.drawLine(start_point, stop_point);
+
+ qp.restore();
+ return(true);
+}
+
+/**
+ Analyse un element XML suppose representer un rectangle. Si l'analyse
+ reussit, le rectangle est ajoute au dessin.
+ Le rectangle est defini par les attributs suivants :
+ - x : abscisse du coin superieur gauche du rectangle
+ - y : ordonnee du coin superieur gauche du rectangle
+ - width : largeur du rectangle
+ - height : hauteur du rectangle
+
+ @param e L'element XML a analyser
+ @param qp Le QPainter a utiliser pour dessiner l'element perso
+ @return true si l'analyse reussit, false sinon
+*/
+bool CustomElement::parseRect(QDomElement &e, QPainter &qp) {
+ // verifie la presence des attributs obligatoires
+ qreal rect_x, rect_y, rect_w, rect_h;
+ if (!QET::attributeIsAReal(e, QString("x"), &rect_x)) return(false);
+ if (!QET::attributeIsAReal(e, QString("y"), &rect_y)) return(false);
+ if (!QET::attributeIsAReal(e, QString("width"), &rect_w)) return(false);
+ if (!QET::attributeIsAReal(e, QString("height"), &rect_h)) return(false);
+ qp.save();
+ setPainterStyle(e, qp);
+
+ // force le type de jointures pour les rectangles
+ QPen p = qp.pen();
+ p.setJoinStyle(Qt::MiterJoin);
+ qp.setPen(p);
+
+ qp.drawRect(QRectF(rect_x, rect_y, rect_w, rect_h));
+ qp.restore();
+ return(true);
+}
+
+/**
+ Analyse un element XML suppose representer un cercle. Si l'analyse
+ reussit, le cercle est ajoute au dessin.
+ Le cercle est defini par les attributs suivants :
+ - x : abscisse du coin superieur gauche de la quadrature du cercle
+ - y : ordonnee du coin superieur gauche de la quadrature du cercle
+ - diameter : diametre du cercle
+
+ @param e L'element XML a analyser
+ @param qp Le QPainter a utiliser pour dessiner l'element perso
+ @return true si l'analyse reussit, false sinon
+*/
+bool CustomElement::parseCircle(QDomElement &e, QPainter &qp) {
+ // verifie la presence des attributs obligatoires
+ qreal cercle_x, cercle_y, cercle_r;
+ if (!QET::attributeIsAReal(e, QString("x"), &cercle_x)) return(false);
+ if (!QET::attributeIsAReal(e, QString("y"), &cercle_y)) return(false);
+ if (!QET::attributeIsAReal(e, QString("diameter"), &cercle_r)) return(false);
+ qp.save();
+ setPainterStyle(e, qp);
+ qp.drawEllipse(QRectF(cercle_x, cercle_y, cercle_r, cercle_r));
+ qp.restore();
+ return(true);
+}
+
+/**
+ Analyse un element XML suppose representer une ellipse. Si l'analyse
+ reussit, l'ellipse est ajoutee au dessin.
+ L'ellipse est definie par les attributs suivants :
+ - x : abscisse du coin superieur gauche du rectangle dans lequel s'inscrit l'ellipse
+ - y : ordonnee du coin superieur gauche du rectangle dans lequel s'inscrit l'ellipse
+ - width : dimension de la diagonale horizontale de l'ellipse
+ - height : dimension de la diagonale verticale de l'ellipse
+
+ @param e L'element XML a analyser
+ @param qp Le QPainter a utiliser pour dessiner l'element perso
+ @return true si l'analyse reussit, false sinon
+*/
+bool CustomElement::parseEllipse(QDomElement &e, QPainter &qp) {
+ // verifie la presence des attributs obligatoires
+ qreal ellipse_x, ellipse_y, ellipse_l, ellipse_h;
+ if (!QET::attributeIsAReal(e, QString("x"), &ellipse_x)) return(false);
+ if (!QET::attributeIsAReal(e, QString("y"), &ellipse_y)) return(false);
+ if (!QET::attributeIsAReal(e, QString("width"), &ellipse_l)) return(false);
+ if (!QET::attributeIsAReal(e, QString("height"), &ellipse_h)) return(false);
+ qp.save();
+ setPainterStyle(e, qp);
+ qp.drawEllipse(QRectF(ellipse_x, ellipse_y, ellipse_l, ellipse_h));
+ qp.restore();
+ return(true);
+}
+
+/**
+ Analyse un element XML suppose representer un arc de cercle. Si l'analyse
+ reussit, l'arc de cercle est ajoute au dessin.
+ L'arc de cercle est defini par les quatres parametres d'une ellipse (en fait
+ l'ellipse dans laquelle s'inscrit l'arc de cercle) auxquels s'ajoutent les
+ attributs suivants :
+ - start : angle de depart : l'angle "0 degre" est a trois heures
+ - angle : etendue (en degres) de l'arc de cercle ; une valeur positive
+ va dans le sens contraire des aiguilles d'une montre
+
+ @param e L'element XML a analyser
+ @param qp Le QPainter a utiliser pour dessiner l'element perso
+ @return true si l'analyse reussit, false sinon
+*/
+bool CustomElement::parseArc(QDomElement &e, QPainter &qp) {
+ // verifie la presence des attributs obligatoires
+ qreal arc_x, arc_y, arc_l, arc_h, arc_s, arc_a;
+ if (!QET::attributeIsAReal(e, QString("x"), &arc_x)) return(false);
+ if (!QET::attributeIsAReal(e, QString("y"), &arc_y)) return(false);
+ if (!QET::attributeIsAReal(e, QString("width"), &arc_l)) return(false);
+ if (!QET::attributeIsAReal(e, QString("height"), &arc_h)) return(false);
+ if (!QET::attributeIsAReal(e, QString("start"), &arc_s)) return(false);
+ if (!QET::attributeIsAReal(e, QString("angle"), &arc_a)) return(false);
+
+ qp.save();
+ setPainterStyle(e, qp);
+ qp.drawArc(QRectF(arc_x, arc_y, arc_l, arc_h), (int)(arc_s * 16), (int)(arc_a * 16));
+ qp.restore();
+ return(true);
+}
+
+/**
+ Analyse un element XML suppose representer un polygone. Si l'analyse
+ reussit, le polygone est ajoute au dessin.
+ Le polygone est defini par une serie d'attributs x1, x2, ..., xn et autant
+ d'attributs y1, y2, ..., yn representant les coordonnees des differents
+ points du polygone.
+ Il est possible d'obtenir un polygone non ferme en utilisant closed="false"
+ @param e L'element XML a analyser
+ @param qp Le QPainter a utiliser pour dessiner l'element perso
+ @return true si l'analyse reussit, false sinon
+*/
+bool CustomElement::parsePolygon(QDomElement &e, QPainter &qp) {
+ int i = 1;
+ while(true) {
+ if (QET::attributeIsAReal(e, QString("x%1").arg(i)) && QET::attributeIsAReal(e, QString("y%1").arg(i))) ++ i;
+ else break;
+ }
+ if (i < 3) return(false);
+ QVector<QPointF> points(i-1);
+ for (int j = 1 ; j < i ; ++ j) {
+ points.insert(
+ j - 1,
+ QPointF(
+ e.attribute(QString("x%1").arg(j)).toDouble(),
+ e.attribute(QString("y%1").arg(j)).toDouble()
+ )
+ );
+ }
+ qp.save();
+ setPainterStyle(e, qp);
+ if (e.attribute("closed") == "false") qp.drawPolyline(points.data(), i-1);
+ else qp.drawPolygon(points.data(), i-1);
+ qp.restore();
+ return(true);
+}
+
+/**
+ Analyse un element XML suppose representer un texte. Si l'analyse
+ reussit, le texte est ajoute au dessin.
+ Le texte est defini par une position, une chaine de caracteres et une
+ taille.
+ @param e L'element XML a analyser
+ @param qp Le QPainter a utiliser pour dessiner l'element perso
+ @return true si l'analyse reussit, false sinon
+*/
+bool CustomElement::parseText(QDomElement &e, QPainter &qp) {
+ qreal pos_x, pos_y;
+ int size;
+ if (
+ !QET::attributeIsAReal(e, "x", &pos_x) ||\
+ !QET::attributeIsAReal(e, "y", &pos_y) ||\
+ !QET::attributeIsAnInteger(e, "size", &size) ||\
+ !e.hasAttribute("text")
+ ) return(false);
+
+ qp.save();
+ setPainterStyle(e, qp);
+
+ // determine la police a utiliser et en recupere les metriques associees
+ QFont used_font = QETApp::diagramTextsFont(size);
+ QFontMetrics qfm(used_font);
+ QColor text_color = (e.attribute("color") != "white"? Qt::black : Qt::white);
+
+ // instancie un QTextDocument (comme la classe QGraphicsTextItem) pour
+ // generer le rendu graphique du texte
+ QTextDocument text_document;
+ text_document.setDefaultFont(used_font);
+ text_document.setPlainText(e.attribute("text"));
+
+ // Se positionne aux coordonnees indiquees dans la description du texte
+ qp.setTransform(QTransform(), false);
+ qp.translate(pos_x, pos_y);
+
+ // Pivote le systeme de coordonnees du QPainter pour effectuer le rendu
+ // dans le bon sens
+ qreal default_rotation_angle = 0.0;
+ if (QET::attributeIsAReal(e, "rotation", &default_rotation_angle)) {
+ qp.rotate(default_rotation_angle);
+ }
+
+ /*
+ Deplace le systeme de coordonnees du QPainter pour effectuer le rendu au
+ bon endroit ; note : on soustrait l'ascent() de la police pour
+ determiner le coin superieur gauche du texte alors que la position
+ indiquee correspond a la baseline.
+ */
+ QPointF qpainter_offset(0.0, -qfm.ascent());
+
+ // ajuste le decalage selon la marge du document texte
+#if QT_VERSION >= 0x040500
+ text_document.setDocumentMargin(0.0);
+#else
+ // il semblerait qu'avant Qt 4.5, le documentMargin vaille 2.0 (et pas 4.0)
+ qpainter_offset.rx() -= 2.0;
+ qpainter_offset.ry() -= 2.0;
+#endif
+
+ qp.translate(qpainter_offset);
+
+ // force the palette used to render the QTextDocument
+ QAbstractTextDocumentLayout::PaintContext ctx;
+ ctx.palette.setColor(QPalette::Text, text_color);
+ text_document.documentLayout() -> draw(&qp, ctx);
+
+ qp.restore();
+ return(true);
+}
+
+/**
+ Analyse un element XML suppose representer un champ de texte editable par
+ l'utilisateur. Si l'analyse reussit, le champ est ajoute au dessin.
+ Le texte est defini par :
+ - une position
+ - une chaine de caracteres facultative utilisee comme valeur par defaut
+ - une taille
+ - le fait de subir les rotations de l'element ou non
+ @param e L'element XML a analyser
+ @return Un pointeur vers l'objet ElementTextItem ainsi cree si l'analyse reussit, 0 sinon
+*/
+ElementTextItem *CustomElement::parseInput(QDomElement &e) {
+ qreal pos_x, pos_y;
+ int size;
+ if (
+ !QET::attributeIsAReal(e, "x", &pos_x) ||\
+ !QET::attributeIsAReal(e, "y", &pos_y) ||\
+ !QET::attributeIsAnInteger(e, "size", &size)
+ ) return(0);
+
+ ElementTextItem *eti = new ElementTextItem(e.attribute("text"), this);
+ eti -> setFont(QETApp::diagramTextsFont(size));
+
+ // position du champ de texte
+ eti -> setOriginalPos(QPointF(pos_x, pos_y));
+ eti -> setPos(pos_x, pos_y);
+
+ // rotation du champ de texte
+ qreal original_rotation_angle = 0.0;
+ QET::attributeIsAReal(e, "rotation", &original_rotation_angle);
+ eti -> setOriginalRotationAngle(original_rotation_angle);
+ eti -> setRotationAngle(original_rotation_angle);
+
+ // comportement du champ lorsque son element parent est pivote
+ eti -> setFollowParentRotations(e.attribute("rotate") == "true");
+
+ list_texts_ << eti;
+
+ return(eti);
+}
+
+/**
+ Analyse un element XML suppose representer une borne. Si l'analyse
+ reussit, la borne est ajoutee a l'element.
+ Une borne est definie par les attributs suivants :
+ - x, y : coordonnees de la borne
+ - orientation : orientation de la borne = Nord (n), Sud (s), Est (e) ou Ouest (w)
+
+ @param e L'element XML a analyser
+ @return Un pointeur vers l'objet Terminal ainsi cree, 0 sinon
+*/
+Terminal *CustomElement::parseTerminal(QDomElement &e) {
+ // verifie la presence et la validite des attributs obligatoires
+ qreal terminalx, terminaly;
+ QET::Orientation terminalo;
+ if (!QET::attributeIsAReal(e, QString("x"), &terminalx)) return(0);
+ if (!QET::attributeIsAReal(e, QString("y"), &terminaly)) return(0);
+ if (!e.hasAttribute("orientation")) return(0);
+ if (e.attribute("orientation") == "n") terminalo = QET::North;
+ else if (e.attribute("orientation") == "s") terminalo = QET::South;
+ else if (e.attribute("orientation") == "e") terminalo = QET::East;
+ else if (e.attribute("orientation") == "w") terminalo = QET::West;
+ else return(0);
+ Terminal *new_terminal = new Terminal(terminalx, terminaly, terminalo, this, qobject_cast<Diagram *>(scene()));
+ new_terminal -> setZValue(420); // valeur arbitraire pour maintenir les bornes au-dessus des champs de texte
+ list_terminals << new_terminal;
+ return(new_terminal);
+}
+
+/**
+ Active / desactive l'antialiasing sur un QPainter
+ @param qp Le QPainter a modifier
+ @param aa Booleen a true pour activer l'antialiasing, a false pour le desactiver
+*/
+void CustomElement::setQPainterAntiAliasing(QPainter &qp, bool aa) {
+ if (forbid_antialiasing) aa = false;
+ qp.setRenderHint(QPainter::Antialiasing, aa);
+ qp.setRenderHint(QPainter::TextAntialiasing, aa);
+ qp.setRenderHint(QPainter::SmoothPixmapTransform, aa);
+}
+
+/**
+ Verifie si l'attribut "orientation" de l'element XML e correspond bien a la
+ syntaxe decrivant les orientations possibles pour un element.
+ Cette syntaxe comprend exactement 4 lettres :
+ - une pour le Nord
+ - une pour l'Est
+ - une pour le Sud
+ - une pour l'Ouest
+
+ Pour chaque orientation, on indique si elle est :
+ - l'orientation par defaut : d
+ - une orientation autorisee : y
+ - une orientation interdire : n
+
+ Exemple : "dnny" represente un element par defaut oriente vers le nord et qui
+ peut etre oriente vers l'ouest mais pas vers le sud ou vers l'est.
+ @param e Element XML
+ @return true si l'attribut "orientation" est valide, false sinon
+*/
+bool CustomElement::validOrientationAttribute(const QDomElement &e) {
+ return(ori.fromString(e.attribute("orientation")));
+}
+
+/**
+ Applique les parametres de style definis dans l'attribut "style" de
+ l'element XML e au QPainter qp
+ Les styles possibles sont :
+ - line-style : style du trait
+ - dashed : trait en pointilles (tirets)
+ - dashdotted : Traits et points
+ - dotted : trait en pointilles (points)
+ - normal : trait plein [par defaut]
+ - line-weight : epaiseur du trait
+ - thin : trait fin
+ - normal : trait d'epaisseur 1 [par defaut]
+ - filling : remplissage de la forme
+ - white : remplissage blanc
+ - black : remplissage noir
+ - red : remplissage rouge
+ - blue : remplissage bleu
+ - green : remplissage vert
+ - none : pas de remplissage [par defaut]
+ - color : couleur du trait et du texte
+ - white : trait noir [par defaut]
+ - black : trait blanc
+ - red : trait rouge
+ - blue : trait bleu
+ - green : trait vert
+
+ Les autres valeurs ne sont pas prises en compte.
+ @param e L'element XML a parser
+ @param qp Le QPainter a modifier en fonction des styles
+*/
+void CustomElement::setPainterStyle(QDomElement &e, QPainter &qp) {
+ // recupere le QPen et la QBrush du QPainter
+ QPen pen = qp.pen();
+ QBrush brush = qp.brush();
+
+ // attributs par defaut
+ pen.setJoinStyle(Qt::BevelJoin);
+ pen.setCapStyle(Qt::SquareCap);
+
+ // recupere la liste des couples style / valeur
+ QStringList styles = e.attribute("style").split(";", QString::SkipEmptyParts);
+
+ // agit sur le QPen et la QBrush en fonction des valeurs rencontrees
+ QRegExp rx("^\\s*([a-z-]+)\\s*:\\s*([a-z-]+)\\s*$");
+ foreach (QString style, styles) {
+ if (rx.exactMatch(style)) {
+ QString style_name = rx.cap(1);
+ QString style_value = rx.cap(2);
+ if (style_name == "line-style") {
+ if (style_value == "dashed") pen.setStyle(Qt::DashLine);
+ else if (style_value == "dotted") pen.setStyle(Qt::DotLine);
+ else if (style_value == "dashdotted") pen.setStyle(Qt::DashDotLine);
+ else if (style_value == "normal") pen.setStyle(Qt::SolidLine);
+ } else if (style_name == "line-weight") {
+ if (style_value == "thin") pen.setWidth(0);
+ else if (style_value == "normal") pen.setWidthF(1.0);
+ else if (style_value == "none") pen.setColor(QColor(0, 0, 0, 0));
+ } else if (style_name == "filling") {
+ if (style_value == "white") {
+ brush.setStyle(Qt::SolidPattern);
+ brush.setColor(Qt::white);
+ } else if (style_value == "black") {
+ brush.setStyle(Qt::SolidPattern);
+ brush.setColor(Qt::black);
+ } else if (style_value == "blue") {
+ brush.setStyle(Qt::SolidPattern);
+ brush.setColor(Qt::blue);
+ } else if (style_value == "red") {
+ brush.setStyle(Qt::SolidPattern);
+ brush.setColor(Qt::red);
+ } else if (style_value == "green") {
+ brush.setStyle(Qt::SolidPattern);
+ brush.setColor(Qt::green);
+ } else if (style_value == "none") {
+ brush.setStyle(Qt::NoBrush);
+ }
+ } else if (style_name == "color") {
+ if (style_value == "black") {
+ pen.setColor(QColor(0, 0, 0, pen.color().alpha()));
+ } else if (style_value == "white") {
+ pen.setColor(QColor(255, 255, 255, pen.color().alpha()));
+ } else if (style_value == "red") {
+ pen.setColor(Qt::red);
+ }else if (style_value == "blue") {
+ pen.setColor(Qt::blue);
+ }else if (style_value == "green") {
+ pen.setColor(Qt::green);
+ }
+ }
+ }
+ }
+
+ // affectation du QPen et de la QBrush modifies au QPainter
+ qp.setPen(pen);
+ qp.setBrush(brush);
+
+ // mise en place (ou non) de l'antialiasing
+ setQPainterAntiAliasing(qp, e.attribute("antialias") == "true");
+}
Added: branches/devel/sources/qetgraphicsitem/customelement.h
===================================================================
--- branches/devel/sources/qetgraphicsitem/customelement.h (rev 0)
+++ branches/devel/sources/qetgraphicsitem/customelement.h 2013-11-07 09:18:03 UTC (rev 2596)
@@ -0,0 +1,132 @@
+/*
+ Copyright 2006-2013 The QElectroTech Team
+ 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/>.
+*/
+#ifndef CUSTOM_ELEMENT_H
+#define CUSTOM_ELEMENT_H
+#include "fixedelement.h"
+#include <QtGui>
+#include "nameslist.h"
+#include "elementslocation.h"
+class ElementTextItem;
+class Terminal;
+/**
+ This class represents an electrical element; it may be used like a fixed
+ element, the difference being that the CustomElement reads its description
+ (names, drawing, behavior) from an XML document.
+*/
+class CustomElement : public FixedElement {
+
+ Q_OBJECT
+
+ // constructors, destructor
+ public:
+ CustomElement(const ElementsLocation &, QGraphicsItem * = 0, Diagram * = 0, int * = 0);
+ CustomElement(const QDomElement &, QGraphicsItem * = 0, Diagram * = 0, int * = 0);
+ virtual ~CustomElement();
+
+ private:
+ CustomElement(const CustomElement &);
+
+ // attributes
+ protected:
+ int elmt_state; // hold the error code in case the instanciation fails, or 0 if everything went well
+ NamesList names;
+ ElementsLocation location_;
+ QPicture drawing;
+ QPicture low_zoom_drawing;
+ QList<Terminal *> list_terminals;
+ QList<ElementTextItem *> list_texts_;
+ bool forbid_antialiasing;
+
+ // methods
+ public:
+ virtual QList<Terminal *> terminals() const;
+ virtual QList<Conductor *> conductors() const;
+ virtual QList<ElementTextItem *> texts() const;
+ virtual int terminalsCount() const;
+ virtual void paint(QPainter *, const QStyleOptionGraphicsItem *);
+ QString typeId() const;
+ ElementsLocation location() const;
+ bool isNull() const;
+ int state() const;
+ QString name() const;
+
+ protected:
+ virtual bool buildFromXml(const QDomElement &, int * = 0);
+ virtual bool parseElement(QDomElement &, QPainter &);
+ virtual bool parseLine(QDomElement &, QPainter &);
+ virtual bool parseRect(QDomElement &, QPainter &);
+ virtual bool parseEllipse(QDomElement &, QPainter &);
+ virtual bool parseCircle(QDomElement &, QPainter &);
+ virtual bool parseArc(QDomElement &, QPainter &);
+ virtual bool parsePolygon(QDomElement &, QPainter &);
+ virtual bool parseText(QDomElement &, QPainter &);
+ virtual ElementTextItem *parseInput(QDomElement &);
+ virtual Terminal *parseTerminal(QDomElement &);
+ virtual void setQPainterAntiAliasing(QPainter &, bool);
+ virtual bool validOrientationAttribute(const QDomElement &);
+ virtual void setPainterStyle(QDomElement &, QPainter &);
+};
+
+/**
+ @return The element type ID; considering a CustomElement, this means the
+ @location of its XML description.
+ @see location()
+*/
+inline QString CustomElement::typeId() const {
+ return(location_.path());
+}
+
+/**
+ @return the location of the XML document describing this element.
+*/
+inline ElementsLocation CustomElement::location() const {
+ return(location_);
+}
+
+/**
+ @return true if this element is null, i.e. if its XML description could not
+ be loaded.
+*/
+inline bool CustomElement::isNull() const {
+ return(elmt_state);
+}
+
+/**
+ @return An integer representing the state of this element:
+ - 0: instantiation succeeded
+ - 1: the file does not exist
+ - 2: the file could not be opened
+ - 3: The file is not a valid XML document
+ - 4: The XML document does not have a "definition" root element.
+ - 5: The definition attributes are missing or invalid
+ - 6: The definition is empty
+ - 7: The parsing of an XML element describing an element drawing primitive failed
+ - 8: No primitive could be loadedAucune partie du dessin n'a pu etre chargee
+*/
+inline int CustomElement::state() const {
+ return(elmt_state);
+}
+
+/**
+ @return The name of this element.
+*/
+inline QString CustomElement::name() const {
+ return(names.name(location_.baseName()));
+}
+
+#endif
Modified: branches/devel/sources/qetgraphicsitem/diagramimageitem.cpp
===================================================================
--- branches/devel/sources/qetgraphicsitem/diagramimageitem.cpp 2013-11-06 18:44:39 UTC (rev 2595)
+++ branches/devel/sources/qetgraphicsitem/diagramimageitem.cpp 2013-11-07 09:18:03 UTC (rev 2596)
@@ -57,28 +57,6 @@
}
/**
- Permet de tourner le image a un angle donne de maniere absolue.
- Un angle de 0 degres correspond a un image horizontal non retourne.
- @param rotation Nouvel angle de rotation de ce image
- @see applyRotation
-*/
-void DiagramImageItem::setRotationAngle(const qreal &rotation_angle) {
- qreal applied_rotation = QET::correctAngle(rotation_angle);
- applyRotation(applied_rotation - rotation());
-}
-
-/**
- Permet de tourner le image de maniere relative.
- L'angle added_rotation est ajoute a l'orientation actuelle du image.
- @param added_rotation Angle a ajouter a la rotation actuelle
- @see applyRotation
-*/
-void DiagramImageItem::rotateBy(const qreal &added_rotation) {
- qreal applied_added_rotation = QET::correctAngle(added_rotation);
- applyRotation(applied_added_rotation);
-}
-
-/**
* @brief DiagramImageItem::paint
* Draw the pixmap.
* @param painter the Qpainter to use for draw the pixmap
@@ -104,16 +82,6 @@
}
/**
- Effectue la rotation du image en elle-meme
- Pour les DiagramImageItem, la rotation s'effectue autour du point (0, 0).
- Cette methode peut toutefois etre redefinie dans des classes filles
- @param angle Angle de la rotation a effectuer
-*/
-void DiagramImageItem::applyRotation(const qreal &angle) {
- setRotation(QET::correctAngle(rotation()+angle));
-}
-
-/**
* @brief DiagramImageItem::setScale
* @param scale the value of @scale must be betwen 1 and 200
*/
Modified: branches/devel/sources/qetgraphicsitem/diagramimageitem.h
===================================================================
--- branches/devel/sources/qetgraphicsitem/diagramimageitem.h 2013-11-06 18:44:39 UTC (rev 2595)
+++ branches/devel/sources/qetgraphicsitem/diagramimageitem.h 2013-11-07 09:18:03 UTC (rev 2596)
@@ -49,15 +49,12 @@
virtual bool fromXml(const QDomElement &);
virtual QDomElement toXml(QDomDocument &) const;
- void setRotationAngle(const qreal &);
- void rotateBy(const qreal &);
virtual void editProperty();
void setPixmap(const QPixmap &pixmap);
virtual QRectF boundingRect() const;
protected:
virtual void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *);
- void applyRotation(const qreal &);
signals:
Added: branches/devel/sources/qetgraphicsitem/diagramtextitem.cpp
===================================================================
--- branches/devel/sources/qetgraphicsitem/diagramtextitem.cpp (rev 0)
+++ branches/devel/sources/qetgraphicsitem/diagramtextitem.cpp 2013-11-07 09:18:03 UTC (rev 2596)
@@ -0,0 +1,328 @@
+/*
+ Copyright 2006-2013 QElectroTech Team
+ 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/>.
+*/
+#include "diagramtextitem.h"
+#include "diagramcommands.h"
+#include "qet.h"
+#include "qetapp.h"
+
+#include "richtext/richtexteditor_p.h"
+
+/**
+ Constructeur
+ @param parent Le QGraphicsItem parent du champ de texte
+ @param parent_diagram Le schema auquel appartient le champ de texte
+*/
+DiagramTextItem::DiagramTextItem(QGraphicsItem *parent, Diagram *parent_diagram) :
+ QGraphicsTextItem(parent, parent_diagram),
+ previous_text_(),
+ rotation_angle_(0.0)
+{
+ //set Zvalue at 10 to be upper than the DiagramImageItem
+ setZValue(10);
+ setDefaultTextColor(Qt::black);
+ setFont(QETApp::diagramTextsFont());
+ setFlags(QGraphicsItem::ItemIsSelectable|QGraphicsItem::ItemIsMovable);
+#if QT_VERSION >= 0x040600
+ setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
+#endif
+ connect(this, SIGNAL(lostFocus()), this, SLOT(setNonFocusable()));
+}
+
+/**
+ Constructeur
+ @param text Le texte affiche par le champ de texte
+ @param parent Le QGraphicsItem parent du champ de texte
+ @param parent_diagram Le schema auquel appartient le champ de texte
+*/
+DiagramTextItem::DiagramTextItem(const QString &text, QGraphicsItem *parent, Diagram *parent_diagram) :
+ QGraphicsTextItem(text, parent, parent_diagram),
+ previous_text_(text),
+ rotation_angle_(0.0)
+{
+ //set Zvalue at 10 to be upper than the DiagramImageItem
+ setZValue(10);
+ setDefaultTextColor(Qt::black);
+ setFont(QETApp::diagramTextsFont());
+ setFlags(QGraphicsItem::ItemIsSelectable|QGraphicsItem::ItemIsMovable);
+#if QT_VERSION >= 0x040600
+ setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
+#endif
+ connect(this, SIGNAL(lostFocus()), this, SLOT(setNonFocusable()));
+}
+
+/// Destructeur
+DiagramTextItem::~DiagramTextItem() {
+}
+
+/**
+ @return le Diagram auquel ce texte appartient, ou 0 si ce texte n'est
+ rattache a aucun schema
+*/
+Diagram *DiagramTextItem::diagram() const {
+ return(qobject_cast<Diagram *>(scene()));
+}
+
+/**
+ @return l'angle de rotation actuel de ce texte
+*/
+qreal DiagramTextItem::rotationAngle() const {
+ return(rotation_angle_);
+}
+
+/**
+ Permet de tourner le texte a un angle donne de maniere absolue.
+ Un angle de 0 degres correspond a un texte horizontal non retourne.
+ @param rotation Nouvel angle de rotation de ce texte
+ @see applyRotation
+*/
+void DiagramTextItem::setRotationAngle(const qreal &rotation) {
+ qreal applied_rotation = QET::correctAngle(rotation);
+ applyRotation(applied_rotation - rotation_angle_);
+ rotation_angle_ = applied_rotation;
+}
+
+/**
+ Permet de tourner le texte de maniere relative.
+ L'angle added_rotation est ajoute a l'orientation actuelle du texte.
+ @param added_rotation Angle a ajouter a la rotation actuelle
+ @see applyRotation
+*/
+void DiagramTextItem::rotateBy(const qreal &added_rotation) {
+ qreal applied_added_rotation = QET::correctAngle(added_rotation);
+ rotation_angle_ = QET::correctAngle(rotation_angle_ + applied_added_rotation);
+ applyRotation(applied_added_rotation);
+}
+
+/**
+ Traduit en coordonnees de la scene un mouvement / vecteur initialement
+ exprime en coordonnees locales.
+ @param movement Vecteur exprime en coordonnees locales
+ @return le meme vecteur, exprime en coordonnees de la scene
+*/
+QPointF DiagramTextItem::mapMovementToScene(const QPointF &movement) const {
+ // on definit deux points en coordonnees locales
+ QPointF local_origin(0.0, 0.0);
+ QPointF local_movement_point(movement);
+
+ // on les mappe sur la scene
+ QPointF scene_origin(mapToScene(local_origin));
+ QPointF scene_movement_point(mapToScene(local_movement_point));
+
+ // on calcule le vecteur represente par ces deux points
+ return(scene_movement_point - scene_origin);
+}
+
+/**
+ Traduit en coordonnees locales un mouvement / vecteur initialement
+ exprime en coordonnees de la scene.
+ @param movement Vecteur exprime en coordonnees de la scene
+ @return le meme vecteur, exprime en coordonnees locales
+*/
+QPointF DiagramTextItem::mapMovementFromScene(const QPointF &movement) const {
+ // on definit deux points sur la scene
+ QPointF scene_origin(0.0, 0.0);
+ QPointF scene_movement_point(movement);
+
+ // on les mappe sur ce QGraphicsItem
+ QPointF local_origin(mapFromScene(scene_origin));
+ QPointF local_movement_point(mapFromScene(scene_movement_point));
+
+ // on calcule le vecteur represente par ces deux points
+ return(local_movement_point - local_origin);
+}
+
+/**
+ Traduit en coordonnees de l'item parent un mouvement / vecteur initialement
+ exprime en coordonnees locales.
+ @param movement Vecteur exprime en coordonnees locales
+ @return le meme vecteur, exprime en coordonnees du parent
+*/
+QPointF DiagramTextItem::mapMovementToParent(const QPointF &movement) const {
+ // on definit deux points en coordonnees locales
+ QPointF local_origin(0.0, 0.0);
+ QPointF local_movement_point(movement);
+
+ // on les mappe sur la scene
+ QPointF parent_origin(mapToParent(local_origin));
+ QPointF parent_movement_point(mapToParent(local_movement_point));
+
+ // on calcule le vecteur represente par ces deux points
+ return(parent_movement_point - parent_origin);
+}
+
+/**
+ Traduit en coordonnees locales un mouvement / vecteur initialement
+ exprime en coordonnees du parent.
+ @param movement Vecteur exprime en coordonnees du parent
+ @return le meme vecteur, exprime en coordonnees locales
+*/
+QPointF DiagramTextItem::mapMovementFromParent(const QPointF &movement) const {
+ // on definit deux points sur le parent
+ QPointF parent_origin(0.0, 0.0);
+ QPointF parent_movement_point(movement);
+
+ // on les mappe sur ce QGraphicsItem
+ QPointF local_origin(mapFromParent(parent_origin));
+ QPointF local_movement_point(mapFromParent(parent_movement_point));
+
+ // on calcule le vecteur represente par ces deux points
+ return(local_movement_point - local_origin);
+}
+
+/**
+ Dessine le champ de texte.
+ Cette methode delegue simplement le travail a QGraphicsTextItem::paint apres
+ avoir desactive l'antialiasing.
+ @param painter Le QPainter a utiliser pour dessiner le champ de texte
+ @param option Les options de style pour le champ de texte
+ @param widget Le QWidget sur lequel on dessine
+*/
+void DiagramTextItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) {
+ painter -> setRenderHint(QPainter::Antialiasing, false);
+ QGraphicsTextItem::paint(painter, option, widget);
+}
+
+/**
+ Gere la prise de focus du champ de texte
+ @param e Objet decrivant la prise de focus
+*/
+void DiagramTextItem::focusInEvent(QFocusEvent *e) {
+ QGraphicsTextItem::focusInEvent(e);
+
+ // empeche le deplacement du texte pendant son edition
+ setFlag(QGraphicsItem::ItemIsMovable, false);
+
+ // memorise le texte avant que l'utilisateur n'y touche
+ previous_text_ = toHtml();
+ // cela permettra de determiner si l'utilisateur a modifie le texte a la fin de l'edition
+}
+
+/**
+ Gere la perte de focus du champ de texte
+ @param e Objet decrivant la perte de focus
+*/
+void DiagramTextItem::focusOutEvent(QFocusEvent *e) {
+ QGraphicsTextItem::focusOutEvent(e);
+
+ // signale la modification du texte si besoin
+ if (toPlainText() != previous_text_) {
+ emit(diagramTextChanged(this, previous_text_, toHtml()));
+ previous_text_ = toHtml();
+ }
+
+ // deselectionne le texte
+ QTextCursor cursor = textCursor();
+ cursor.clearSelection();
+ setTextCursor(cursor);
+
+ // hack a la con pour etre re-entrant
+ setTextInteractionFlags(Qt::NoTextInteraction);
+
+ // autorise de nouveau le deplacement du texte
+ setFlag(QGraphicsItem::ItemIsMovable, true);
+ QTimer::singleShot(0, this, SIGNAL(lostFocus()));
+}
+
+/**
+ Gere les double-clics sur ce champ de texte.
+ @param event un QGraphicsSceneMouseEvent decrivant le double-clic
+*/
+void DiagramTextItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) {
+ if (!(textInteractionFlags() & Qt::TextEditable)) {
+ // rend le champ de texte editable
+ setTextInteractionFlags(Qt::TextEditorInteraction);
+
+ // edite le champ de texte
+ setFocus(Qt::MouseFocusReason);
+ } else {
+ QGraphicsTextItem::mouseDoubleClickEvent(event);
+ }
+}
+
+/**
+ Effectue la rotation du texte en elle-meme
+ Pour les DiagramTextItem, la rotation s'effectue autour du point (0, 0).
+ Cette methode peut toutefois etre redefinie dans des classes filles
+ @param angle Angle de la rotation a effectuer
+*/
+void DiagramTextItem::applyRotation(const qreal &angle) {
+ setRotation(QET::correctAngle(rotation()+angle));
+}
+
+/**
+ Change la position du champ de texte en veillant a ce qu'il
+ reste sur la grille du schema auquel il appartient.
+ @param p Nouvelles coordonnees de l'element
+*/
+void DiagramTextItem::setPos(const QPointF &p) {
+ if (p == pos()) return;
+ // pas la peine de positionner sur la grille si l'element n'est pas sur un Diagram
+ if (scene()) {
+ // arrondit l'abscisse a 10 px pres
+ int p_x = qRound(p.x() / (Diagram::xGrid * 1.0)) * Diagram::xGrid;
+ // arrondit l'ordonnee a 10 px pres
+ int p_y = qRound(p.y() / (Diagram::yGrid * 1.0)) * Diagram::yGrid;
+ QGraphicsTextItem::setPos(p_x, p_y);
+ } else QGraphicsTextItem::setPos(p);
+}
+
+/**
+ Change la position du champ de texte en veillant a ce que l'il
+ reste sur la grille du schema auquel il appartient.
+ @param x Nouvelle abscisse de l'element
+ @param y Nouvelle ordonnee de l'element
+*/
+void DiagramTextItem::setPos(qreal x, qreal y) {
+ setPos(QPointF(x, y));
+}
+
+/**
+ @return la position du champ de texte
+*/
+QPointF DiagramTextItem::pos() const {
+ return(QGraphicsTextItem::pos());
+}
+
+/// Rend le champ de texte non focusable
+void DiagramTextItem::setNonFocusable() {
+ setFlag(QGraphicsTextItem::ItemIsFocusable, false);
+}
+
+
+/**
+ * @brief DiagramTextItem::setHtmlText
+ * @param txt
+ */
+void DiagramTextItem::setHtmlText(const QString &txt) {
+ setHtml( txt );
+}
+
+/**
+ * @brief Edit the text with HtmlEditor
+ */
+void DiagramTextItem::edit() {
+ //Open the HtmlEditor
+ qdesigner_internal::RichTextEditorDialog *editor = new qdesigner_internal::RichTextEditorDialog();
+ // connect the in/out
+ connect(editor, SIGNAL(applyEditText(const QString &)), this, SLOT(setHtmlText(const QString &)));
+ // load the Html txt
+ editor->setText( toHtml() );
+ // show
+ editor->show();
+}
+
Added: branches/devel/sources/qetgraphicsitem/diagramtextitem.h
===================================================================
--- branches/devel/sources/qetgraphicsitem/diagramtextitem.h (rev 0)
+++ branches/devel/sources/qetgraphicsitem/diagramtextitem.h 2013-11-07 09:18:03 UTC (rev 2596)
@@ -0,0 +1,85 @@
+/*
+ Copyright 2006-2013 The QElectroTech Team
+ 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/>.
+*/
+#ifndef DIAGRAM_TEXT_ITEM_H
+#define DIAGRAM_TEXT_ITEM_H
+#include <QtGui>
+#include "diagram.h"
+/**
+ This class represents a selectable, movable and editable text field on a
+ diagram.
+ @see QGraphicsItem::GraphicsItemFlags
+*/
+class DiagramTextItem : public QGraphicsTextItem {
+ Q_OBJECT
+ // constructors, destructor
+ public:
+ DiagramTextItem(QGraphicsItem * = 0, Diagram * = 0);
+ DiagramTextItem(const QString &, QGraphicsItem * = 0, Diagram * = 0);
+ virtual ~DiagramTextItem();
+
+ // attributes
+ public:
+ enum { Type = UserType + 1004 };
+
+ // methods
+ public:
+ /**
+ Enable the use of qgraphicsitem_cast to safely cast a QGraphicsItem into a
+ DiagramTextItem
+ @return the QGraphicsItem type
+ */
+ virtual int type() const { return Type; }
+ Diagram *diagram() const;
+ virtual void fromXml(const QDomElement &) = 0;
+ virtual QDomElement toXml(QDomDocument &) const = 0;
+ virtual void setPos(const QPointF &);
+ virtual void setPos(qreal, qreal);
+ virtual QPointF pos() const;
+ qreal rotationAngle() const;
+ void setRotationAngle(const qreal &);
+ void rotateBy(const qreal &);
+ void edit();
+ QPointF mapMovementToScene(const QPointF &) const;
+ QPointF mapMovementFromScene(const QPointF &) const;
+ QPointF mapMovementToParent(const QPointF &) const;
+ QPointF mapMovementFromParent(const QPointF &) const;
+
+ protected:
+ virtual void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *);
+ virtual void focusInEvent(QFocusEvent *);
+ virtual void focusOutEvent(QFocusEvent *);
+ virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *);
+ virtual void applyRotation(const qreal &);
+
+ signals:
+ /// signal emitted when the text field loses focus
+ void lostFocus();
+ /// signal emitted after text was changed
+ void diagramTextChanged(DiagramTextItem *, const QString &, const QString &);
+
+ public slots:
+ void setNonFocusable();
+ void setHtmlText(const QString &);
+
+ private:
+ /// Previous text value
+ QString previous_text_;
+ /// angle of rotation of the text field
+ qreal rotation_angle_;
+};
+#endif
Added: branches/devel/sources/qetgraphicsitem/element.cpp
===================================================================
--- branches/devel/sources/qetgraphicsitem/element.cpp (rev 0)
+++ branches/devel/sources/qetgraphicsitem/element.cpp 2013-11-07 09:18:03 UTC (rev 2596)
@@ -0,0 +1,433 @@
+/*
+ Copyright 2006-2013 The QElectroTech Team
+ 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/>.
+*/
+#include "element.h"
+#include "qetapp.h"
+#include "diagram.h"
+#include "conductor.h"
+#include "elementtextitem.h"
+#include "diagramcommands.h"
+#include <QtDebug>
+
+/**
+ Constructeur pour un element sans scene ni parent
+*/
+Element::Element(QGraphicsItem *parent, Diagram *scene) :
+ QetGraphicsItem(parent),
+ internal_connections_(false),
+ must_highlight_(false)
+{
+ setZValue(10);
+}
+
+/**
+ Destructeur
+*/
+Element::~Element() {
+}
+
+/**
+ @return true si l'element est mis en evidence
+*/
+bool Element::isHighlighted() const {
+ return(must_highlight_);
+}
+
+/**
+ @param hl true pour mettre l'element en evidence, false sinon
+*/
+void Element::setHighlighted(bool hl) {
+ must_highlight_ = hl;
+ update();
+}
+
+/**
+ Methode principale de dessin de l'element
+ @param painter Le QPainter utilise pour dessiner l'elment
+ @param options Les options de style a prendre en compte
+ @param widget Le widget sur lequel on dessine
+*/
+void Element::paint(QPainter *painter, const QStyleOptionGraphicsItem *options, QWidget *widget) {
+
+#ifndef Q_WS_WIN
+ // corrige un bug de rendu ne se produisant que lors du rendu sur QGraphicsScene sous X11 au zoom par defaut
+ static bool must_correct_rendering_bug = QETApp::settings().value("correct-rendering", false).toBool();
+ if (must_correct_rendering_bug) {
+ Diagram *dia = diagram();
+ if (dia && options -> levelOfDetail == 1.0 && widget) {
+ // calcule la rotation qu'a subi l'element
+ qreal applied_rotation = 90.0 * (ori.current() - ori.defaultOrientation());
+ while (applied_rotation < 360.0) applied_rotation += 360.0;
+ while (applied_rotation > 360.0) applied_rotation -= 360.0;
+ if (applied_rotation == 90.0) painter -> translate(1.0, -1.0);
+ else if (applied_rotation == 180.0) painter -> translate(-1.0, -1.0);
+ else if (applied_rotation == 270.0) painter -> translate(-1.0, 1.0);
+ }
+ }
+#endif
+ if (must_highlight_) drawHighlight(painter, options);
+
+ // Dessin de l'element lui-meme
+ paint(painter, options);
+
+ // Dessin du cadre de selection si necessaire
+ if (isSelected()) drawSelection(painter, options);
+}
+
+/**
+ @return Le rectangle delimitant le contour de l'element
+*/
+QRectF Element::boundingRect() const {
+ return(QRectF(QPointF(-hotspot_coord.x(), -hotspot_coord.y()), dimensions));
+}
+
+/**
+ Definit la taille de l'element sur le schema. Les tailles doivent etre
+ des multiples de 10 ; si ce n'est pas le cas, les dimensions indiquees
+ seront arrrondies aux dizaines superieures.
+ @param wid Largeur de l'element
+ @param hei Hauteur de l'element
+ @return La taille finale de l'element
+*/
+QSize Element::setSize(int wid, int hei) {
+ prepareGeometryChange();
+ // chaque dimension indiquee est arrondie a la dizaine superieure
+ while (wid % 10) ++ wid;
+ while (hei % 10) ++ hei;
+ // les dimensions finales sont conservees et retournees
+ return(dimensions = QSize(wid, hei));
+}
+
+/**
+ @return la taille de l'element sur le schema
+*/
+QSize Element::size() const {
+ return(dimensions);
+}
+
+/**
+ Definit le hotspot de l'element par rapport au coin superieur gauche de son rectangle delimitant.
+ Necessite que la taille ait deja ete definie
+ @param hs Coordonnees du hotspot
+*/
+QPoint Element::setHotspot(QPoint hs) {
+ // la taille doit avoir ete definie
+ prepareGeometryChange();
+ if (dimensions.isNull()) hotspot_coord = QPoint(0, 0);
+ else {
+ // les coordonnees indiquees ne doivent pas depasser les dimensions de l'element
+ int hsx = qMin(hs.x(), dimensions.width());
+ int hsy = qMin(hs.y(), dimensions.height());
+ hotspot_coord = QPoint(hsx, hsy);
+ }
+ return(hotspot_coord);
+}
+
+/**
+ @return Le hotspot courant de l'element
+*/
+QPoint Element::hotspot() const {
+ return(hotspot_coord);
+}
+
+/**
+ Selectionne l'element
+*/
+void Element::select() {
+ setSelected(true);
+}
+
+/**
+ Deselectionne l'element
+*/
+void Element::deselect() {
+ setSelected(false);
+}
+
+/**
+ @return La pixmap de l'element
+*/
+QPixmap Element::pixmap() {
+ if (preview.isNull()) updatePixmap(); // on genere la pixmap si ce n'est deja fait
+ return(preview);
+}
+
+/**
+ Permet de specifier l'orientation de l'element
+ @param o la nouvelle orientation de l'objet
+ @return true si l'orientation a pu etre appliquee, false sinon
+*/
+bool Element::setOrientation(QET::Orientation o) {
+ // verifie que l'orientation demandee est acceptee
+ if (!ori.accept(o)) return(false);
+ prepareGeometryChange();
+ // rotation en consequence et rafraichissement de l'element graphique
+ qreal rotation_value = 90.0 * (o - ori.current());
+ applyRotation(rotation_value);
+ ori.setCurrent(o);
+ update();
+ foreach(QGraphicsItem *qgi, childItems()) {
+ if (Terminal *p = qgraphicsitem_cast<Terminal *>(qgi)) {
+ p -> updateConductor();
+ }
+ }
+ return(true);
+}
+
+/*** Methodes protegees ***/
+
+/**
+ Dessine un petit repere (axes x et y) relatif a l'element
+ @param painter Le QPainter a utiliser pour dessiner les axes
+ @param options Les options de style a prendre en compte
+*/
+void Element::drawAxes(QPainter *painter, const QStyleOptionGraphicsItem *options) {
+ Q_UNUSED(options);
+ painter -> setPen(Qt::blue);
+ painter -> drawLine(0, 0, 10, 0);
+ painter -> drawLine(7,-3, 10, 0);
+ painter -> drawLine(7, 3, 10, 0);
+ painter -> setPen(Qt::red);
+ painter -> drawLine(0, 0, 0, 10);
+ painter -> drawLine(0, 10,-3, 7);
+ painter -> drawLine(0, 10, 3, 7);
+}
+
+/*** Methodes privees ***/
+
+/**
+ Dessine le cadre de selection de l'element de maniere systematiquement non antialiasee.
+ @param painter Le QPainter a utiliser pour dessiner les bornes.
+ @param options Les options de style a prendre en compte
+ */
+void Element::drawSelection(QPainter *painter, const QStyleOptionGraphicsItem *options) {
+ Q_UNUSED(options);
+ painter -> save();
+ // Annulation des renderhints
+ painter -> setRenderHint(QPainter::Antialiasing, false);
+ painter -> setRenderHint(QPainter::TextAntialiasing, false);
+ painter -> setRenderHint(QPainter::SmoothPixmapTransform, false);
+ // Dessin du cadre de selection en gris
+ QPen t;
+ t.setColor(Qt::gray);
+ t.setStyle(Qt::DashDotLine);
+ painter -> setPen(t);
+ // Le dessin se fait a partir du rectangle delimitant
+ painter -> drawRoundRect(boundingRect().adjusted(1, 1, -1, -1), 10, 10);
+ painter -> restore();
+}
+
+/**
+ Dessine le cadre de selection de l'element de maniere systematiquement non antialiasee.
+ @param painter Le QPainter a utiliser pour dessiner les bornes.
+ @param options Les options de style a prendre en compte
+ */
+void Element::drawHighlight(QPainter *painter, const QStyleOptionGraphicsItem *options) {
+ Q_UNUSED(options);
+ painter -> save();
+
+ qreal gradient_radius = qMin(boundingRect().width(), boundingRect().height()) / 2.0;
+ QRadialGradient gradient(
+ boundingRect().center(),
+ gradient_radius,
+ boundingRect().center()
+ );
+ gradient.setColorAt(0.0, QColor::fromRgb(69, 137, 255, 255));
+ gradient.setColorAt(1.0, QColor::fromRgb(69, 137, 255, 0));
+ QBrush brush(gradient);
+
+ painter -> setPen(Qt::NoPen);
+ painter -> setBrush(brush);
+ // Le dessin se fait a partir du rectangle delimitant
+ painter -> drawRoundRect(boundingRect().adjusted(1, 1, -1, -1), 10, 10);
+ painter -> restore();
+}
+
+/**
+ Fonction initialisant et dessinant la pixmap de l'element.
+*/
+void Element::updatePixmap() {
+ // Pixmap transparente faisant la taille de base de l'element
+ preview = QPixmap(dimensions);
+ preview.fill(QColor(255, 255, 255, 0));
+ // QPainter sur la pixmap, avec antialiasing
+ QPainter p(&preview);
+ p.setRenderHint(QPainter::Antialiasing, true);
+ p.setRenderHint(QPainter::SmoothPixmapTransform, true);
+ // Translation de l'origine du repere de la pixmap
+ p.translate(hotspot_coord);
+ // L'element se dessine sur la pixmap
+ paint(&p, 0);
+}
+
+/**
+ Permet de savoir si un element XML (QDomElement) represente bien un element
+ @param e Le QDomElement a valide
+ @return true si l'element XML est un Element, false sinon
+*/
+bool Element::valideXml(QDomElement &e) {
+ // verifie le nom du tag
+ if (e.tagName() != "element") return(false);
+
+ // verifie la presence des attributs minimaux
+ if (!e.hasAttribute("type")) return(false);
+ if (!e.hasAttribute("x")) return(false);
+ if (!e.hasAttribute("y")) return(false);
+
+ bool conv_ok;
+ // parse l'abscisse
+ e.attribute("x").toDouble(&conv_ok);
+ if (!conv_ok) return(false);
+
+ // parse l'ordonnee
+ e.attribute("y").toDouble(&conv_ok);
+ if (!conv_ok) return(false);
+ return(true);
+}
+
+/**
+ Methode d'import XML. Cette methode est appelee lors de l'import de contenu
+ XML (coller, import, ouverture de fichier...) afin que l'element puisse
+ gerer lui-meme l'importation de ses bornes. Ici, comme cette classe est
+ caracterisee par un nombre fixe de bornes, l'implementation exige de
+ retrouver exactement ses bornes dans le fichier XML.
+ @param e L'element XML a analyser.
+ @param table_id_adr Reference vers la table de correspondance entre les IDs
+ du fichier XML et les adresses en memoire. Si l'import reussit, il faut y
+ ajouter les bons couples (id, adresse).
+ @return true si l'import a reussi, false sinon
+
+*/
+bool Element::fromXml(QDomElement &e, QHash<int, Terminal *> &table_id_adr, bool handle_inputs_rotation) {
+ /*
+ les bornes vont maintenant etre recensees pour associer leurs id a leur adresse reelle
+ ce recensement servira lors de la mise en place des fils
+ */
+ QList<QDomElement> liste_terminals;
+ foreach(QDomElement qde, QET::findInDomElement(e, "terminals", "terminal")) {
+ if (Terminal::valideXml(qde)) liste_terminals << qde;
+ }
+
+ QHash<int, Terminal *> priv_id_adr;
+ int terminals_non_trouvees = 0;
+ foreach(QGraphicsItem *qgi, childItems()) {
+ if (Terminal *p = qgraphicsitem_cast<Terminal *>(qgi)) {
+ bool terminal_trouvee = false;
+ foreach(QDomElement qde, liste_terminals) {
+ if (p -> fromXml(qde)) {
+ priv_id_adr.insert(qde.attribute("id").toInt(), p);
+ terminal_trouvee = true;
+ // We used to break here, because we did not expect
+ // several terminals to share the same position.
+ // Of course, it finally happened.
+ }
+ }
+ if (!terminal_trouvee) ++ terminals_non_trouvees;
+ }
+ }
+
+ if (terminals_non_trouvees > 0) {
+ return(false);
+ } else {
+ // verifie que les associations id / adr n'entrent pas en conflit avec table_id_adr
+ foreach(int id_trouve, priv_id_adr.keys()) {
+ if (table_id_adr.contains(id_trouve)) {
+ // cet element possede un id qui est deja reference (= conflit)
+ return(false);
+ }
+ }
+ // copie des associations id / adr
+ foreach(int id_trouve, priv_id_adr.keys()) {
+ table_id_adr.insert(id_trouve, priv_id_adr.value(id_trouve));
+ }
+ }
+
+ // importe les valeurs des champs de texte
+ QList<QDomElement> inputs = QET::findInDomElement(e, "inputs", "input");
+ foreach(QGraphicsItem *qgi, childItems()) {
+ if (ElementTextItem *eti = qgraphicsitem_cast<ElementTextItem *>(qgi)) {
+ foreach(QDomElement input, inputs) eti -> fromXml(input);
+ }
+ }
+
+ // position, selection
+ setPos(e.attribute("x").toDouble(), e.attribute("y").toDouble());
+ setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
+
+ // orientation
+ bool conv_ok;
+ int read_ori = e.attribute("orientation").toInt(&conv_ok);
+ if (!conv_ok || read_ori < 0 || read_ori > 3) read_ori = ori.defaultOrientation();
+ if (handle_inputs_rotation) {
+ RotateElementsCommand::rotateElement(this, (QET::Orientation)read_ori);
+ } else {
+ setOrientation((QET::Orientation)read_ori);
+ }
+ return(true);
+}
+
+/**
+ Permet d'exporter l'element en XML
+ @param document Document XML a utiliser
+ @param table_adr_id Table de correspondance entre les adresses des bornes
+ et leur id dans la representation XML ; cette table completee par cette
+ methode
+ @return L'element XML representant cet element electrique
+*/
+QDomElement Element::toXml(QDomDocument &document, QHash<Terminal *, int> &table_adr_id) const {
+ QDomElement element = document.createElement("element");
+
+ // type
+ element.setAttribute("type", typeId());
+
+ // position, selection et orientation
+ element.setAttribute("x", QString("%1").arg(pos().x()));
+ element.setAttribute("y", QString("%1").arg(pos().y()));
+ element.setAttribute("orientation", QString("%1").arg(ori.current()));
+
+ /* recupere le premier id a utiliser pour les bornes de cet element */
+ int id_terminal = 0;
+ if (!table_adr_id.isEmpty()) {
+ // trouve le plus grand id
+ int max_id_t = -1;
+ foreach (int id_t, table_adr_id.values()) {
+ if (id_t > max_id_t) max_id_t = id_t;
+ }
+ id_terminal = max_id_t + 1;
+ }
+
+ // enregistrement des bornes de l'appareil
+ QDomElement xml_terminals = document.createElement("terminals");
+ // pour chaque enfant de l'element
+ foreach(Terminal *t, terminals()) {
+ // alors on enregistre la borne
+ QDomElement terminal = t -> toXml(document);
+ terminal.setAttribute("id", id_terminal);
+ table_adr_id.insert(t, id_terminal ++);
+ xml_terminals.appendChild(terminal);
+ }
+ element.appendChild(xml_terminals);
+
+ // enregistrement des champ de texte de l'appareil
+ QDomElement inputs = document.createElement("inputs");
+ foreach(ElementTextItem *eti, texts()) {
+ inputs.appendChild(eti -> toXml(document));
+ }
+ element.appendChild(inputs);
+
+ return(element);
+}
Added: branches/devel/sources/qetgraphicsitem/element.h
===================================================================
--- branches/devel/sources/qetgraphicsitem/element.h (rev 0)
+++ branches/devel/sources/qetgraphicsitem/element.h 2013-11-07 09:18:03 UTC (rev 2596)
@@ -0,0 +1,157 @@
+/*
+ Copyright 2006-2013 The QElectroTech Team
+ 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/>.
+*/
+#ifndef ELEMENT_H
+#define ELEMENT_H
+#include <QtGui>
+#include "terminal.h"
+#include "orientationset.h"
+#include "qetgraphicsitem.h"
+class Diagram;
+class ElementTextItem;
+/**
+ This is the base class for electrical elements.
+*/
+class Element : public QetGraphicsItem {
+
+ Q_OBJECT
+
+ // constructors, destructor
+ public:
+ Element(QGraphicsItem * = 0, Diagram * = 0);
+ virtual ~Element();
+
+ private:
+ Element(const Element &);
+
+ // attributes
+ public:
+ enum { Type = UserType + 1000 };
+
+ protected:
+ /**
+ Hold orientations for the element :
+ * allowed orientations
+ * current orientation
+ * default orientation
+ @see OrientationSet
+ */
+ OrientationSet ori;
+
+ private:
+ QSize dimensions;
+ QPoint hotspot_coord;
+ QPixmap preview;
+
+ // methods
+ public:
+ /**
+ Enable the use of qgraphicsitem_cast to safely cast a QGraphicsItem into an
+ Element.
+ @return the QGraphicsItem type
+ */
+ virtual int type() const { return Type; }
+
+ // pure virtual methods to be defined in derived classes
+ /// @return the list of terminals for this element
+ virtual QList<Terminal *> terminals() const = 0;
+ /// @return the list of conductors attached to this element
+ virtual QList<Conductor *> conductors() const = 0;
+ /// @return the list of text items attached to this element
+ virtual QList<ElementTextItem *> texts() const = 0;
+ /// @return the current number of terminals of this element
+ virtual int terminalsCount() const = 0;
+ /// @return the minimum number of terminals for this element
+ virtual int minTerminalsCount() const = 0;
+ /// @return the maximum number of terminals for this element
+ virtual int maxTerminalsCount() const = 0;
+ /**
+ Draw this element
+ */
+ virtual void paint(QPainter *, const QStyleOptionGraphicsItem *) = 0;
+ /// @return This element type ID
+ virtual QString typeId() const = 0;
+ /// @return the human name for this element
+ virtual QString name() const = 0;
+
+ virtual bool isHighlighted() const;
+ virtual void setHighlighted(bool);
+ void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *);
+ QRectF boundingRect() const;
+ QSize setSize(int, int);
+ QSize size() const;
+ QPixmap pixmap();
+
+ // methods related to the hotspot
+ QPoint setHotspot(QPoint);
+ QPoint hotspot() const;
+
+ // selection-related methods
+ void select();
+ void deselect();
+
+ // methods related to internal connections
+ bool internalConnections();
+ void setInternalConnections(bool);
+
+ // methods related to XML import/export
+ static bool valideXml(QDomElement &);
+ virtual bool fromXml(QDomElement &, QHash<int, Terminal *> &, bool = false);
+ virtual QDomElement toXml(QDomDocument &, QHash<Terminal *, int> &) const;
+
+ // orientation-related methods
+ bool setOrientation(QET::Orientation o);
+ const OrientationSet &orientation() const;
+
+ protected:
+ void drawAxes(QPainter *, const QStyleOptionGraphicsItem *);
+
+ private:
+ bool internal_connections_;
+ bool must_highlight_;
+ void drawSelection(QPainter *, const QStyleOptionGraphicsItem *);
+ void drawHighlight(QPainter *, const QStyleOptionGraphicsItem *);
+ void updatePixmap();
+};
+
+/**
+ Indicate whether this element allows internal connections, i.e. whether its
+ terminals can be linked together using a conductor.
+ @return true if internal connections are accepted, false otherwise
+*/
+inline bool Element::internalConnections() {
+ return(internal_connections_);
+}
+
+/**
+ Specify whether this element allows internal connections, i.e. whether its
+ terminals can be linked together using a conductor.
+ @return true for internal connections to be accepted, false otherwise
+*/
+inline void Element::setInternalConnections(bool ic) {
+ internal_connections_ = ic;
+}
+
+/**
+ Indicate the current orientation of this element
+ @return the current orientation of this element
+*/
+inline const OrientationSet & Element::orientation() const {
+ return(ori);
+}
+
+#endif
Added: branches/devel/sources/qetgraphicsitem/elementtextitem.cpp
===================================================================
--- branches/devel/sources/qetgraphicsitem/elementtextitem.cpp (rev 0)
+++ branches/devel/sources/qetgraphicsitem/elementtextitem.cpp 2013-11-07 09:18:03 UTC (rev 2596)
@@ -0,0 +1,310 @@
+/*
+ Copyright 2006-2012 Xavier Guerrin
+ 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/>.
+*/
+#include "elementtextitem.h"
+#include "diagram.h"
+#include "diagramcommands.h"
+#include "element.h"
+
+/**
+ Constructeur
+ @param parent_element Le QGraphicsItem parent du champ de texte
+ @param parent_diagram Le schema auquel appartient le champ de texte
+*/
+ElementTextItem::ElementTextItem(Element *parent_element, Diagram *parent_diagram) :
+ DiagramTextItem(parent_element, parent_diagram),
+ parent_element_(parent_element),
+ follow_parent_rotations(false),
+ original_rotation_angle_(0.0),
+ first_move_(true)
+{
+ // par defaut, les DiagramTextItem sont Selectable et Movable
+ // cela nous convient, on ne touche pas a ces flags
+
+ adjustItemPosition(1);
+ // ajuste la position du QGraphicsItem lorsque le QTextDocument change
+ connect(document(), SIGNAL(blockCountChanged(int)), this, SLOT(adjustItemPosition(int)));
+ connect(document(), SIGNAL(contentsChanged()), this, SLOT(adjustItemPosition()));
+}
+
+/**
+ Constructeur
+ @param parent_element L'element parent du champ de texte
+ @param parent_diagram Le schema auquel appartient le champ de texte
+ @param text Le texte affiche par le champ de texte
+*/
+ElementTextItem::ElementTextItem(const QString &text, Element *parent_element, Diagram *parent_diagram) :
+ DiagramTextItem(text, parent_element, parent_diagram),
+ parent_element_(parent_element),
+ follow_parent_rotations(false),
+ original_rotation_angle_(0.0),
+ first_move_(true)
+{
+ // par defaut, les DiagramTextItem sont Selectable et Movable
+ // cela nous convient, on ne touche pas a ces flags
+
+ adjustItemPosition(1);
+ // ajuste la position du QGraphicsItem lorsque le QTextDocument change
+ connect(document(), SIGNAL(blockCountChanged(int)), this, SLOT(adjustItemPosition(int)));
+ connect(document(), SIGNAL(contentsChanged()), this, SLOT(adjustItemPosition()));
+}
+
+/// Destructeur
+ElementTextItem::~ElementTextItem() {
+}
+
+/**
+ @return L'element parent de ce champ de texte, ou 0 si celui-ci n'en a pas.
+*/
+Element *ElementTextItem::parentElement() const {
+ return(parent_element_);
+}
+
+/**
+ Modifie la position du champ de texte
+ @param pos La nouvelle position du champ de texte
+*/
+void ElementTextItem::setPos(const QPointF &pos) {
+ QGraphicsTextItem::setPos(pos);
+}
+
+/**
+ Modifie la position du champ de texte
+ @param x La nouvelle abscisse du champ de texte
+ @param y La nouvelle ordonnee du champ de texte
+*/
+void ElementTextItem::setPos(qreal x, qreal y) {
+ setPos(QPointF(x, y));
+}
+
+/**
+ @return La position (bidouillee) du champ de texte
+*/
+QPointF ElementTextItem::pos() const {
+ return(QGraphicsTextItem::pos());
+}
+
+/**
+ Permet de lire le texte a mettre dans le champ a partir d'un element XML.
+ Cette methode se base sur la position du champ pour assigner ou non la
+ valeur a ce champ.
+ @param e L'element XML representant le champ de texte
+*/
+void ElementTextItem::fromXml(const QDomElement &e) {
+ QPointF _pos = pos();
+ if (
+ qFuzzyCompare(qreal(e.attribute("x").toDouble()), _pos.x()) &&
+ qFuzzyCompare(qreal(e.attribute("y").toDouble()), _pos.y())
+ ) {
+ setPlainText(e.attribute("text"));
+
+ qreal user_pos_x, user_pos_y;
+ if (
+ QET::attributeIsAReal(e, "userx", &user_pos_x) &&
+ QET::attributeIsAReal(e, "usery", &user_pos_y)
+ ) {
+ setPos(user_pos_x, user_pos_y);
+ }
+
+ qreal xml_rotation_angle;
+ if (QET::attributeIsAReal(e, "userrotation", &xml_rotation_angle)) {
+ setRotationAngle(xml_rotation_angle);
+ }
+ }
+}
+
+/**
+ @param document Le document XML a utiliser
+ @return L'element XML representant ce champ de texte
+*/
+QDomElement ElementTextItem::toXml(QDomDocument &document) const {
+ QDomElement result = document.createElement("input");
+
+ result.setAttribute("x", QString("%1").arg(originalPos().x()));
+ result.setAttribute("y", QString("%1").arg(originalPos().y()));
+
+ if (pos() != originalPos()) {
+ result.setAttribute("userx", QString("%1").arg(pos().x()));
+ result.setAttribute("usery", QString("%1").arg(pos().y()));
+ }
+
+ result.setAttribute("text", toPlainText());
+
+ if (rotationAngle() != originalRotationAngle()) {
+ result.setAttribute("userrotation", QString("%1").arg(rotationAngle()));
+ }
+
+ return(result);
+}
+
+/**
+ @param p Position originale / de reference pour ce champ
+ Cette position est utilisee lors de l'export en XML
+*/
+void ElementTextItem::setOriginalPos(const QPointF &p) {
+ original_position = p;
+}
+
+/**
+ @return la position originale / de reference pour ce champ
+*/
+QPointF ElementTextItem::originalPos() const {
+ return(original_position);
+}
+
+/**
+ Definit l'angle de rotation original de ce champ de texte
+ @param rotation_angle un angle de rotation
+*/
+void ElementTextItem::setOriginalRotationAngle(const qreal &rotation_angle) {
+ original_rotation_angle_ = QET::correctAngle(rotation_angle);
+}
+
+/**
+ @return l'angle de rotation original de ce champ de texte
+*/
+qreal ElementTextItem::originalRotationAngle() const {
+ return(original_rotation_angle_);
+}
+
+/**
+ Set the font used to render the text item to \a font.
+*/
+void ElementTextItem::setFont(const QFont &font) {
+ DiagramTextItem::setFont(font);
+ adjustItemPosition(1);
+}
+
+/**
+ Cette methode s'assure que la position de l'ElementTextItem est coherente
+ en ajustant :
+ * la transformation de base qui permet de considerer que l'origine
+ correspond au milieu du bord gauche du champ de texte
+ * l'origine utilisee lors des appels a setRotation et setScale
+ @param new_block_count Nombre de blocs dans l'ElementTextItem
+*/
+void ElementTextItem::adjustItemPosition(int new_block_count) {
+ Q_UNUSED(new_block_count);
+ qreal origin_offset = boundingRect().bottom() / 2.0;
+
+ QTransform base_translation;
+ base_translation.translate(0.0, -origin_offset);
+ setTransform(base_translation, false);
+ setTransformOriginPoint(0.0, origin_offset);
+}
+
+/**
+ Effetue la rotation du texte en elle-meme
+ Pour les ElementTextItem, la rotation s'effectue autour du milieu du bord
+ gauche du champ de texte.
+ @param angle Angle de la rotation a effectuer
+*/
+void ElementTextItem::applyRotation(const qreal &angle) {
+ QGraphicsTextItem::setRotation(QGraphicsTextItem::rotation() + angle);
+}
+
+/**
+ Gere le clic sur le champ de texte
+ @param e Objet decrivant l'evenement souris
+*/
+void ElementTextItem::mousePressEvent(QGraphicsSceneMouseEvent *e) {
+ first_move_ = true;
+ if (e -> modifiers() & Qt::ControlModifier) {
+ setSelected(!isSelected());
+ }
+ DiagramTextItem::mousePressEvent(e);
+}
+
+/**
+ Gere les mouvements de souris lies au champ de texte
+ @param e Objet decrivant l'evenement souris
+*/
+void ElementTextItem::mouseMoveEvent(QGraphicsSceneMouseEvent *e) {
+ if (textInteractionFlags() & Qt::TextEditable) {
+ DiagramTextItem::mouseMoveEvent(e);
+ } else if ((flags() & QGraphicsItem::ItemIsMovable) && (e -> buttons() & Qt::LeftButton)) {
+ QPointF old_pos = pos();
+ /*
+ Utiliser e -> pos() directement aurait pour effet de positionner
+ l'origine du champ de texte a la position indiquee par le curseur,
+ ce qui n'est pas l'effet recherche
+ Au lieu de cela, on applique a la position actuelle le vecteur
+ definissant le mouvement effectue depuis la derniere position
+ cliquee avec le bouton gauche
+ */
+ QPointF movement = e -> pos() - e -> buttonDownPos(Qt::LeftButton);
+
+ /*
+ Les methodes pos() et setPos() travaillent toujours avec les
+ coordonnees de l'item parent (ou de la scene s'il n'y a pas d'item
+ parent). On n'oublie donc pas de mapper le mouvement fraichement
+ calcule sur l'item parent avant de l'appliquer.
+ */
+ QPointF parent_movement = mapMovementToParent(movement);
+ setPos(pos() + parent_movement);
+
+ Diagram *diagram_ptr = diagram();
+ if (diagram_ptr) {
+ if (first_move_) {
+ // on signale le debut d'un deplacement d'ElementTextItems au schema parent
+ int moved_texts_count = diagram_ptr -> beginMoveElementTexts(this);
+
+ // s'il n'y a qu'un seul texte deplace, on met en valeur l'element parent
+ if (moved_texts_count == 1 && parent_element_) {
+ parent_element_ -> setHighlighted(true);
+ parent_element_ -> update();
+ }
+ }
+
+ /*
+ Comme setPos() n'est pas oblige d'appliquer exactement la
+ valeur qu'on lui fournit, on calcule le mouvement reellement
+ applique.
+ */
+ QPointF effective_movement = pos() - old_pos;
+ QPointF scene_effective_movement = mapMovementToScene(mapMovementFromParent(effective_movement));
+
+ // on applique le mouvement subi aux autres textes a deplacer
+ diagram_ptr -> continueMoveElementTexts(scene_effective_movement);
+ }
+ } else e -> ignore();
+
+ if (first_move_) {
+ first_move_ = false;
+ }
+}
+
+/**
+ Gere le relachement de souris
+ Cette methode cree un objet d'annulation pour le deplacement
+ @param e Objet decrivant l'evenement souris
+*/
+void ElementTextItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *e) {
+ if (Diagram *diagram_ptr = diagram()) {
+ // on arrete de mettre en valeur l'element parent
+ if (parent_element_) {
+ if (parent_element_ -> isHighlighted()) {
+ parent_element_ -> setHighlighted(false);
+ }
+ }
+
+ diagram_ptr -> endMoveElementTexts();
+ }
+ if (!(e -> modifiers() & Qt::ControlModifier)) {
+ QGraphicsTextItem::mouseReleaseEvent(e);
+ }
+}
Added: branches/devel/sources/qetgraphicsitem/elementtextitem.h
===================================================================
--- branches/devel/sources/qetgraphicsitem/elementtextitem.h (rev 0)
+++ branches/devel/sources/qetgraphicsitem/elementtextitem.h 2013-11-07 09:18:03 UTC (rev 2596)
@@ -0,0 +1,96 @@
+/*
+ Copyright 2006-2012 Xavier Guerrin
+ 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/>.
+*/
+#ifndef ELEMENT_TEXT_ITEM_H
+#define ELEMENT_TEXT_ITEM_H
+#include "diagramtextitem.h"
+#include <QtXml>
+class Diagram;
+class Element;
+/**
+ This class represents a text item attached to an element. Users can change its
+ value, adjust its position (defined relatively to its parent element), and
+ direct it to any angle.
+*/
+class ElementTextItem : public DiagramTextItem {
+ Q_OBJECT
+ // constructors, destructor
+ public:
+ ElementTextItem(Element * = 0, Diagram * = 0);
+ ElementTextItem(const QString &, Element * = 0, Diagram * = 0);
+ virtual ~ElementTextItem();
+
+ // attributes
+ public:
+ enum { Type = UserType + 1003 };
+
+ private:
+ Element *parent_element_;
+ bool follow_parent_rotations;
+ QPointF original_position;
+ qreal original_rotation_angle_;
+ bool first_move_;
+
+ // methods
+ public:
+ virtual int type() const { return Type; }
+ Element *parentElement() const;
+ /// @return the rectangle defining the bounds of this text item
+ virtual QRectF boundingRect() const { return(QGraphicsTextItem::boundingRect().adjusted(0.0, -1.1, 0.0, 0.0)); }
+ bool followParentRotations() const;
+ void setFollowParentRotations(bool);
+ void fromXml(const QDomElement &);
+ QDomElement toXml(QDomDocument &) const;
+ void setPos(const QPointF &);
+ void setPos(qreal, qreal);
+ virtual QPointF pos() const;
+ void setOriginalPos(const QPointF &);
+ QPointF originalPos() const;
+ void setOriginalRotationAngle(const qreal &);
+ qreal originalRotationAngle() const;
+ virtual void setFont(const QFont &);
+
+ public slots:
+ void adjustItemPosition(int = 0);
+
+ protected:
+ virtual void applyRotation(const qreal &);
+ virtual void mousePressEvent(QGraphicsSceneMouseEvent *);
+ virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *);
+ virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *);
+};
+
+/**
+ Element text items can optionally be applied a counter-rotation when their
+ parent element is rotated, thus preserving their readability.
+ @return whether this text item follows the rotations of its parent element.
+*/
+inline bool ElementTextItem::followParentRotations() const {
+ return(follow_parent_rotations);
+}
+
+/**
+ Element text items can optionally be applied a counter-rotation when their
+ parent element is rotated, thus preserving their readability.
+ @param frp whether this text item should follow the rotations of its parent
+ element.
+*/
+inline void ElementTextItem::setFollowParentRotations(bool frp) {
+ follow_parent_rotations = frp;
+}
+
+#endif
Added: branches/devel/sources/qetgraphicsitem/fixedelement.cpp
===================================================================
--- branches/devel/sources/qetgraphicsitem/fixedelement.cpp (rev 0)
+++ branches/devel/sources/qetgraphicsitem/fixedelement.cpp 2013-11-07 09:18:03 UTC (rev 2596)
@@ -0,0 +1,43 @@
+/*
+ Copyright 2006-2012 Xavier Guerrin
+ 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/>.
+*/
+#include "fixedelement.h"
+/**
+ Constructeur
+*/
+FixedElement::FixedElement(QGraphicsItem *parent, Diagram *scene) : Element(parent, scene) {
+}
+
+/**
+ Destructeur
+*/
+FixedElement::~FixedElement() {
+}
+
+/**
+ @return Le nombre minimal de bornes que l'element peut avoir
+*/
+int FixedElement::minTerminalsCount() const {
+ return(terminalsCount());
+}
+
+/**
+ @return Le nombre maximal de bornes que l'element peut avoir
+*/
+int FixedElement::maxTerminalsCount() const {
+ return(terminalsCount());
+}
Added: branches/devel/sources/qetgraphicsitem/fixedelement.h
===================================================================
--- branches/devel/sources/qetgraphicsitem/fixedelement.h (rev 0)
+++ branches/devel/sources/qetgraphicsitem/fixedelement.h 2013-11-07 09:18:03 UTC (rev 2596)
@@ -0,0 +1,42 @@
+/*
+ Copyright 2006-2012 Xavier Guerrin
+ 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/>.
+*/
+#ifndef ELEMENTFIXE_H
+#define ELEMENTFIXE_H
+#include "element.h"
+/**
+ This class represents an element having a fixed number of terminals.
+*/
+class FixedElement : public Element {
+
+ Q_OBJECT
+
+ // constructors, destructor
+ public:
+ FixedElement(QGraphicsItem * = 0, Diagram * = 0);
+ virtual ~FixedElement();
+
+ // methods
+ public:
+ int minTerminalsCount() const;
+ int maxTerminalsCount() const;
+ virtual int terminalsCount() const = 0;
+ virtual void paint(QPainter *, const QStyleOptionGraphicsItem *) = 0;
+ virtual QString typeId() const = 0;
+ virtual QString name() const = 0;
+};
+#endif
Added: branches/devel/sources/qetgraphicsitem/ghostelement.cpp
===================================================================
--- branches/devel/sources/qetgraphicsitem/ghostelement.cpp (rev 0)
+++ branches/devel/sources/qetgraphicsitem/ghostelement.cpp 2013-11-07 09:18:03 UTC (rev 2596)
@@ -0,0 +1,191 @@
+/*
+ Copyright 2006-2012 Xavier Guerrin
+ 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/>.
+*/
+#include "ghostelement.h"
+#include "qet.h"
+#include "terminal.h"
+#include "elementtextitem.h"
+#include "diagramcommands.h"
+
+/**
+ Constructeur
+ @param location Emplacement de la definition d'element a utiliser
+ @param qgi Le QGraphicsItem parent de cet element
+ @param d Le schema affichant cet element
+*/
+GhostElement::GhostElement(
+ const ElementsLocation &location,
+ QGraphicsItem *qgi,
+ Diagram *d
+) :
+ CustomElement(location, qgi, d)
+{
+ QString tooltip_string = QString(
+ tr("<u>\311l\351ment manquant\240:</u> %1")
+ ).arg(location_.toString());
+ setToolTip(tooltip_string);
+}
+
+/**
+ Destructeur
+*/
+GhostElement::~GhostElement() {
+}
+
+
+/**
+ @param e L'element XML a analyser.
+ @param table_id_adr Reference vers la table de correspondance entre les IDs
+ du fichier XML et les adresses en memoire. Si l'import reussit, il faut y
+ ajouter les bons couples (id, adresse).
+ @return true si l'import a reussi, false sinon
+*/
+bool GhostElement::fromXml(QDomElement &e, QHash<int, Terminal *> &table_id_adr, bool handle_inputs_rotation) {
+ // instancie les bornes decrites dans l'element XML
+ terminalsFromXml(e, table_id_adr);
+
+ // instancie les champs de texte decrits dans l'element XML
+ foreach(QDomElement qde, QET::findInDomElement(e, "inputs", "input")) {
+ qde.setAttribute("size", 9); // arbitraire
+ if (ElementTextItem *new_input = CustomElement::parseInput(qde)) {
+ new_input -> fromXml(qde);
+ }
+ qde.removeAttribute("size");
+ }
+
+ /*
+ maintenant que l'element fantome connait toutes les bornes et tous les
+ champs de texte, on peut determiner une taille appropriee
+ */
+ QRect final_bounding_rect = minimalBoundingRect().united(childrenBoundingRect()).toAlignedRect();
+ setSize(final_bounding_rect.width(), final_bounding_rect.height());
+ setHotspot(QPoint() - final_bounding_rect.topLeft());
+ setInternalConnections(true);
+
+ // on peut desormais confectionner le rendu de l'element
+ generateDrawings();
+
+ // position, selection
+ setPos(e.attribute("x").toDouble(), e.attribute("y").toDouble());
+ setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
+
+ // orientation
+ bool conv_ok;
+ int read_ori = e.attribute("orientation").toInt(&conv_ok);
+ if (!conv_ok || read_ori < 0 || read_ori > 3) read_ori = ori.defaultOrientation();
+ if (handle_inputs_rotation) {
+ RotateElementsCommand::rotateElement(this, (QET::Orientation)read_ori);
+ } else {
+ setOrientation((QET::Orientation)read_ori);
+ }
+ return(true);
+}
+
+/**
+ @return le bounding rect minimum, utilise si l'element fantome n'a ni champ
+ de texte ni borne.
+*/
+QRectF GhostElement::minimalBoundingRect() const {
+ return(
+ QRectF(
+ QPointF(-10.0, -10.0),
+ QSizeF(20.0, 20.0)
+ )
+ );
+}
+
+/**
+ Gere l'import des bornes
+ @param e L'element XML a analyser.
+ @param table_id_adr Reference vers la table de correspondance entre les IDs
+ du fichier XML et les adresses en memoire. Si l'import reussit, il faut y
+ ajouter les bons couples (id, adresse).
+ @return true si l'import a reussi, false sinon
+*/
+bool GhostElement::terminalsFromXml(QDomElement &e, QHash<int, Terminal *> &table_id_adr) {
+ // instancie les bornes decrites dans l'element XML
+ foreach(QDomElement qde, QET::findInDomElement(e, "terminals", "terminal")) {
+ if (!Terminal::valideXml(qde)) continue;
+
+ // modifie certains attributs pour que l'analyse par la classe CustomElement reussisse
+ int previous_x_value = qde.attribute("x").toInt();
+ int previous_y_value = qde.attribute("y").toInt();
+ int previous_ori_value = qde.attribute("orientation").toInt();
+
+ qreal x_add = 0.0, y_add = 0.0;
+ if (previous_ori_value == QET::North) y_add = -Terminal::terminalSize;
+ else if (previous_ori_value == QET::East) x_add = Terminal::terminalSize;
+ else if (previous_ori_value == QET::South) y_add = Terminal::terminalSize;
+ else if (previous_ori_value == QET::West) x_add = -Terminal::terminalSize;
+ qde.setAttribute("x", previous_x_value + x_add);
+ qde.setAttribute("y", previous_y_value + y_add);
+ qde.setAttribute("orientation", QET::orientationToString(static_cast<QET::Orientation>(previous_ori_value)));
+
+ if (Terminal *new_terminal = CustomElement::parseTerminal(qde)) {
+ table_id_adr.insert(qde.attribute("id").toInt(), new_terminal);
+ }
+
+ // restaure les attributs modifies
+ qde.setAttribute("x", previous_x_value);
+ qde.setAttribute("y", previous_y_value);
+ qde.setAttribute("orientation", previous_ori_value);
+ }
+ return(true);
+}
+
+/**
+ Genere les rendus de l'element fantome : il s'agit d'un rectangle
+ representant grosso modo l'espace que devait prendre l'element initial.
+ En son centre est dessine un point d'interrogation. Une petite croix indique
+ le point de saisie de l'element.
+*/
+void GhostElement::generateDrawings() {
+ // style de dessin
+ QPen t(QBrush(Qt::black), 1.0);
+
+ // rendu normal
+ QPainter qp;
+ qp.begin(&drawing);
+ qp.setPen(t);
+ qp.setRenderHint(QPainter::Antialiasing, false);
+ generateDrawing(&qp);
+ qp.end();
+
+ // rendu low_zoom
+ QPainter low_zoom_qp;
+ low_zoom_qp.begin(&low_zoom_drawing);
+ t.setCosmetic(true);
+ low_zoom_qp.setRenderHint(QPainter::Antialiasing, false);
+ low_zoom_qp.setPen(t);
+ generateDrawing(&low_zoom_qp);
+ low_zoom_qp.end();
+}
+
+/**
+ Genere un rendu de l'element fantome
+ @see generateDrawings
+*/
+void GhostElement::generateDrawing(QPainter *painter) {
+ // une petite croix indique le point de saisie de l'element
+ painter -> drawLine(QLineF(-1.0, 0.0, 1.0, 0.0));
+ painter -> drawLine(QLineF(0.0, -1.0, 0.0, 1.0));
+
+ // rectangle avec un point d'interrogation au centre
+ QRectF drawn_rect = boundingRect().adjusted(4.0, 4.0, -4.0, -4.0);
+ painter -> drawRect(drawn_rect);
+ painter -> drawText(drawn_rect, Qt::AlignHCenter | Qt::AlignVCenter, "?");
+}
Added: branches/devel/sources/qetgraphicsitem/ghostelement.h
===================================================================
--- branches/devel/sources/qetgraphicsitem/ghostelement.h (rev 0)
+++ branches/devel/sources/qetgraphicsitem/ghostelement.h 2013-11-07 09:18:03 UTC (rev 2596)
@@ -0,0 +1,53 @@
+/*
+ Copyright 2006-2012 Xavier Guerrin
+ 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/>.
+*/
+#ifndef GHOST_ELEMENT_H
+#define GHOST_ELEMENT_H
+#include "customelement.h"
+class Diagram;
+class QGraphicsItem;
+class ElementsLocation;
+class Terminal;
+/**
+ The GhostElement class inherits CustomElement. A GhostElement aims at
+ visually replacing a CustomElement whose definition could not be loaded.
+ This way, instead of not loading an element, thus potentially losing its
+ position, its orientation, its child text items and conductors, one can
+ substitute a GhostElement. The GhostElement will extrapolate the position
+ of terminals and text items from the rest of the diagram. It is visually
+ rendered using a simple rectangle.
+*/
+class GhostElement : public CustomElement {
+
+ Q_OBJECT
+
+ // constructor, destructor
+ public:
+ GhostElement(const ElementsLocation &, QGraphicsItem * = 0, Diagram * = 0);
+ virtual ~GhostElement();
+
+ // methods
+ public:
+ virtual bool fromXml(QDomElement &, QHash<int, Terminal *> &, bool = false);
+
+ protected:
+ QRectF minimalBoundingRect() const;
+ bool terminalsFromXml(QDomElement &, QHash<int, Terminal *> &);
+ void generateDrawings();
+ void generateDrawing(QPainter *);
+};
+#endif
Added: branches/devel/sources/qetgraphicsitem/independenttextitem.cpp
===================================================================
--- branches/devel/sources/qetgraphicsitem/independenttextitem.cpp (rev 0)
+++ branches/devel/sources/qetgraphicsitem/independenttextitem.cpp 2013-11-07 09:18:03 UTC (rev 2596)
@@ -0,0 +1,140 @@
+/*
+ Copyright 2006-2012 Xavier Guerrin
+ 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/>.
+*/
+#include "independenttextitem.h"
+#include "diagram.h"
+
+/**
+ Constructeur
+ @param parent_diagram Le schema auquel est rattache le champ de texte
+*/
+IndependentTextItem::IndependentTextItem(Diagram *parent_diagram) :
+ DiagramTextItem(0, parent_diagram),
+ first_move_(true)
+{
+}
+
+/**
+ Constructeur
+ @param text Le texte affiche par le champ de texte
+ @param parent_diagram Le schema auquel est rattache le champ de texte
+*/
+IndependentTextItem::IndependentTextItem(const QString &text, Diagram *parent_diagram) :
+ DiagramTextItem(text, 0, parent_diagram),
+ first_move_(true)
+{
+}
+
+/// Destructeur
+IndependentTextItem::~IndependentTextItem() {
+}
+
+/**
+ Permet de lire le texte a mettre dans le champ a partir d'un element XML.
+ Cette methode se base sur la position du champ pour assigner ou non la
+ valeur a ce champ.
+ @param e L'element XML representant le champ de texte
+*/
+void IndependentTextItem::fromXml(const QDomElement &e) {
+ setPos(e.attribute("x").toDouble(), e.attribute("y").toDouble());
+ setHtml(e.attribute("text"));
+ setRotationAngle(e.attribute("rotation").toDouble());
+}
+
+/**
+ @param document Le document XML a utiliser
+ @return L'element XML representant ce champ de texte
+*/
+QDomElement IndependentTextItem::toXml(QDomDocument &document) const {
+ QDomElement result = document.createElement("input");
+ result.setAttribute("x", QString("%1").arg(pos().x()));
+ result.setAttribute("y", QString("%1").arg(pos().y()));
+ result.setAttribute("text", toHtml());
+ if (rotationAngle()) {
+ result.setAttribute("rotation", QString("%1").arg(rotationAngle()));
+ }
+ return(result);
+}
+
+/**
+ Gere le clic sur le champ de texte
+ @param e Objet decrivant l'evenement souris
+*/
+void IndependentTextItem::mousePressEvent(QGraphicsSceneMouseEvent *e) {
+ first_move_ = true;
+ if (e -> modifiers() & Qt::ControlModifier) {
+ setSelected(!isSelected());
+ }
+ DiagramTextItem::mousePressEvent(e);
+}
+
+/**
+ Gere les mouvements de souris lies au champ de texte
+ @param e Objet decrivant l'evenement souris
+*/
+void IndependentTextItem::mouseMoveEvent(QGraphicsSceneMouseEvent *e) {
+ if (textInteractionFlags() & Qt::TextEditable) {
+ DiagramTextItem::mouseMoveEvent(e);
+ } else if ((flags() & QGraphicsItem::ItemIsMovable) && isSelected() && (e -> buttons() & Qt::LeftButton)) {
+ // le champ de texte est en train d'etre deplace
+ Diagram *diagram_ptr = diagram();
+ if (diagram_ptr) {
+ if (first_move_) {
+ // il s'agit du premier mouvement du deplacement, on le signale
+ // au schema parent
+ diagram_ptr -> beginMoveElements(this);
+ }
+ }
+
+ // on applique le mouvement impose par la souris
+ QPointF old_pos = pos();
+ if (first_move_) {
+ mouse_to_origin_movement_ = old_pos - e -> buttonDownScenePos(Qt::LeftButton);
+ }
+ QPointF expected_pos = e-> scenePos() + mouse_to_origin_movement_;
+ setPos(expected_pos); // setPos() will snap the expected position to the grid
+
+ // on calcule le mouvement reellement applique par setPos()
+ QPointF effective_movement = pos() - old_pos;
+ if (diagram_ptr) {
+ // on signale le mouvement ainsi applique au schema parent, qui
+ // l'appliquera aux autres items selectionnes selon son bon vouloir
+ diagram_ptr -> continueMoveElements(effective_movement);
+ }
+ } else e -> ignore();
+
+ if (first_move_) {
+ first_move_ = false;
+ }
+}
+
+/**
+ Gere le relachement de souris
+ Cette methode a ete reimplementee pour tenir a jour la liste des elements
+ et conducteurs a deplacer au niveau du schema.
+ @param e Objet decrivant l'evenement souris
+*/
+void IndependentTextItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *e) {
+ if (flags() & QGraphicsItem::ItemIsMovable) {
+ if (Diagram *diagram_ptr = diagram()) {
+ diagram_ptr -> endMoveElements();
+ }
+ }
+ if (!(e -> modifiers() & Qt::ControlModifier)) {
+ DiagramTextItem::mouseReleaseEvent(e);
+ }
+}
Added: branches/devel/sources/qetgraphicsitem/independenttextitem.h
===================================================================
--- branches/devel/sources/qetgraphicsitem/independenttextitem.h (rev 0)
+++ branches/devel/sources/qetgraphicsitem/independenttextitem.h 2013-11-07 09:18:03 UTC (rev 2596)
@@ -0,0 +1,58 @@
+/*
+ Copyright 2006-2012 Xavier Guerrin
+ 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/>.
+*/
+#ifndef INDEPENDENT_TEXT_ITEM_H
+#define INDEPENDENT_TEXT_ITEM_H
+#include <QtGui>
+#include "diagramtextitem.h"
+/**
+ This class represents an independent text field on a particular diagram.
+ It may be moved, edited, and rotated.
+*/
+class IndependentTextItem : public DiagramTextItem {
+ Q_OBJECT
+ // constructors, destructor
+ public:
+ IndependentTextItem(Diagram * = 0);
+ IndependentTextItem(const QString &, Diagram* = 0);
+ virtual ~IndependentTextItem();
+
+ // attributes
+ public:
+ enum { Type = UserType + 1005 };
+
+ // methods
+ public:
+ /**
+ Enable the use of qgraphicsitem_cast to safely cast a QGraphicsItem into an
+ IndependentTextItem.
+ @return le type de QGraphicsItem
+ */
+ virtual int type() const { return Type; }
+ virtual void fromXml(const QDomElement &);
+ virtual QDomElement toXml(QDomDocument &) const;
+
+ protected:
+ virtual void mousePressEvent(QGraphicsSceneMouseEvent *);
+ virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *);
+ virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *);
+
+ private:
+ bool first_move_;
+ QPointF mouse_to_origin_movement_;
+};
+#endif
Modified: branches/devel/sources/qetgraphicsitem/qetgraphicsitem.cpp
===================================================================
--- branches/devel/sources/qetgraphicsitem/qetgraphicsitem.cpp 2013-11-06 18:44:39 UTC (rev 2595)
+++ branches/devel/sources/qetgraphicsitem/qetgraphicsitem.cpp 2013-11-07 09:18:03 UTC (rev 2596)
@@ -23,15 +23,17 @@
* @param diagram, diagram aka QGraphicsScene of the item
* @param parent, Parent Item
*/
-QetGraphicsItem::QetGraphicsItem(QetGraphicsItem *parent):
+QetGraphicsItem::QetGraphicsItem(QGraphicsItem *parent):
QGraphicsObject(parent),
- first_move_(false)
+ first_move_(true)
{
}
QetGraphicsItem::~QetGraphicsItem()
{}
+void QetGraphicsItem::editProperty(){}
+
/**
* @brief QetGraphicsItem::diagram
*return the diagram of this item
@@ -67,6 +69,37 @@
}
/**
+ Permet de tourner l'item a un angle donne de maniere absolue.
+ Un angle de 0 degres correspond a un image horizontal non retourne.
+ @param rotation Nouvel angle de rotation de ce image
+ @see applyRotation
+*/
+void QetGraphicsItem::setRotationAngle(const qreal &rotation_angle) {
+ qreal applied_rotation = QET::correctAngle(rotation_angle);
+ applyRotation(applied_rotation - rotation());
+}
+
+/**
+ Permet de tourner l'item de maniere relative.
+ L'angle added_rotation est ajoute a l'orientation actuelle du image.
+ @param added_rotation Angle a ajouter a la rotation actuelle
+ @see applyRotation
+*/
+void QetGraphicsItem::rotateBy(const qreal &added_rotation) {
+ qreal applied_added_rotation = QET::correctAngle(added_rotation);
+ applyRotation(applied_added_rotation);
+}
+
+/**
+ Effectue la rotation de l'item en lui même
+ Cette methode peut toutefois etre redefinie dans des classes filles
+ @param angle Angle de la rotation a effectuer
+*/
+void QetGraphicsItem::applyRotation(const qreal &angle) {
+ setRotation(QET::correctAngle(rotation() + angle));
+}
+
+/**
* @brief QetGraphicsItem::mousePressEvent
*handle the mouse click
* @param e
Modified: branches/devel/sources/qetgraphicsitem/qetgraphicsitem.h
===================================================================
--- branches/devel/sources/qetgraphicsitem/qetgraphicsitem.h 2013-11-06 18:44:39 UTC (rev 2595)
+++ branches/devel/sources/qetgraphicsitem/qetgraphicsitem.h 2013-11-07 09:18:03 UTC (rev 2596)
@@ -25,18 +25,18 @@
public:
//constructor destructor
- QetGraphicsItem(QetGraphicsItem *parent = 0);
- virtual ~QetGraphicsItem();
+ QetGraphicsItem(QGraphicsItem *parent = 0);
+ virtual ~QetGraphicsItem() = 0;
//abstarct methode
- virtual bool fromXml(const QDomElement &document) = 0;
- virtual QDomElement toXml(QDomDocument &document) const = 0;
- virtual void editProperty () = 0;
+ virtual void editProperty ();
//public methode
Diagram* diagram() const;
virtual void setPos(const QPointF &p);
virtual void setPos(qreal x, qreal y);
+ void setRotationAngle(const qreal &);
+ void rotateBy(const qreal &);
signals:
@@ -44,6 +44,7 @@
//protected method
protected:
+ void applyRotation(const qreal &);
virtual void mousePressEvent(QGraphicsSceneMouseEvent *e);
virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *e);
virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *e);
Modified: branches/devel/sources/terminal.cpp
===================================================================
--- branches/devel/sources/terminal.cpp 2013-11-06 18:44:39 UTC (rev 2595)
+++ branches/devel/sources/terminal.cpp 2013-11-07 09:18:03 UTC (rev 2596)
@@ -17,8 +17,8 @@
*/
#include "terminal.h"
#include "diagram.h"
-#include "element.h"
-#include "conductor.h"
+#include "qetgraphicsitem/element.h"
+#include "qetgraphicsitem/conductor.h"
#include "diagramcommands.h"
#include "qetapp.h"
--Ofro6XGXHTz--