diff --git a/conducer.cpp b/conducer.cpp index d2f280ec2..531aafde9 100644 --- a/conducer.cpp +++ b/conducer.cpp @@ -74,7 +74,7 @@ Conducer::~Conducer() { */ void Conducer::update(const QRectF &rect) { // utilise soit la fonction priv_modifieConducteur soit la fonction priv_calculeConducteur - void (Conducer::* fonction_update) (const QPointF &, Terminal::Orientation, const QPointF &, Terminal::Orientation); + void (Conducer::* fonction_update) (const QPointF &, QET::Orientation, const QPointF &, QET::Orientation); fonction_update = (nbSegments() && modified_path) ? &Conducer::priv_modifieConducer : &Conducer::priv_calculeConducer; // appelle la bonne fonction pour calculer l'aspect du conducteur @@ -147,7 +147,7 @@ void Conducer::segmentsToPath() { @param p2 Coordonnees du point d'amarrage de la borne 2 @param o2 Orientation de la borne 2 */ -void Conducer::priv_modifieConducer(const QPointF &p1, Terminal::Orientation, const QPointF &p2, Terminal::Orientation) { +void Conducer::priv_modifieConducer(const QPointF &p1, QET::Orientation, const QPointF &p2, QET::Orientation) { Q_ASSERT_X(nbSegments() > 1, "priv_modifieConducer", "pas de points a modifier"); // recupere les dernieres coordonnees connues des bornes @@ -194,9 +194,9 @@ void Conducer::priv_modifieConducer(const QPointF &p1, Terminal::Orientation, co @param p2 Coordonnees du point d'amarrage de la borne 2 @param o2 Orientation de la borne 2 */ -void Conducer::priv_calculeConducer(const QPointF &p1, Terminal::Orientation o1, const QPointF &p2, Terminal::Orientation o2) { +void Conducer::priv_calculeConducer(const QPointF &p1, QET::Orientation o1, const QPointF &p2, QET::Orientation o2) { QPointF sp1, sp2, depart, newp1, newp2, arrivee, depart0, arrivee0; - Terminal::Orientation ori_depart, ori_arrivee; + QET::Orientation ori_depart, ori_arrivee; // s'assure qu'il n'y a ni points QList points; @@ -236,34 +236,34 @@ void Conducer::priv_calculeConducer(const QPointF &p1, Terminal::Orientation o1, // commence le vrai trajet if (depart.y() < arrivee.y()) { // trajet descendant - if ((ori_depart == Terminal::Nord && (ori_arrivee == Terminal::Sud || ori_arrivee == Terminal::Ouest)) || (ori_depart == Terminal::Est && ori_arrivee == Terminal::Ouest)) { + if ((ori_depart == QET::North && (ori_arrivee == QET::South || ori_arrivee == QET::West)) || (ori_depart == QET::East && ori_arrivee == QET::West)) { // cas « 3 » qreal ligne_inter_x = (depart.x() + arrivee.x()) / 2.0; points << QPointF(ligne_inter_x, depart.y()); points << QPointF(ligne_inter_x, arrivee.y()); - } else if ((ori_depart == Terminal::Sud && (ori_arrivee == Terminal::Nord || ori_arrivee == Terminal::Est)) || (ori_depart == Terminal::Ouest && ori_arrivee == Terminal::Est)) { + } else if ((ori_depart == QET::South && (ori_arrivee == QET::North || ori_arrivee == QET::East)) || (ori_depart == QET::West && ori_arrivee == QET::East)) { // cas « 4 » qreal ligne_inter_y = (depart.y() + arrivee.y()) / 2.0; points << QPointF(depart.x(), ligne_inter_y); points << QPointF(arrivee.x(), ligne_inter_y); - } else if ((ori_depart == Terminal::Nord || ori_depart == Terminal::Est) && (ori_arrivee == Terminal::Nord || ori_arrivee == Terminal::Est)) { + } 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 == Terminal::Ouest && (ori_arrivee == Terminal::Est || ori_arrivee == Terminal::Sud)) || (ori_depart == Terminal::Nord && ori_arrivee == Terminal::Sud)) { + if ((ori_depart == QET::West && (ori_arrivee == QET::East || ori_arrivee == QET::South)) || (ori_depart == QET::North && ori_arrivee == QET::South)) { // cas « 3 » qreal ligne_inter_y = (depart.y() + arrivee.y()) / 2.0; points << QPointF(depart.x(), ligne_inter_y); points << QPointF(arrivee.x(), ligne_inter_y); - } else if ((ori_depart == Terminal::Est && (ori_arrivee == Terminal::Ouest || ori_arrivee == Terminal::Nord)) || (ori_depart == Terminal::Sud && ori_arrivee == Terminal::Nord)) { + } else if ((ori_depart == QET::East && (ori_arrivee == QET::West || ori_arrivee == QET::North)) || (ori_depart == QET::South && ori_arrivee == QET::North)) { // cas « 4 » qreal ligne_inter_x = (depart.x() + arrivee.x()) / 2.0; points << QPointF(ligne_inter_x, depart.y()); points << QPointF(ligne_inter_x, arrivee.y()); - } else if ((ori_depart == Terminal::Ouest || ori_depart == Terminal::Nord) && (ori_arrivee == Terminal::Ouest || ori_arrivee == Terminal::Nord)) { + } 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 » @@ -287,19 +287,19 @@ void Conducer::priv_calculeConducer(const QPointF &p1, Terminal::Orientation o1, @param ext_size la taille de la prolongation @return le point correspondant a la borne apres prolongation */ -QPointF Conducer::extendTerminal(const QPointF &terminal, Terminal::Orientation terminal_orientation, qreal ext_size) { +QPointF Conducer::extendTerminal(const QPointF &terminal, QET::Orientation terminal_orientation, qreal ext_size) { QPointF extended_terminal; switch(terminal_orientation) { - case Terminal::Nord: + case QET::North: extended_terminal = QPointF(terminal.x(), terminal.y() - ext_size); break; - case Terminal::Est: + case QET::East: extended_terminal = QPointF(terminal.x() + ext_size, terminal.y()); break; - case Terminal::Sud: + case QET::South: extended_terminal = QPointF(terminal.x(), terminal.y() + ext_size); break; - case Terminal::Ouest: + case QET::West: extended_terminal = QPointF(terminal.x() - ext_size, terminal.y()); break; default: extended_terminal = terminal; @@ -356,36 +356,6 @@ void Conducer::paint(QPainter *qp, const QStyleOptionGraphicsItem */*qsogi*/, QW qp -> restore(); } -/** - Indique si deux orientations de Borne sont sur le meme axe (Vertical / Horizontal). - @param a La premiere orientation de Borne - @param b La seconde orientation de Borne - @return Un booleen a true si les deux orientations de bornes sont sur le meme axe -*/ -bool Conducer::surLeMemeAxe(Terminal::Orientation a, Terminal::Orientation b) { - if ((a == Terminal::Nord || a == Terminal::Sud) && (b == Terminal::Nord || b == Terminal::Sud)) return(true); - else if ((a == Terminal::Est || a == Terminal::Ouest) && (b == Terminal::Est || b == Terminal::Ouest)) return(true); - else return(false); -} - -/** - Indique si une orientation de borne est horizontale (Est / Ouest). - @param a L'orientation de borne - @return True si l'orientation de borne est horizontale, false sinon -*/ -bool Conducer::estHorizontale(Terminal::Orientation a) { - return(a == Terminal::Est || a == Terminal::Ouest); -} - -/** - Indique si une orientation de borne est verticale (Nord / Sud). - @param a L'orientation de borne - @return True si l'orientation de borne est verticale, false sinon -*/ -bool Conducer::estVerticale(Terminal::Orientation a) { - return(a == Terminal::Nord || a == Terminal::Sud); -} - /** Methode de preparation a la destruction du conducteur ; le conducteur se detache de ses deux bornes */ diff --git a/conducer.h b/conducer.h index 85981228a..d321bb32b 100644 --- a/conducer.h +++ b/conducer.h @@ -71,17 +71,14 @@ class Conducer : public QGraphicsPathItem { private: void segmentsToPath(); void updatePoints(); - void priv_calculeConducer(const QPointF &, Terminal::Orientation, const QPointF &, Terminal::Orientation); - void priv_modifieConducer(const QPointF &, Terminal::Orientation, const QPointF &, Terminal::Orientation); + void priv_calculeConducer(const QPointF &, QET::Orientation, const QPointF &, QET::Orientation); + void priv_modifieConducer(const QPointF &, QET::Orientation, const QPointF &, QET::Orientation); int nbSegments() const; QList segmentsToPoints() const; void pointsToSegments(QList); bool hasClickedOn(QPointF, QPointF) const; void calculateTextItemPosition(); - static QPointF extendTerminal(const QPointF &, Terminal::Orientation, qreal = 12.0); - static bool surLeMemeAxe(Terminal::Orientation, Terminal::Orientation); - static bool estHorizontale(Terminal::Orientation a); - static bool estVerticale(Terminal::Orientation a); + static QPointF extendTerminal(const QPointF &, QET::Orientation, qreal = 12.0); static qreal conducer_bound(qreal tobound, qreal bound1, qreal bound2); static qreal conducer_bound(qreal tobound, qreal bound, bool positive); }; diff --git a/customelement.cpp b/customelement.cpp index 614ce098c..db0f99717 100644 --- a/customelement.cpp +++ b/customelement.cpp @@ -1,7 +1,6 @@ #include "customelement.h" #include "elementtextitem.h" #include "diagram.h" - /** Constructeur de la classe ElementPerso. Permet d'instancier un element utilisable comme un element fixe a la difference que l'element perso lit @@ -63,10 +62,10 @@ CustomElement::CustomElement(QString &nom_fichier, QGraphicsItem *qgi, Diagram * // ces attributs doivent etre presents et valides int w, h, hot_x, hot_y; if ( - !attributeIsAnInteger(racine, QString("width"), &w) ||\ - !attributeIsAnInteger(racine, QString("height"), &h) ||\ - !attributeIsAnInteger(racine, QString("hotspot_x"), &hot_x) ||\ - !attributeIsAnInteger(racine, QString("hotspot_y"), &hot_y) ||\ + !QET::attributeIsAnInteger(racine, QString("width"), &w) ||\ + !QET::attributeIsAnInteger(racine, QString("height"), &h) ||\ + !QET::attributeIsAnInteger(racine, QString("hotspot_x"), &hot_x) ||\ + !QET::attributeIsAnInteger(racine, QString("hotspot_y"), &hot_y) ||\ !validOrientationAttribute(racine) ) { if (etat != NULL) *etat = 5; @@ -78,6 +77,7 @@ CustomElement::CustomElement(QString &nom_fichier, QGraphicsItem *qgi, Diagram * setSize(w, h); setHotspot(QPoint(hot_x, hot_y)); setConnexionsInternesAcceptees(racine.attribute("ci") == "true"); + // la definition est supposee avoir des enfants if (racine.firstChild().isNull()) { if (etat != NULL) *etat = 6; @@ -194,12 +194,20 @@ bool CustomElement::parseElement(QDomElement &e, QPainter &qp, Diagram *s) { @return true si l'analyse reussit, false sinon */ bool CustomElement::parseLine(QDomElement &e, QPainter &qp) { + //qDebug() << "parseLine sur " << (void *)(&dessin); +// qDebug() << names.name() << (void *)(&dessin); +// qp.end(); +// PartLine t; +// t.fromXml(e); +// t.renderToCustomElement(*this); +// qp.begin(&dessin); + //return(true); // verifie la presence et la validite des attributs obligatoires double x1, y1, x2, y2; - if (!attributeIsAReal(e, QString("x1"), &x1)) return(false); - if (!attributeIsAReal(e, QString("y1"), &y1)) return(false); - if (!attributeIsAReal(e, QString("x2"), &x2)) return(false); - if (!attributeIsAReal(e, QString("y2"), &y2)) return(false); + 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); qp.save(); setPainterStyle(e, qp); qp.drawLine(QLineF(x1, y1, x2, y2)); @@ -223,9 +231,9 @@ bool CustomElement::parseLine(QDomElement &e, QPainter &qp) { bool CustomElement::parseCircle(QDomElement &e, QPainter &qp) { // verifie la presence des attributs obligatoires double cercle_x, cercle_y, cercle_r; - if (!attributeIsAReal(e, QString("x"), &cercle_x)) return(false); - if (!attributeIsAReal(e, QString("y"), &cercle_y)) return(false); - if (!attributeIsAReal(e, QString("diameter"), &cercle_r)) return(false); + 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)); @@ -250,10 +258,10 @@ bool CustomElement::parseCircle(QDomElement &e, QPainter &qp) { bool CustomElement::parseEllipse(QDomElement &e, QPainter &qp) { // verifie la presence des attributs obligatoires double ellipse_x, ellipse_y, ellipse_l, ellipse_h; - if (!attributeIsAReal(e, QString("x"), &ellipse_x)) return(false); - if (!attributeIsAReal(e, QString("y"), &ellipse_y)) return(false); - if (!attributeIsAReal(e, QString("width"), &ellipse_l)) return(false); - if (!attributeIsAReal(e, QString("height"), &ellipse_h)) return(false); + 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)); @@ -278,12 +286,12 @@ bool CustomElement::parseEllipse(QDomElement &e, QPainter &qp) { bool CustomElement::parseArc(QDomElement &e, QPainter &qp) { // verifie la presence des attributs obligatoires double arc_x, arc_y, arc_l, arc_h, arc_s, arc_a; - if (!attributeIsAReal(e, QString("x"), &arc_x)) return(false); - if (!attributeIsAReal(e, QString("y"), &arc_y)) return(false); - if (!attributeIsAReal(e, QString("width"), &arc_l)) return(false); - if (!attributeIsAReal(e, QString("height"), &arc_h)) return(false); - if (!attributeIsAReal(e, QString("start"), &arc_s)) return(false); - if (!attributeIsAReal(e, QString("angle"), &arc_a)) return(false); + 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); @@ -306,7 +314,7 @@ bool CustomElement::parseArc(QDomElement &e, QPainter &qp) { bool CustomElement::parsePolygon(QDomElement &e, QPainter &qp) { int i = 1; while(true) { - if (attributeIsAReal(e, QString("x%1").arg(i)) && attributeIsAReal(e, QString("y%1").arg(i))) ++ i; + 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); @@ -338,9 +346,9 @@ bool CustomElement::parseText(QDomElement &e, QPainter &qp) { qreal pos_x, pos_y; int size; if ( - !attributeIsAReal(e, "x", &pos_x) ||\ - !attributeIsAReal(e, "y", &pos_y) ||\ - !attributeIsAnInteger(e, "size", &size) ||\ + !QET::attributeIsAReal(e, "x", &pos_x) ||\ + !QET::attributeIsAReal(e, "y", &pos_y) ||\ + !QET::attributeIsAnInteger(e, "size", &size) ||\ !e.hasAttribute("text") ) return(false); @@ -368,9 +376,9 @@ bool CustomElement::parseInput(QDomElement &e, Diagram *s) { qreal pos_x, pos_y; int size; if ( - !attributeIsAReal(e, "x", &pos_x) ||\ - !attributeIsAReal(e, "y", &pos_y) ||\ - !attributeIsAnInteger(e, "size", &size) + !QET::attributeIsAReal(e, "x", &pos_x) ||\ + !QET::attributeIsAReal(e, "y", &pos_y) ||\ + !QET::attributeIsAnInteger(e, "size", &size) ) return(false); ElementTextItem *eti = new ElementTextItem(e.attribute("text"), this, s); @@ -394,14 +402,14 @@ bool CustomElement::parseInput(QDomElement &e, Diagram *s) { bool CustomElement::parseTerminal(QDomElement &e, Diagram *s) { // verifie la presence et la validite des attributs obligatoires double terminalx, terminaly; - Terminal::Orientation terminalo; - if (!attributeIsAReal(e, QString("x"), &terminalx)) return(false); - if (!attributeIsAReal(e, QString("y"), &terminaly)) return(false); + QET::Orientation terminalo; + if (!QET::attributeIsAReal(e, QString("x"), &terminalx)) return(false); + if (!QET::attributeIsAReal(e, QString("y"), &terminaly)) return(false); if (!e.hasAttribute("orientation")) return(false); - if (e.attribute("orientation") == "n") terminalo = Terminal::Nord; - else if (e.attribute("orientation") == "s") terminalo = Terminal::Sud; - else if (e.attribute("orientation") == "e") terminalo = Terminal::Est; - else if (e.attribute("orientation") == "w") terminalo = Terminal::Ouest; + 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(false); new Terminal(terminalx, terminaly, terminalo, this, s); ++ nb_terminals; @@ -419,44 +427,6 @@ void CustomElement::setQPainterAntiAliasing(QPainter &qp, bool aa) { qp.setRenderHint(QPainter::SmoothPixmapTransform, aa); } -/** - Permet de savoir si l'attribut nom_attribut d'un element XML e est bien un - entier. Si oui, sa valeur est copiee dans entier. - @param e Element XML - @param nom_attribut Nom de l'attribut a analyser - @param entier Pointeur facultatif vers un entier - @return true si l'attribut est bien un entier, false sinon -*/ -bool CustomElement::attributeIsAnInteger(QDomElement &e, QString nom_attribut, int *entier) { - // verifie la presence de l'attribut - if (!e.hasAttribute(nom_attribut)) return(false); - // verifie la validite de l'attribut - bool ok; - int tmp = e.attribute(nom_attribut).toInt(&ok); - if (!ok) return(false); - if (entier != NULL) *entier = tmp; - return(true); -} - -/** - Permet de savoir si l'attribut nom_attribut d'un element XML e est bien un - reel. Si oui, sa valeur est copiee dans reel. - @param e Element XML - @param nom_attribut Nom de l'attribut a analyser - @param reel Pointeur facultatif vers un double - @return true si l'attribut est bien un reel, false sinon -*/ -bool CustomElement::attributeIsAReal(QDomElement &e, QString nom_attribut, double *reel) { - // verifie la presence de l'attribut - if (!e.hasAttribute(nom_attribut)) return(false); - // verifie la validite de l'attribut - bool ok; - qreal tmp = e.attribute(nom_attribut).toDouble(&ok); - if (!ok) return(false); - if (reel != NULL) *reel = tmp; - return(true); -} - /** Verifie si l'attribut "orientation" de l'element XML e correspond bien a la syntaxe decrivant les orientations possibles pour un element. @@ -477,30 +447,7 @@ bool CustomElement::attributeIsAReal(QDomElement &e, QString nom_attribut, doubl @return true si l'attribut "orientation" est valide, false sinon */ bool CustomElement::validOrientationAttribute(QDomElement &e) { - // verifie la presence de l'attribut orientation - if (!e.hasAttribute("orientation")) return(false); - QString t = e.attribute("orientation"); - // verification syntaxique : 4 lettres, un d, que des y ou des n pour le reste - if (t.length() != 4) return(false); - int d_pos = -1; - for (int i = 0 ; i < 4 ; ++ i) { - QChar c = t.at(i); - if (c != 'd' && c != 'y' && c != 'n') return(false); - if (c == 'd') { - if (d_pos == -1) d_pos = i; - else return(false); - } - } - if (d_pos == -1) return(false); - - // orientation : 4 lettres = nord/est/sud/ouest avec d = default, y = yes et n = no - ori_n = (t.at(0) == 'd' || t.at(0) == 'y'); - ori_e = (t.at(1) == 'd' || t.at(1) == 'y'); - ori_s = (t.at(2) == 'd' || t.at(2) == 'y'); - ori_w = (t.at(3) == 'd' || t.at(3) == 'y'); - ori_d = (Terminal::Orientation)d_pos; - ori = ori_d; - return(true); + return(ori.fromString(e.attribute("orientation"))); } /** diff --git a/customelement.h b/customelement.h index be1fd2163..789c7eed5 100644 --- a/customelement.h +++ b/customelement.h @@ -3,6 +3,9 @@ #include "fixedelement.h" #include #include "nameslist.h" +class CustomElementPart; +// #include "customelementpart.h" +// #include "cep_line.h" /** Cette classe represente un element electrique. Elle est utilisable comme un element fixe. La difference est que l'element perso lit @@ -15,6 +18,8 @@ class CustomElement : public FixedElement { CustomElement(QString &, QGraphicsItem * = 0, Diagram * = 0, int * = NULL); virtual ~CustomElement(); + friend class CustomElementPart; + private: CustomElement(const CustomElement &); @@ -47,8 +52,6 @@ class CustomElement : public FixedElement { bool parseInput(QDomElement &, Diagram *); bool parseTerminal(QDomElement &, Diagram *); void setQPainterAntiAliasing(QPainter &, bool); - bool attributeIsAnInteger(QDomElement &, QString, int * = NULL); - bool attributeIsAReal(QDomElement &, QString, double * = NULL); bool validOrientationAttribute(QDomElement &); void setPainterStyle(QDomElement &, QPainter &); }; diff --git a/diagramview.cpp b/diagramview.cpp index 695a621d8..732aafd72 100644 --- a/diagramview.cpp +++ b/diagramview.cpp @@ -153,7 +153,7 @@ void DiagramView::pivoter() { if (scene -> selectedItems().isEmpty()) return; foreach (QGraphicsItem *item, scene -> selectedItems()) { if (Element *elt = qgraphicsitem_cast(item)) { - elt -> setOrientation(elt -> nextAcceptableOrientation()); + elt -> setOrientation(elt -> orientation().next()); elt -> update(); } } diff --git a/editor/circleeditor.cpp b/editor/circleeditor.cpp new file mode 100644 index 000000000..fc5d0045b --- /dev/null +++ b/editor/circleeditor.cpp @@ -0,0 +1,56 @@ +#include "circleeditor.h" +#include "partcircle.h" + +CircleEditor::CircleEditor(PartCircle *circle, QWidget *parent) : QWidget(parent) { + + part = circle; + + x = new QLineEdit(); + y = new QLineEdit(); + r = new QLineEdit(); + +// QDoubleValidator *format = new QDoubleValidator(-1000.0, -1000.0, 4, this); +// x -> setValidator(new QDoubleValidator(-1000.0, 1000.0, 4, this)); +// y -> setValidator(new QDoubleValidator(-1000.0, 1000.0, 4, this)); +// h -> setValidator(new QDoubleValidator(0.0, 1000.0, 4, this)); + + + QGridLayout *grid = new QGridLayout(this); + grid -> addWidget(new QLabel(tr("Centre : ")), 0, 0); + grid -> addWidget(new QLabel("x"), 1, 0); + grid -> addWidget(x, 1, 1); + grid -> addWidget(new QLabel("y"), 1, 2); + grid -> addWidget(y, 1, 3); + grid -> addWidget(new QLabel(tr("Diam\350tre : ")), 2, 0); + grid -> addWidget(r, 2, 1); + + updateForm(); + + connect(x, SIGNAL(editingFinished()), this, SLOT(updateCircle())); + connect(y, SIGNAL(editingFinished()), this, SLOT(updateCircle())); + connect(r, SIGNAL(editingFinished()), this, SLOT(updateCircle())); +} + +CircleEditor::~CircleEditor() { + qDebug() << "~CircleEditor()"; +} + +void CircleEditor::updateCircle() { + qreal _x = x -> text().toDouble(); + qreal _y = y -> text().toDouble(); + qreal _d = r -> text().toDouble(); + part -> setRect( + QRectF( + part -> mapFromScene(QPointF(_x - _d / 2.0, _y - _d / 2.0)), + QSizeF(_d, _d) + ) + ); +} + +void CircleEditor::updateForm() { + qreal _d = part -> rect().width(); + QPointF top_left(part -> sceneTopLeft()); + x -> setText(QString("%1").arg(top_left.x() + _d / 2.0)); + y -> setText(QString("%1").arg(top_left.y() + _d / 2.0)); + r -> setText(QString("%1").arg(_d)); +} diff --git a/editor/circleeditor.h b/editor/circleeditor.h new file mode 100644 index 000000000..12a795361 --- /dev/null +++ b/editor/circleeditor.h @@ -0,0 +1,29 @@ +#ifndef CIRCLE_EDITOR_H +#define CIRCLE_EDITOR_H +#include +class PartCircle; +/** + Cette classe represente un editeur de cercle. + Elle permet d'editer a travers une interface graphique les + proprietes d'une cercle composant le dessin d'un element. +*/ +class CircleEditor : public QWidget { + Q_OBJECT + // Constructeurs, destructeur + public: + CircleEditor(PartCircle *, QWidget * = 0); + virtual ~CircleEditor(); + private: + CircleEditor(const CircleEditor &); + + // attributs + private: + PartCircle *part; + QLineEdit *x, *y, *r; + + // methodes + public slots: + void updateCircle(); + void updateForm(); +}; +#endif diff --git a/editor/customelementeditor.cpp b/editor/customelementeditor.cpp new file mode 100644 index 000000000..19fc50beb --- /dev/null +++ b/editor/customelementeditor.cpp @@ -0,0 +1,447 @@ +#include "customelementeditor.h" +#include "editorscene.h" +#include "customelementpart.h" +#include "newelementwizard.h" +#include "qetapp.h" + +CustomElementEditor::CustomElementEditor(QWidget *parent) : + QMainWindow(parent), + read_only(false), + min_title(tr("QElectroTech - \311diteur d'\351l\351ment")), + _filename(QString()) +{ + setMinimumWidth(700); + setMinimumHeight(450); + setWindowTitle(min_title); + setWindowIcon(QIcon(":/ico/qet.png")); + + setupInterface(); + setupActions(); + setupMenus(); +} + +CustomElementEditor::~CustomElementEditor() { + qDebug() << "~CustomElementEditor()"; + // recupere le layout +// QLayout *layout = tools_dock -> widget() -> layout(); +// +// // enleve les widgets deja presents +// QLayoutItem *qli; +// while ((qli = layout -> takeAt(0)) != 0) { +// if (qli -> widget()) { +// layout -> removeWidget(qli -> widget()); +// qli -> widget() -> setParent(0); +// } +// } + + +} + +void CustomElementEditor::setupActions() { + new_element = new QAction(QIcon(":/ico/new.png"), tr("&Nouveau"), this); + open = new QAction(QIcon(":/ico/open.png"), tr("&Ouvrir"), this); + save = new QAction(QIcon(":/ico/save.png"), tr("&Enregistrer"), this); + save_as = new QAction(QIcon(":/ico/saveas.png"), tr("Enregistrer sous"), this); + quit = new QAction(QIcon(":/ico/exit.png"), tr("&Quitter"), this); + selectall = new QAction( tr("Tout s\351lectionner"), this); + deselectall = new QAction( tr("D\351s\351lectionner tout"), this); + inv_select = new QAction( tr("Inverser la s\351lection"), this); + edit_delete = new QAction(QIcon(":/ico/delete.png"), tr("&Supprimer"), this); + edit_size = new QAction( tr("Modifier la taille"), this); + edit_hotspot = new QAction( tr("Modifier le point de saisie"), this); + edit_names = new QAction( tr("\311diter les noms"), this); + edit_ori = new QAction(QIcon(":/ico/orientations.png"), tr("\311diter les orientations"), this); + move = new QAction(QIcon(":/ico/select.png"), tr("D\351placer un objet"), this); + add_line = new QAction(QIcon(":/ico/line.png"), tr("Ajouter une ligne"), this); + add_ellipse = new QAction(QIcon(":/ico/ellipse.png"), tr("Ajouter une ellipse"), this); + add_circle = new QAction(QIcon(":/ico/circle.png"), tr("Ajouter un cercle"), this); + add_polygon = new QAction(QIcon(":/ico/polygon.png"), tr("Ajouter un polygone"), this); + add_text = new QAction(QIcon(":/ico/text.png"), tr("Ajouter du texte"), this); + add_arc = new QAction(QIcon(":/ico/arc.png"), tr("Ajouter un arc de cercle"), this); + add_terminal = new QAction(QIcon(":/ico/terminal.png"), tr("Ajouter une borne"), this); + add_textfield = new QAction(QIcon(":/ico/textfield.png"), tr("Ajouter un champ de texte"), this); + + edit_delete -> setEnabled(false); + edit_size -> setEnabled(false); + edit_hotspot -> setEnabled(false); + + selectall -> setShortcut(QKeySequence::SelectAll); + deselectall -> setShortcut(QKeySequence(tr("Ctrl+Shift+A"))); + inv_select -> setShortcut(QKeySequence(tr("Ctrl+I"))); + edit_delete -> setShortcut(QKeySequence(tr("Ctrl+Suppr"))); + + connect(new_element, SIGNAL(triggered()), this, SLOT(slot_new())); + connect(open, SIGNAL(triggered()), this, SLOT(slot_open())); + connect(save, SIGNAL(triggered()), this, SLOT(slot_save())); + connect(save_as, SIGNAL(triggered()), this, SLOT(slot_saveAs())); + connect(quit, SIGNAL(triggered()), this, SLOT(slot_quit())); + connect(selectall, SIGNAL(triggered()), ce_scene, SLOT(slot_selectAll())); + connect(deselectall, SIGNAL(triggered()), ce_scene, SLOT(slot_deselectAll())); + connect(inv_select, SIGNAL(triggered()), ce_scene, SLOT(slot_invertSelection())); + connect(edit_delete, SIGNAL(triggered()), ce_scene, SLOT(slot_delete())); + connect(edit_size, SIGNAL(triggered()), ce_scene, SLOT(slot_editSize())); + connect(edit_hotspot, SIGNAL(triggered()), ce_scene, SLOT(slot_editHotSpot())); + connect(edit_names, SIGNAL(triggered()), ce_scene, SLOT(slot_editNames())); + connect(edit_ori, SIGNAL(triggered()), ce_scene, SLOT(slot_editOrientations())); + connect(move, SIGNAL(triggered()), ce_scene, SLOT(slot_move())); + connect(add_line, SIGNAL(triggered()), ce_scene, SLOT(slot_addLine())); + connect(add_ellipse, SIGNAL(triggered()), ce_scene, SLOT(slot_addEllipse())); + connect(add_circle, SIGNAL(triggered()), ce_scene, SLOT(slot_addCircle())); + connect(add_polygon, SIGNAL(triggered()), ce_scene, SLOT(slot_addPolygon())); + connect(add_text, SIGNAL(triggered()), ce_scene, SLOT(slot_addText())); + connect(add_arc, SIGNAL(triggered()), ce_scene, SLOT(slot_addArc())); + connect(add_terminal, SIGNAL(triggered()), ce_scene, SLOT(slot_addTerminal())); + connect(add_textfield, SIGNAL(triggered()), ce_scene, SLOT(slot_addTextField())); + + connect(move, SIGNAL(triggered()), this, SLOT(slot_setRubberBandToView())); + connect(add_line, SIGNAL(triggered()), this, SLOT(slot_setNoDragToView())); + connect(add_ellipse, SIGNAL(triggered()), this, SLOT(slot_setNoDragToView())); + connect(add_circle, SIGNAL(triggered()), this, SLOT(slot_setNoDragToView())); + connect(add_polygon, SIGNAL(triggered()), this, SLOT(slot_setNoDragToView())); + connect(add_text, SIGNAL(triggered()), this, SLOT(slot_setNoDragToView())); + connect(add_arc, SIGNAL(triggered()), this, SLOT(slot_setNoDragToView())); + connect(add_terminal, SIGNAL(triggered()), this, SLOT(slot_setNoDragToView())); + connect(add_textfield, SIGNAL(triggered()), this, SLOT(slot_setNoDragToView())); + + connect(ce_scene, SIGNAL(needNormalMode()), this, SLOT(slot_setNormalMode())); + + move -> setCheckable(true); + add_line -> setCheckable(true); + add_ellipse -> setCheckable(true); + add_circle -> setCheckable(true); + add_polygon -> setCheckable(true); + add_text -> setCheckable(true); + add_arc -> setCheckable(true); + add_terminal -> setCheckable(true); + add_textfield -> setCheckable(true); + + parts = new QActionGroup(this); + parts -> addAction(move); + parts -> addAction(add_line); + parts -> addAction(add_ellipse); + parts -> addAction(add_circle); + parts -> addAction(add_polygon); + parts -> addAction(add_text); + parts -> addAction(add_arc); + parts -> addAction(add_textfield); + parts -> addAction(add_terminal); + parts -> setExclusive(true); + + parts_toolbar = new QToolBar(tr("Parties"), this); + foreach (QAction *action, parts -> actions()) parts_toolbar -> addAction(action); + move -> setChecked(true); + parts_toolbar -> setAllowedAreas(Qt::LeftToolBarArea | Qt::RightToolBarArea); + + QAction *xml_preview = new QAction(QIcon(":/ico/info.png"), tr("XML"), this); + connect(xml_preview, SIGNAL(triggered()), this, SLOT(xmlPreview())); + parts_toolbar -> addAction(xml_preview); + + addToolBar(Qt::LeftToolBarArea, parts_toolbar); + + connect(ce_scene, SIGNAL(selectionChanged()), this, SLOT(slot_updateInformations())); + connect(ce_scene, SIGNAL(selectionChanged()), this, SLOT(slot_updateMenus())); +} + +void CustomElementEditor::setupMenus() { + file_menu = new QMenu(tr("Fichier")); + edit_menu = new QMenu(tr("\311dition")); + display_menu = new QMenu(tr("Affichage")); + tools_menu = new QMenu(tr("Outils")); + help_menu = new QMenu(tr("Aide")); + + file_menu -> setTearOffEnabled(true); + edit_menu -> setTearOffEnabled(true); + display_menu -> setTearOffEnabled(true); + tools_menu -> setTearOffEnabled(true); + help_menu -> setTearOffEnabled(true); + + file_menu -> addAction(new_element); + file_menu -> addAction(open); + file_menu -> addAction(save); + file_menu -> addAction(save_as); + file_menu -> addSeparator(); + file_menu -> addAction(quit); + + edit_menu -> addAction(selectall); + edit_menu -> addAction(deselectall); + edit_menu -> addAction(inv_select); + edit_menu -> addSeparator(); + edit_menu -> addAction(edit_delete); + edit_menu -> addSeparator(); + edit_menu -> addAction(edit_names); + edit_menu -> addAction(edit_size); + edit_menu -> addAction(edit_hotspot); + edit_menu -> addAction(edit_ori); + + menuBar() -> addMenu(file_menu); + menuBar() -> addMenu(edit_menu); + menuBar() -> addMenu(display_menu); + menuBar() -> addMenu(tools_menu); + menuBar() -> addMenu(help_menu); +} + +void CustomElementEditor::slot_updateMenus() { + edit_delete -> setEnabled(!ce_scene -> selectedItems().isEmpty()); +} + +void CustomElementEditor::setupInterface() { + // editeur + ce_scene = new EditorScene(this); + ce_scene -> slot_move(); + ce_view = new QGraphicsView(ce_scene, this); + ce_view -> setInteractive(true); + ce_view -> setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); + //ce_view -> setTransformationAnchor(QGraphicsView::AnchorUnderMouse); + ce_view -> setResizeAnchor(QGraphicsView::AnchorUnderMouse); + //ce_view -> setSceneRect(QRectF(0.0, 0.0, 50.0, 200.0)); + ce_view -> scale(4.0, 4.0); + slot_setRubberBandToView(); + setCentralWidget(ce_view); + + // widget par defaut dans le QDockWidget + default_informations = new QLabel(); + + // panel sur le cote + tools_dock = new QDockWidget(tr("Informations"), this); + tools_dock -> setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); + tools_dock -> setFeatures(QDockWidget::AllDockWidgetFeatures); + tools_dock -> setMinimumWidth(285); + addDockWidget(Qt::RightDockWidgetArea, tools_dock); + QWidget *info_widget = new QWidget(); + info_widget -> setLayout(new QVBoxLayout(info_widget)); + tools_dock -> setWidget(info_widget); + slot_updateInformations(); + + // barre d'etat + statusBar() -> showMessage(tr("\311diteur d'\351l\351ments")); +} + +void CustomElementEditor::slot_setRubberBandToView() { + ce_view -> setDragMode(QGraphicsView::RubberBandDrag); +} + +void CustomElementEditor::slot_setNoDragToView() { + ce_view -> setDragMode(QGraphicsView::NoDrag); +} + +void CustomElementEditor::slot_setNormalMode() { + if (!move -> isChecked()) move -> setChecked(true); + ce_view -> setDragMode(QGraphicsView::RubberBandDrag); + ce_scene -> slot_move(); +} + +void CustomElementEditor::slot_updateInformations() { + QList selected_qgis = ce_scene -> selectedItems(); + QList selected_parts; + foreach(QGraphicsItem *qgi, selected_qgis) { + if (CustomElementPart *cep = dynamic_cast(qgi)) { + selected_parts.append(cep); + } + } + + // recupere le layout + QLayout *layout = tools_dock -> widget() -> layout(); + + // enleve les widgets deja presents + QLayoutItem *qli; + while ((qli = layout -> takeAt(0)) != 0) { + if (qli -> widget()) { + layout -> removeWidget(qli -> widget()); + qli -> widget() -> setParent(0); + } + } + if (selected_parts.size() == 1) { + // recupere le premier CustomElementPart et en ajoute le widget d'edition + layout -> addWidget(selected_parts.first() -> elementInformations()); + } else { + default_informations -> setText( + selected_parts.size() ? + QString("%1").arg(selected_parts.size()) + tr(" parties s\351lectionn\351es.") : + tr("Aucune partie s\351lectionn\351e.") + ); + layout -> addWidget(default_informations); + } +} + +void CustomElementEditor::xmlPreview() { + QMessageBox::information( + this, + "Export XML", + ce_scene -> toXml().toString(4) + ); +} + +void CustomElementEditor::fromFile(const QString &filepath) { + bool state = true; + QString error_message; + + // le fichier doit exister + QFileInfo infos_file(filepath); + if (!infos_file.exists() || !infos_file.isFile()) { + state = false; + error_message = tr("Le fichier ") + filepath + tr(" n'existe pas."); + } + + // le fichier doit etre lisible + QFile file(filepath); + if (state) { + if (!file.open(QIODevice::ReadOnly)) { + state = false; + error_message = tr("Impossible d'ouvrir le fichier ") + filepath + "."; + } + } + + // le fichier doit etre un document XML + QDomDocument document_xml; + if (state) { + if (!document_xml.setContent(&file)) { + state = false; + error_message = tr("Ce fichier n'est pas un document XML valide"); + } + file.close(); + } + + if (!state) { + QMessageBox::critical(this, tr("Erreur"), error_message); + return; + } + + // chargement de l'element + ce_scene -> fromXml(document_xml); + + // gestion de la lecture seule + if (!infos_file.isWritable()) { + QMessageBox::warning( + this, + tr("\311dition en lecture seule"), + tr("Vous n'avez pas les privil\350ges n\351cessaires pour modifier cet \351lement. Il sera donc ouvert en lecture seule.") + ); + setReadOnly(true); + } + + // memorise le fichier + _filename = filepath; + + // modifie le titre de la fenetre + QString new_title = min_title + " - " + ce_scene -> names().name(); + if (isReadOnly()) new_title += tr(" [lecture seule]"); + setWindowTitle(new_title); +} + +bool CustomElementEditor::toFile(const QString &fn) { + QFile file(fn); + if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { + QMessageBox::warning(this, tr("Erreur"), tr("Impossible d'ecrire dans ce fichier")); + return(false); + } + QTextStream out(&file); + out.setCodec("UTF-8"); + out << ce_scene -> toXml().toString(4); + file.close(); + return(true); +} + +/** + specifie si l'editeur d'element doit etre en mode lecture seule + @param ro true pour activer le mode lecture seule, false pour le desactiver +*/ +void CustomElementEditor::setReadOnly(bool ro) { + read_only = ro; + // active / desactive les actions + foreach (QAction *action, parts -> actions()) action -> setEnabled(!ro); + + // active / desactive les interactions avec la scene + ce_view -> setInteractive(!ro); + + // active / desactive l'edition de la taille, du hotspot, des noms et des orientations + edit_size -> setEnabled(!ro); + edit_hotspot -> setEnabled(!ro); + edit_names -> setEnabled(!ro); + edit_ori -> setEnabled(!ro); +} + +/** + @return true si l'editeur d'element est en mode lecture seule +*/ +bool CustomElementEditor::isReadOnly() const { + return(read_only); +} + +void CustomElementEditor::slot_new() { + NewElementWizard new_element_wizard; + new_element_wizard.exec(); +} + +void CustomElementEditor::slot_open() { + // demande un nom de fichier a ouvrir a l'utilisateur + QString user_filename = QFileDialog::getOpenFileName( + this, + tr("Ouvrir un fichier"), + QETApp::customElementsDir(), + tr("\311l\351ments QElectroTech (*.elmt);;Fichiers XML (*.xml);;Tous les fichiers (*)") + ); + if (user_filename == "") return; + CustomElementEditor *cee = new CustomElementEditor(); + cee -> fromFile(user_filename); + cee -> show(); +} + +bool CustomElementEditor::slot_save() { + // si on ne connait pas le nom du fichier en cours, enregistrer revient a enregistrer sous + if (_filename == QString()) return(slot_saveAs()); + // sinon on enregistre dans le nom de fichier connu + return(toFile(_filename)); +} + +bool CustomElementEditor::slot_saveAs() { + // demande un nom de fichier a l'utilisateur pour enregistrer l'element + QString fn = QFileDialog::getSaveFileName( + this, + tr("Enregistrer sous"), + QETApp::customElementsDir(), + tr("\311l\351ments QElectroTech (*.elmt)") + ); + // si aucun nom n'est entre, renvoie faux. + if (fn == "") return(false); + // si le nom ne se termine pas par l'extension .elmt, celle-ci est ajoutee + if (!fn.endsWith(".elmt", Qt::CaseInsensitive)) fn += ".elmt"; + // tente d'enregistrer le fichier + bool result_save = toFile(fn); + // si l'enregistrement reussit, le nom du fichier est conserve + if (result_save) setFileName(fn); + // retourne un booleen representatif de la reussite de l'enregistrement + return(result_save); +} + +void CustomElementEditor::slot_quit(QCloseEvent *event) { + if (close()) { + if (event != NULL) event -> accept(); + delete(this); + } else if (event != NULL) event -> ignore(); +} + +bool CustomElementEditor::close() { + // demande d'abord a l'utilisateur s'il veut enregistrer l'element en cours + QMessageBox::StandardButton answer = QMessageBox::question( + this, + tr("Enregistrer l'\351l\351ment en cours ?"), + tr("Voulez-vous enregistrer l'\351l\351ment ") + ce_scene -> names().name() + tr(" ?"), + QMessageBox::Yes|QMessageBox::No|QMessageBox::Cancel, + QMessageBox::Cancel + ); + bool result; + switch(answer) { + case QMessageBox::Cancel: result = false; break; // l'utilisateur annule : echec de la fermeture + case QMessageBox::Yes: result = slot_save(); break; // l'utilisateur dit oui : la reussite depend de l'enregistrement + default: result = true; // l'utilisateur dit non ou ferme le dialogue: c'est reussi + } + return(result); +} + +/** + Permet de quitter l'editeur lors de la fermeture de la fenetre principale + @param qce Le QCloseEvent correspondant a l'evenement de fermeture +*/ +void CustomElementEditor::closeEvent(QCloseEvent *qce) { + slot_quit(qce); +} diff --git a/editor/customelementeditor.h b/editor/customelementeditor.h new file mode 100644 index 000000000..30d871dd2 --- /dev/null +++ b/editor/customelementeditor.h @@ -0,0 +1,128 @@ +#ifndef CUSTOM_ELEMENT_EDITOR_H +#define CUSTOM_ELEMENT_EDITOR_H +#include +#include "editorscene.h" +#include "orientationset.h" +class CustomElementEditor : public QMainWindow { + Q_OBJECT + + // constructeur, destructeur + public: + CustomElementEditor(QWidget * = 0); + virtual ~CustomElementEditor(); + private: + CustomElementEditor(const CustomElementEditor &); + + // attributs + private: + /// booleen indiquant si l'editeur est en mode "lecture seule" ou non + bool read_only; + /// menus + QMenu *file_menu, *edit_menu, *display_menu, *tools_menu, *help_menu; + /// vue sur la scene d'edition + QGraphicsView *ce_view; + /// scene d'edition + EditorScene *ce_scene; + /// container pour les widgets d'edition des parties + QDockWidget *tools_dock; + /// actions du menu fichier + QAction *new_element, *open, *save, *save_as, *quit; + /// actions du menu edition + QAction *selectall, *deselectall, *inv_select; + QAction *edit_delete, *edit_size, *edit_hotspot, *edit_names, *edit_ori; + /// barre d'outils + QToolBar *parts_toolbar; + /// actions de la barre d'outils + QActionGroup *parts; + QAction *move, *add_line, *add_circle, *add_ellipse, *add_polygon, *add_text; + QAction *add_arc, *add_terminal, *add_textfield; + /// label affiche lors de la selection de plusieurs elements + QLabel *default_informations; + /// titre minimal + QString min_title; + /// Nom de fichier + QString _filename; + + // methodes + public: + void setSize(const QSize &); + QSize size() const; + void setHotspot(const QPoint &); + QPoint hotspot() const; + void setNames(const NamesList &); + void setOrientations(const OrientationSet &orientation_set); + OrientationSet orientations() const; + void setFileName(const QString &); + QString fileName() const; + void setReadOnly(bool); + bool isReadOnly() const; + void fromFile(const QString &); + bool toFile(const QString &); + + protected: + void closeEvent(QCloseEvent *); + + private: + void setupActions(); + void setupMenus(); + void setupInterface(); + bool close(); + + public slots: + void slot_new(); + void slot_open(); + bool slot_save(); + bool slot_saveAs(); + void slot_quit(QCloseEvent * = NULL); + void slot_setRubberBandToView(); + void slot_setNoDragToView(); + void slot_setNormalMode(); + void slot_updateInformations(); + void slot_updateMenus(); + void xmlPreview(); +}; + +inline void CustomElementEditor::setSize(const QSize &siz) { + ce_scene -> setWidth(siz.width()); + ce_scene -> setHeight(siz.height()); +} + +inline QSize CustomElementEditor::size() const { + return( + QSize( + ce_scene -> width(), + ce_scene -> height() + ) + ); +} + +inline void CustomElementEditor::setHotspot(const QPoint &hs) { + ce_scene -> setHotspot(hs); +} + +inline QPoint CustomElementEditor::hotspot() const { + return(ce_scene -> hotspot()); +} + +inline void CustomElementEditor::setNames(const NamesList &nameslist) { + ce_scene -> setNames(nameslist); +} + +inline void CustomElementEditor::setOrientations(const OrientationSet &orientation_set) { + ce_scene -> setOrientations(orientation_set); +} + +inline OrientationSet CustomElementEditor::orientations() const { + return(ce_scene -> orientations()); +} + +inline void CustomElementEditor::setFileName(const QString &fn) { + setWindowTitle(min_title + " - " + fn); + _filename = fn; +} + +inline QString CustomElementEditor::fileName() const { + return(_filename); +} + +#endif diff --git a/editor/customelementgraphicpart.cpp b/editor/customelementgraphicpart.cpp new file mode 100644 index 000000000..411536f75 --- /dev/null +++ b/editor/customelementgraphicpart.cpp @@ -0,0 +1,133 @@ +#include "customelementgraphicpart.h" + +/** + Ecrit les attributs de style dans un element XML + @param qde L'element XML a modifier + +*/ +void CustomElementGraphicPart::stylesToXml(QDomElement &qde) const { + QString css_like_styles; + + css_like_styles += "line-style:"; + if (_linestyle == DashedStyle) css_like_styles += "dashed"; + else if (_linestyle == NormalStyle) css_like_styles += "normal"; + + css_like_styles += ";line-weight:"; + if (_lineweight == NoneWeight) css_like_styles += "none"; + else if (_lineweight == ThinWeight) css_like_styles += "thin"; + else if (_lineweight == NormalWeight) css_like_styles += "normal"; + + css_like_styles += ";filling:"; + if (_filling == NoneFilling) css_like_styles += "none"; + else if (_filling == BlackFilling) css_like_styles += "black"; + else if (_filling == WhiteFilling) css_like_styles += "white"; + + css_like_styles += ";color:"; + if (_color == WhiteColor) css_like_styles += "white"; + else if (_color == BlackColor) css_like_styles += "black"; + + qde.setAttribute("style", css_like_styles); + qde.setAttribute("antialias", _antialiased ? "true" : "false"); +} + +/** + Lit les attributs de style depuis un element XML + @param qde L'element XML a analyser +*/ +void CustomElementGraphicPart::stylesFromXml(const QDomElement &qde) { + resetStyles(); + + // recupere la liste des couples style / valeur + QStringList styles = qde.attribute("style").split(";", QString::SkipEmptyParts); + + // analyse chaque couple + QRegExp rx("^\\s*([a-z-]+)\\s*:\\s*([a-z-]+)\\s*$"); + foreach (QString style, styles) { + if (!rx.exactMatch(style)) continue; + QString style_name = rx.cap(1); + QString style_value = rx.cap(2); + if (style_name == "line-style") { + if (style_value == "dashed") _linestyle = DashedStyle; + else if (style_value == "normal") _linestyle = NormalStyle; + // il n'y a pas de else car les valeurs non conformes sont ignorees (idem par la suite) + } else if (style_name == "line-weight") { + if (style_value == "thin") _lineweight = ThinWeight; + else if (style_value == "normal") _lineweight = NormalWeight; + else if (style_value == "none") _lineweight = NoneWeight; + } else if (style_name == "filling") { + if (style_value == "white") _filling = WhiteFilling; + else if (style_value == "black") _filling = BlackFilling; + else if (style_value == "none") _filling = NoneFilling; + } else if (style_name == "color") { + if (style_value == "black") _color = BlackColor; + else if (style_value == "white") _color = WhiteColor; + } + } + + // recupere l'antialiasing + _antialiased = qde.attribute("antialias") == "true"; + + // met a jour l'editeur de style + style_editor -> updateForm(); +} + +/** + Remet les styles par defaut +*/ +void CustomElementGraphicPart::resetStyles() { + _linestyle = NormalStyle; + _lineweight = NormalWeight; + _filling = NoneFilling; + _color = BlackColor; + _antialiased = false; +} + +/** + Applique les styles a un Qpainter + @param painter QPainter a modifier +*/ +void CustomElementGraphicPart::applyStylesToQPainter(QPainter &painter) const { + // recupere le QPen et la QBrush du QPainter + QPen pen = painter.pen(); + QBrush brush = painter.brush(); + + // applique le style de trait + if (_linestyle == DashedStyle) pen.setStyle(Qt::DashLine); + else if (_linestyle == NormalStyle) pen.setStyle(Qt::SolidLine); + + // applique l'epaisseur de trait + if (_lineweight == NoneWeight) pen.setColor(QColor(0, 0, 0, 0)); + else if (_lineweight == ThinWeight) pen.setWidth(0); + else if (_lineweight == NormalWeight) pen.setWidthF(1.0); + + // applique le remplissage + if (_filling == NoneFilling) { + brush.setStyle(Qt::NoBrush); + } else if (_filling == BlackFilling) { + brush.setStyle(Qt::SolidPattern); + brush.setColor(Qt::black); + } else if (_filling == WhiteFilling) { + brush.setStyle(Qt::SolidPattern); + brush.setColor(Qt::white); + } + + // applique la couleur de trait + if (_color == WhiteColor) pen.setColor(QColor(255, 255, 255, pen.color().alpha())); + else if (_color == BlackColor) pen.setColor(QColor( 0, 0, 0, pen.color().alpha())); + + + // applique l'antialiasing + painter.setRenderHint(QPainter::Antialiasing, _antialiased); + painter.setRenderHint(QPainter::TextAntialiasing, _antialiased); + painter.setRenderHint(QPainter::SmoothPixmapTransform, _antialiased); + + painter.setPen(pen); + painter.setBrush(brush); +} + +/** + @return Le widget permettant d'editer les styles +*/ +QWidget *CustomElementGraphicPart::elementInformations() { + return(style_editor); +} diff --git a/editor/customelementgraphicpart.h b/editor/customelementgraphicpart.h new file mode 100644 index 000000000..d4c8b9c22 --- /dev/null +++ b/editor/customelementgraphicpart.h @@ -0,0 +1,145 @@ +#ifndef CUSTOM_ELEMENT_GRAPHIC_PART_H +#define CUSTOM_ELEMENT_GRAPHIC_PART_H +#include +#include "customelementpart.h" +#include "styleeditor.h" +/** + Cette classe represente une partie graphique d'element + Elle encapsule des methodes afin de gerer les attributs de style communs + a la plupart des parties d'elements +*/ +typedef CustomElementGraphicPart CEGP; +class CustomElementGraphicPart : public CustomElementPart { + public: + enum LineStyle { NormalStyle, DashedStyle }; + enum LineWeight { NormalWeight, ThinWeight, NoneWeight }; + enum Filling { NoneFilling, BlackFilling, WhiteFilling }; + enum Color { BlackColor, WhiteColor }; + + // constructeurs, destructeur + public: + CustomElementGraphicPart() : + _linestyle(NormalStyle), + _lineweight(NormalWeight), + _filling(NoneFilling), + _color(BlackColor), + _antialiased(false) + { + style_editor = new StyleEditor(this); + }; + + virtual ~CustomElementGraphicPart() { + qDebug() << "~CustomElementGraphicPart()"; + delete style_editor; + }; + + // attributs + private: + LineStyle _linestyle; + LineWeight _lineweight; + Filling _filling ; + Color _color; + bool _antialiased; + + protected: + StyleEditor *style_editor; + + //methodes + public: + void setLineStyle(LineStyle); + void setLineWeight(LineWeight); + void setFilling(Filling); + void setColor(Color); + void setAntialiased(bool); + + LineStyle lineStyle() const; + LineWeight lineWeight() const; + Filling filling() const; + Color color() const; + bool antialiased() const; + + QWidget *elementInformations(); + + protected: + void stylesToXml(QDomElement &) const; + void stylesFromXml(const QDomElement &); + void resetStyles(); + void applyStylesToQPainter(QPainter &) const; +}; + +/** + Change le style de trait + @param ls Le nouveau style de trait +*/ +inline void CustomElementGraphicPart::setLineStyle(LineStyle ls) { + _linestyle = ls; +} + +/** + Change l'epaisseur de trait + @param lw La nouvelle epaisseur de trait +*/ +inline void CustomElementGraphicPart::setLineWeight(LineWeight lw) { + _lineweight = lw; +} + +/** + Change la couleur de remplissage + @param f La nouvelle couleur de remplissage +*/ +inline void CustomElementGraphicPart::setFilling(Filling f) { + _filling = f; +} + +/** + Change la couleur de trait + @param c La nouvelle couleur de trait +*/ +inline void CustomElementGraphicPart::setColor(Color c) { + _color = c; +} + +/** + @return Le style de trait +*/ +inline CustomElementGraphicPart::LineStyle CustomElementGraphicPart::lineStyle() const { + return(_linestyle); +} + +/** + @return L'epaisseur de trait +*/ +inline CustomElementGraphicPart::LineWeight CustomElementGraphicPart::lineWeight() const { + return(_lineweight); +} + +/** + @return La couleur de remplissage +*/ +inline CustomElementGraphicPart::Filling CustomElementGraphicPart::filling() const { + return(_filling); +} + +/** + @return La couleur de trait +*/ +inline CustomElementGraphicPart::Color CustomElementGraphicPart::color() const { + return(_color); +} + +/** + Definit si la partie doit etre antialiasee ou non + @param aa True pour activer l'antialiasing, false pour le desactiver +*/ +inline void CustomElementGraphicPart::setAntialiased(bool aa) { + _antialiased = aa; +} + +/** + @return true si la partie est antialiasee, false sinon +*/ +inline bool CustomElementGraphicPart::antialiased() const { + return(_antialiased); +} + +#endif diff --git a/editor/customelementpart.cpp b/editor/customelementpart.cpp new file mode 100644 index 000000000..990173907 --- /dev/null +++ b/editor/customelementpart.cpp @@ -0,0 +1,6 @@ +#include "customelementpart.h" +#include "customelement.h" + +QPicture *CustomElementPart::getCustomElementQPicture(CustomElement &ce) const { + return(&(ce.dessin)); +} diff --git a/editor/customelementpart.h b/editor/customelementpart.h new file mode 100644 index 000000000..a46c52238 --- /dev/null +++ b/editor/customelementpart.h @@ -0,0 +1,39 @@ +#ifndef CUSTOM_ELEMENT_PART_H +#define CUSTOM_ELEMENT_PART_H +#include +#include +#include +class CustomElement; +/** + Cette classe abstraite represente une partie de la representation graphique + d'un element de schema electrique. Les attributs et methodes qu'elle + encapsule ne sont pas integres directement dans la classe CustomElement + afin de ne pas alourdir celle-ci. Il est en effet inutile pour cette classe + de retenir sa conception graphique autrement que sous la forme d'une + QImage. +*/ +class CustomElementPart { + // constructeurs, destructeur + public: + CustomElementPart() {}; + virtual ~CustomElementPart() { + qDebug() << "~CustomElementPart()"; + }; + private: + CustomElementPart(const CustomElementPart &); + + // attributs + private: + + // methodes + public: + virtual void fromXml(const QDomElement &) = 0; + virtual const QDomElement toXml(QDomDocument &) const = 0; + virtual QWidget *elementInformations() = 0; + //virtual void renderToCustomElement(CustomElement &) const = 0; + //virtual void toEditorPart(const EditorPart &); + //virtual void fromEditorPart(const EditorPart &) = 0; + protected: + QPicture *getCustomElementQPicture(CustomElement &ce) const; +}; +#endif diff --git a/editor/editorscene.cpp b/editor/editorscene.cpp new file mode 100644 index 000000000..8400b863c --- /dev/null +++ b/editor/editorscene.cpp @@ -0,0 +1,447 @@ +#include "editorscene.h" +#include +#include "partline.h" +#include "partellipse.h" +#include "partcircle.h" +#include "partpolygon.h" +#include "partterminal.h" +#include "parttext.h" +#define GRILLE_X 10 +#define GRILLE_Y 10 + +EditorScene::EditorScene(QObject *parent) : + QGraphicsScene(parent), + _width(3), + _height(7), + _hotspot(15, 35) +{ + current_polygon = NULL; + connect(this, SIGNAL(changed(const QList &)), this, SLOT(slot_checkSelectionChanged())); +} + +EditorScene::~EditorScene() { + qDebug() << "~EditorScene()"; +} + +void EditorScene::slot_move() { + behavior = Normal; +} + +void EditorScene::slot_addLine() { + behavior = Line; +} + +void EditorScene::slot_addCircle() { + behavior = Circle; +} + +void EditorScene::slot_addEllipse() { + behavior = Ellipse; +} + +void EditorScene::slot_addPolygon() { + behavior = Polygon; +} + +void EditorScene::slot_addText() { + behavior = Text; +} + +void EditorScene::slot_addTerminal() { + behavior = Terminal; +} + +void EditorScene::slot_addArc() { + behavior = Arc; +} + +void EditorScene::slot_addTextField() { + behavior = TextField; +} + +void EditorScene::mouseMoveEvent(QGraphicsSceneMouseEvent *e) { + if (behavior != Polygon && current_polygon != NULL) current_polygon = NULL; + QRectF temp_rect; + qreal radius; + QPointF temp_point; + QPolygonF temp_polygon; + if (e -> buttons() & Qt::LeftButton) { + switch(behavior) { + case Normal: + QGraphicsScene::mouseMoveEvent(e); + break; + case Line: + current_line -> setLine(QLineF(current_line -> line().p1(), e -> scenePos())); + break; + case Ellipse: + temp_rect = current_ellipse -> rect(); + temp_rect.setBottomRight(e -> scenePos()); + current_ellipse -> setRect(temp_rect); + break; + case Circle: + temp_rect = current_circle -> rect(); + temp_point = e -> scenePos() - current_circle -> mapToScene(temp_rect.center()); + radius = sqrt(pow(temp_point.x(), 2) + pow(temp_point.y(), 2)); + temp_rect = QRectF( + temp_rect.center() - QPointF(radius, radius), + QSizeF(2.0 * radius, 2.0 * radius) + ); + current_circle -> setRect(temp_rect); + break; + case Polygon: + if (current_polygon == NULL) break; + temp_polygon = current_polygon -> polygon(); + temp_polygon.pop_back(); + temp_polygon << e -> scenePos(); + current_polygon -> setPolygon(temp_polygon); + break; + default: + QGraphicsScene::mouseMoveEvent(e); + } + } else if (behavior == Polygon && current_polygon != NULL) { + temp_polygon = current_polygon -> polygon(); + temp_polygon.pop_back(); + temp_polygon << e -> scenePos(); + current_polygon -> setPolygon(temp_polygon); + } else QGraphicsScene::mouseMoveEvent(e); +} + +void EditorScene::mousePressEvent(QGraphicsSceneMouseEvent *e) { + if (behavior != Polygon && current_polygon != NULL) current_polygon = NULL; + QPolygonF temp_polygon; + if (e -> button() & Qt::LeftButton) { + switch(behavior) { + case Normal: + QGraphicsScene::mousePressEvent(e); + break; + case Line: + current_line = new PartLine(0, this); + current_line -> setLine(QLineF(e -> scenePos(), e -> scenePos())); + break; + case Ellipse: + current_ellipse = new PartEllipse(0, this); + current_ellipse -> setRect(QRectF(e -> scenePos(), QSizeF(0.0, 0.0))); + break; + case Circle: + current_circle = new PartCircle(0, this); + current_circle -> setRect(QRectF(e -> scenePos(), QSizeF(0.0, 0.0))); + break; + case Polygon: + if (current_polygon == NULL) { + current_polygon = new PartPolygon(0, this); + temp_polygon = QPolygonF(0); + } else temp_polygon = current_polygon -> polygon(); + // au debut, on insere deux points + if (!temp_polygon.count()) temp_polygon << e -> scenePos(); + temp_polygon << e -> scenePos(); + current_polygon -> setPolygon(temp_polygon); + break; + default: + QGraphicsScene::mousePressEvent(e); + } + } else QGraphicsScene::mousePressEvent(e); +} + +void EditorScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *e) { + PartTerminal *terminal; + PartText *text; + if (behavior != Polygon && current_polygon != NULL) current_polygon = NULL; + if (e -> button() & Qt::LeftButton) { + switch(behavior) { + case Normal: + QGraphicsScene::mouseReleaseEvent(e); + break; + case Line: + break; + case Ellipse: + current_ellipse -> setRect(current_ellipse -> rect().normalized()); + break; + case Circle: + current_circle -> setRect(current_circle -> rect().normalized()); + break; + case Terminal: + terminal = new PartTerminal(0, this); + terminal -> setPos(e -> scenePos()); + break; + case Text: + text = new PartText(0, this); + text -> setPos(e -> scenePos()); + break; + default: + QGraphicsScene::mouseReleaseEvent(e); + } + } else if (e -> button() & Qt::RightButton) { + if (behavior == Polygon) { + behavior = Normal; + current_polygon = NULL; + emit(needNormalMode()); + } else QGraphicsScene::mouseReleaseEvent(e); + } else QGraphicsScene::mouseReleaseEvent(e); +} + +/** + Dessine l'arriere-plan de l'editeur, cad la grille. + @param p Le QPainter a utiliser pour dessiner + @param r Le rectangle de la zone a dessiner +*/ +void EditorScene::drawBackground(QPainter *p, const QRectF &r) { + p -> save(); + + // desactive tout antialiasing, sauf pour le texte + p -> setRenderHint(QPainter::Antialiasing, false); + p -> setRenderHint(QPainter::TextAntialiasing, true); + p -> setRenderHint(QPainter::SmoothPixmapTransform, false); + + // dessine un fond blanc + p -> setPen(Qt::NoPen); + p -> setBrush(Qt::white); + p -> drawRect(r); + + // encadre la zone dessinable de l'element + QRectF drawable_area(-_hotspot.x(), -_hotspot.y(), width(), height()); + p -> setPen(Qt::black); + p -> setBrush(Qt::NoBrush); + p -> drawRect(drawable_area); + + if (r.width() < 2500 && r.height() < 2500) { + // dessine les points de la grille + p -> setPen(Qt::black); + p -> setBrush(Qt::NoBrush); + qreal limite_x = r.x() + r.width(); + qreal limite_y = r.y() + r.height(); + + int g_x = (int)ceil(r.x()); + while (g_x % GRILLE_X) ++ g_x; + int g_y = (int)ceil(r.y()); + while (g_y % GRILLE_Y) ++ g_y; + + for (int gx = g_x ; gx < limite_x ; gx += GRILLE_X) { + for (int gy = g_y ; gy < limite_y ; gy += GRILLE_Y) { + p -> drawPoint(gx, gy); + } + } + } + p -> restore(); +} + +/** + Dessine l'arriere-plan de l'editeur, cad l'indicateur de hotspotó. + @param p Le QPainter a utiliser pour dessiner + @param r Le rectangle de la zone a dessiner +*/ +void EditorScene::drawForeground(QPainter *p, const QRectF &) { + p -> save(); + + // desactive tout antialiasing, sauf pour le texte + p -> setRenderHint(QPainter::Antialiasing, false); + p -> setRenderHint(QPainter::TextAntialiasing, true); + p -> setRenderHint(QPainter::SmoothPixmapTransform, false); + + p -> setPen(Qt::red); + p -> setBrush(Qt::NoBrush); + p -> drawLine(QLineF(0.0, -_hotspot.y(), 0.0, height() - _hotspot.y())); + p -> drawLine(QLineF(-_hotspot.x(), 0.0, width() - _hotspot.x(), 0.0)); + p -> restore(); +} + +const QDomDocument EditorScene::toXml() const { + // document XML + QDomDocument xml_document; + + // racine du document XML + QDomElement root = xml_document.createElement("definition"); + root.setAttribute("type", "element"); + root.setAttribute("width", QString("%1").arg(_width * 10)); + root.setAttribute("height", QString("%1").arg(_height * 10)); + root.setAttribute("hotspot_x", QString("%1").arg(_hotspot.x())); + root.setAttribute("hotspot_y", QString("%1").arg(_hotspot.y())); + root.setAttribute("orientation", ori.toString()); + + // noms de l'element + root.appendChild(_names.toXml(xml_document)); + + QDomElement description = xml_document.createElement("description"); + // description de l'element + foreach(QGraphicsItem *qgi, items()) { + if (CustomElementPart *ce = dynamic_cast(qgi)) { + description.appendChild(ce -> toXml(xml_document)); + } + } + root.appendChild(description); + + xml_document.appendChild(root); + return(xml_document); +} + +void EditorScene::fromXml(const QDomDocument &xml_document) { + + QString error_message; + bool state = true; + + // la racine est supposee etre une definition d'element + QDomElement root = xml_document.documentElement(); + if (root.tagName() != "definition" || root.attribute("type") != "element") { + state = false; + error_message = tr("Ce document XML n'est pas une definition d'\351l\351ment."); + } + + // dimensions et hotspot + if (state) { + // ces attributs doivent etre presents et valides + int w, h, hot_x, hot_y; + if ( + !QET::attributeIsAnInteger(root, QString("width"), &w) ||\ + !QET::attributeIsAnInteger(root, QString("height"), &h) ||\ + !QET::attributeIsAnInteger(root, QString("hotspot_x"), &hot_x) ||\ + !QET::attributeIsAnInteger(root, QString("hotspot_y"), &hot_y) + ) { + state = false; + error_message = tr("Les dimensions ou le point de saisie ne sont pas valides."); + } else { + setWidth(w); + setHeight(h); + setHotspot(QPoint(hot_x, hot_y)); + } + } + + // orientations + if (state) { + if (!ori.fromString(root.attribute("orientation"))) { + state = false; + error_message = tr("Les orientations ne sont pas valides."); + } + } + + // extrait les noms de la definition XML + if (state) { + _names.fromXml(root); + } + + // parcours des enfants de la definition : parties de l'element + if (state) { + for (QDomNode node = root.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 + int z = 1; + for (QDomNode n = node.firstChild() ; !n.isNull() ; n = n.nextSibling()) { + QDomElement qde = n.toElement(); + if (qde.isNull()) continue; + CustomElementPart *cep; + if (qde.tagName() == "line") cep = new PartLine (0, this); + else if (qde.tagName() == "ellipse") cep = new PartEllipse (0, this); + else if (qde.tagName() == "circle") cep = new PartCircle (0, this); + else if (qde.tagName() == "polygon") cep = new PartPolygon (0, this); + else if (qde.tagName() == "terminal") cep = new PartTerminal(0, this); + else if (qde.tagName() == "text") cep = new PartText (0, this); + else continue; + if (QGraphicsItem *qgi = dynamic_cast(cep)) qgi -> setZValue(z++); + cep -> fromXml(qde); + } + } + } + } +} + +void EditorScene::slot_checkSelectionChanged() { + static QList cache_selecteditems = QList(); + QList selecteditems = selectedItems(); + if (cache_selecteditems != selecteditems) emit(selectionChanged()); + cache_selecteditems = selecteditems; +} + +void EditorScene::slot_selectAll() { + foreach(QGraphicsItem *qgi, items()) qgi -> setSelected(true); +} + +void EditorScene::slot_deselectAll() { + clearSelection(); +} + +void EditorScene::slot_invertSelection() { + foreach(QGraphicsItem *qgi, items()) qgi -> setSelected(!qgi -> isSelected()); +} + +void EditorScene::slot_delete() { + // verifie qu'il y a qqc de selectionne + QList selected_items = selectedItems(); + if (selected_items.isEmpty()) return; + + // efface tout ce qui est selectionne + foreach(QGraphicsItem *qgi, selected_items) { + removeItem(qgi); + delete qgi; + } +} + +void EditorScene::slot_editSize() { + +} + +void EditorScene::slot_editHotSpot() { + +} + +void EditorScene::slot_editOrientations() { + + // cree un dialogue + QDialog dialog_ori; + dialog_ori.setModal(true); + dialog_ori.setFixedSize(400, 230); + dialog_ori.setWindowTitle(tr("\311diter les orientations")); + QVBoxLayout *dialog_layout = new QVBoxLayout(&dialog_ori); + + // ajoute un champ explicatif au dialogue + QLabel *information_label = new QLabel(tr("L'orientation par d\351faut est l'orientation dans laquelle s'effectue la cr\351ation de l'\351l\351ment.")); + information_label -> setAlignment(Qt::AlignJustify | Qt::AlignVCenter); + information_label -> setWordWrap(true); + dialog_layout -> addWidget(information_label); + + // ajoute un OrientationSetWidget au dialogue + OrientationSetWidget *ori_widget = new OrientationSetWidget(); + ori_widget -> setOrientationSet(ori); + dialog_layout -> addWidget(ori_widget); + + // ajoute deux boutons au dialogue + QDialogButtonBox *dialog_buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + dialog_layout -> addWidget(dialog_buttons); + connect(dialog_buttons, SIGNAL(accepted()), &dialog_ori, SLOT(accept())); + connect(dialog_buttons, SIGNAL(rejected()), &dialog_ori, SLOT(reject())); + + // lance le dialogue + if (dialog_ori.exec() == QDialog::Accepted) ori = ori_widget -> orientationSet(); +} + +void EditorScene::slot_editNames() { + + // cree un dialogue + QDialog dialog; + dialog.setModal(true); + dialog.setFixedSize(400, 330); + dialog.setWindowTitle(tr("\311diter les noms")); + QVBoxLayout *dialog_layout = new QVBoxLayout(&dialog); + + // ajoute un champ explicatif au dialogue + QLabel *information_label = new QLabel(tr("Vous pouvez sp\351cifier le nom de l'\351l\351ment dans plusieurs langues.")); + information_label -> setAlignment(Qt::AlignJustify | Qt::AlignVCenter); + information_label -> setWordWrap(true); + dialog_layout -> addWidget(information_label); + + // ajoute un NamesListWidget au dialogue + NamesListWidget *names_widget = new NamesListWidget(); + names_widget -> setNames(_names); + dialog_layout -> addWidget(names_widget); + + // ajoute deux boutons au dialogue + QDialogButtonBox *dialog_buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + dialog_layout -> addWidget(dialog_buttons); + connect(dialog_buttons, SIGNAL(accepted()), names_widget, SLOT(check())); + connect(names_widget, SIGNAL(inputChecked()), &dialog, SLOT(accept())); + connect(dialog_buttons, SIGNAL(rejected()), &dialog, SLOT(reject())); + + // lance le dialogue + if (dialog.exec() == QDialog::Accepted) _names = names_widget -> names(); +} + diff --git a/editor/editorscene.h b/editor/editorscene.h new file mode 100644 index 000000000..a5405d2d0 --- /dev/null +++ b/editor/editorscene.h @@ -0,0 +1,136 @@ +#ifndef EDITOR_SCNE_H +#define EDITOR_SCNE_H +#include +#include +#include "nameslistwidget.h" +#include "orientationsetwidget.h" +class PartLine; +class PartEllipse; +class PartCircle; +class PartPolygon; +class EditorScene : public QGraphicsScene { + Q_OBJECT + + // enum + enum Behavior { Normal, Line, Circle, Ellipse, Polygon, Text, Terminal, Arc, TextField }; + + // constructeurs, destructeur + public: + EditorScene(QObject * = 0); + virtual ~EditorScene(); + + private: + EditorScene(const EditorScene &); + + // attributs + private: + /// longueur de l'element en dizaines de pixels + uint _width; + /// hauteur de l'element en dizaines de pixels + uint _height; + /// position du point de saisie + QPoint _hotspot; + /// Liste des noms de l'element + NamesList _names; + /// Liste des orientations de l'element + OrientationSet ori; + + /// Variables relatives a la gestion du dessin des parties sur la scene + Behavior behavior; + PartLine *current_line; + PartEllipse *current_ellipse; + PartCircle *current_circle; + PartPolygon *current_polygon; + + // methodes + public: + void setWidth(const uint& theValue); + uint width() const; + void setHeight(const uint& theValue); + uint height() const; + void setHotspot(const QPoint &); + QPoint hotspot() const; + void setNames(const NamesList); + NamesList names() const; + OrientationSet orientations(); + void setOrientations(const OrientationSet &); + virtual const QDomDocument toXml() const; + virtual void fromXml(const QDomDocument &); + + protected: + virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *); + virtual void mousePressEvent(QGraphicsSceneMouseEvent *); + virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *); + virtual void drawBackground(QPainter *, const QRectF &); + virtual void drawForeground(QPainter *, const QRectF &); + + public slots: + void slot_move(); + void slot_addLine(); + void slot_addCircle(); + void slot_addEllipse(); + void slot_addPolygon(); + void slot_addText(); + void slot_addArc(); + void slot_addTerminal(); + void slot_addTextField(); + void slot_checkSelectionChanged(); + void slot_selectAll(); + void slot_deselectAll(); + void slot_invertSelection(); + void slot_delete(); + void slot_editSize(); + void slot_editHotSpot(); + void slot_editNames(); + void slot_editOrientations(); + + signals: + void selectionChanged(); + void needNormalMode(); +}; + +inline void EditorScene::setWidth(const uint &wid) { + _width = wid; + while (_width % 10) ++ _width; + _width /= 10; +} + +inline uint EditorScene::width() const { + return(_width * 10); +} + +inline void EditorScene::setHeight(const uint &hei) { + _height = hei; + while (_height % 10) ++ _height; + _height /= 10; +} + +inline uint EditorScene::height() const { + return(_height * 10); +} + +inline void EditorScene::setHotspot(const QPoint &hs) { + _hotspot = hs; +} + +inline QPoint EditorScene::hotspot() const { + return(_hotspot); +} + +inline void EditorScene::setNames(const NamesList nameslist) { + _names = nameslist; +} + +inline NamesList EditorScene::names() const { + return(_names); +} + +inline OrientationSet EditorScene::orientations() { + return(ori); +} + +inline void EditorScene::setOrientations(const OrientationSet &orientation_set) { + ori = orientation_set; +} + +#endif diff --git a/editor/ellipseeditor.cpp b/editor/ellipseeditor.cpp new file mode 100644 index 000000000..454a11327 --- /dev/null +++ b/editor/ellipseeditor.cpp @@ -0,0 +1,66 @@ +#include "ellipseeditor.h" +#include "partellipse.h" + +EllipseEditor::EllipseEditor(PartEllipse *ellipse, QWidget *parent) : QWidget(parent) { + + part = ellipse; + + x = new QLineEdit(); + y = new QLineEdit(); + h = new QLineEdit(); + v = new QLineEdit(); + +// QDoubleValidator *format = new QDoubleValidator(-1000.0, -1000.0, 4, this); +// x -> setValidator(new QDoubleValidator(-1000.0, 1000.0, 4, this)); +// y -> setValidator(new QDoubleValidator(-1000.0, 1000.0, 4, this)); +// h -> setValidator(new QDoubleValidator(0.0, 1000.0, 4, this)); +// v -> setValidator(new QDoubleValidator(0.0, 1000.0, 4, this)); + + + QGridLayout *grid = new QGridLayout(this); + grid -> addWidget(new QLabel(tr("Centre : ")), 0, 0); + grid -> addWidget(new QLabel("x"), 1, 0); + grid -> addWidget(x, 1, 1); + grid -> addWidget(new QLabel("y"), 1, 2); + grid -> addWidget(y, 1, 3); + grid -> addWidget(new QLabel(tr("Diam\350tres : ")), 2, 0); + grid -> addWidget(new QLabel(tr("horizontal :")), 3, 0); + grid -> addWidget(h, 3, 1); + grid -> addWidget(new QLabel(tr("vertical :")), 4, 0); + grid -> addWidget(v, 4, 1); + + updateForm(); + + connect(x, SIGNAL(editingFinished()), this, SLOT(updateEllipse())); + connect(y, SIGNAL(editingFinished()), this, SLOT(updateEllipse())); + connect(h, SIGNAL(editingFinished()), this, SLOT(updateEllipse())); + connect(v, SIGNAL(editingFinished()), this, SLOT(updateEllipse())); +} + +EllipseEditor::~EllipseEditor() { + qDebug() << "~EllipseEditor()"; +} + +void EllipseEditor::updateEllipse() { + qreal _x = x -> text().toDouble(); + qreal _y = y -> text().toDouble(); + qreal _h = h -> text().toDouble(); + qreal _v = v -> text().toDouble(); + _v = _v < 0 ? -_v : _v; + part -> setRect( + QRectF( + part -> mapFromScene(QPointF(_x - (_h / 2.0), _y - (_v / 2.0))), + QSizeF(_h, _v) + ) + ); +} + +void EllipseEditor::updateForm() { + qreal _h = part -> rect().width(); + qreal _v = part -> rect().height(); + QPointF top_left(part -> sceneTopLeft()); + x -> setText(QString("%1").arg(top_left.x() + (_h / 2.0))); + y -> setText(QString("%1").arg(top_left.y() + (_v / 2.0))); + h -> setText(QString("%1").arg(_h)); + v -> setText(QString("%1").arg(_v)); +} diff --git a/editor/ellipseeditor.h b/editor/ellipseeditor.h new file mode 100644 index 000000000..b713814a4 --- /dev/null +++ b/editor/ellipseeditor.h @@ -0,0 +1,24 @@ +#ifndef ELLIPSE_EDITOR_H +#define ELLIPSE_EDITOR_H +#include +class PartEllipse; +class EllipseEditor : public QWidget { + Q_OBJECT + //constructeurs, destructeur + public: + EllipseEditor(PartEllipse *, QWidget * = 0); + ~EllipseEditor(); + private: + EllipseEditor(const EllipseEditor &); + + // attributs + private: + PartEllipse *part; + QLineEdit *x, *y, *h, *v; + + // methodes + public slots: + void updateEllipse(); + void updateForm(); +}; +#endif diff --git a/editor/lineeditor.cpp b/editor/lineeditor.cpp new file mode 100644 index 000000000..66c8ba35f --- /dev/null +++ b/editor/lineeditor.cpp @@ -0,0 +1,57 @@ +#include "lineeditor.h" +#include "partline.h" + +LineEditor::LineEditor(PartLine *line, QWidget *parent) : QWidget(parent) { + + part = line; + + x1 = new QLineEdit(); + y1 = new QLineEdit(); + x2 = new QLineEdit(); + y2 = new QLineEdit(); + + QGridLayout *grid = new QGridLayout(this); + grid -> addWidget(new QLabel("x1"), 0, 0); + grid -> addWidget(x1, 0, 1); + grid -> addWidget(new QLabel("y1"), 0, 2); + grid -> addWidget(y1, 0, 3); + grid -> addWidget(new QLabel("x2"), 1, 0); + grid -> addWidget(x2, 1, 1); + grid -> addWidget(new QLabel("y2"), 1, 2); + grid -> addWidget(y2, 1, 3); + + updateForm(); + + connect(x1, SIGNAL(editingFinished()), this, SLOT(updateLine())); + connect(y1, SIGNAL(editingFinished()), this, SLOT(updateLine())); + connect(x2, SIGNAL(editingFinished()), this, SLOT(updateLine())); + connect(y2, SIGNAL(editingFinished()), this, SLOT(updateLine())); +} + +LineEditor::~LineEditor() { + qDebug() << "~LineEditor()"; +} + +void LineEditor::updateLine() { + part -> setLine( + QLineF( + part -> mapFromScene( + x1 -> text().toDouble(), + y1 -> text().toDouble() + ), + part -> mapFromScene( + x2 -> text().toDouble(), + y2 -> text().toDouble() + ) + ) + ); +} + +void LineEditor::updateForm() { + QPointF p1(part -> sceneP1()); + QPointF p2(part -> sceneP2()); + x1 -> setText(QString("%1").arg(p1.x())); + y1 -> setText(QString("%1").arg(p1.y())); + x2 -> setText(QString("%1").arg(p2.x())); + y2 -> setText(QString("%1").arg(p2.y())); +} diff --git a/editor/lineeditor.h b/editor/lineeditor.h new file mode 100644 index 000000000..4a7050dca --- /dev/null +++ b/editor/lineeditor.h @@ -0,0 +1,24 @@ +#ifndef LINE_EDITOR_H +#define LINE_EDITOR_H +#include +class PartLine; +class LineEditor : public QWidget { + Q_OBJECT + //constructeurs, destructeur + public: + LineEditor(PartLine *, QWidget * = 0); + ~LineEditor(); + private: + LineEditor(const LineEditor &); + + // attributs + private: + PartLine *part; + QLineEdit *x1, *y1, *x2, *y2; + + // methodes + public slots: + void updateLine(); + void updateForm(); +}; +#endif diff --git a/editor/partcircle.cpp b/editor/partcircle.cpp new file mode 100644 index 000000000..e34c9a1a0 --- /dev/null +++ b/editor/partcircle.cpp @@ -0,0 +1,77 @@ +#include "partcircle.h" +#include "circleeditor.h" + +PartCircle::PartCircle(QGraphicsItem *parent, QGraphicsScene *scene) : QGraphicsEllipseItem(parent, scene), CustomElementGraphicPart() { + setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable); + setAcceptedMouseButtons(Qt::LeftButton); + informations = new CircleEditor(this); + style_editor -> appendWidget(informations); +} + +void PartCircle::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) { + applyStylesToQPainter(*painter); + QPen t = painter -> pen(); + if (isSelected()) { + t.setColor(Qt::red); + painter -> setPen(t); + } + painter -> drawEllipse(rect()); + if (isSelected()) { + painter -> setRenderHint(QPainter::Antialiasing, false); + painter -> setPen((painter -> brush().color() == QColor(Qt::black) && painter -> brush().isOpaque()) ? Qt::yellow : Qt::blue); + QPointF center = rect().center(); + painter -> drawLine(QLineF(center.x() - 2.0, center.y(), center.x() + 2.0, center.y())); + painter -> drawLine(QLineF(center.x(), center.y() - 2.0, center.x(), center.y() + 2.0)); + } +} + +const QDomElement PartCircle::toXml(QDomDocument &xml_document) const { + QDomElement xml_element = xml_document.createElement("circle"); + QPointF top_left(sceneTopLeft()); + xml_element.setAttribute("x", top_left.x()); + xml_element.setAttribute("y", top_left.y()); + xml_element.setAttribute("diameter", rect().width()); + stylesToXml(xml_element); + return(xml_element); +} + +void PartCircle::fromXml(const QDomElement &qde) { + stylesFromXml(qde); + qreal diameter = qde.attribute("diameter", "0").toDouble(); + setRect( + QRectF( + mapFromScene( + qde.attribute("x", "0").toDouble(), + qde.attribute("y", "0").toDouble() + ), + QSizeF( + diameter, + diameter + ) + ) + ); +} + +QVariant PartCircle::itemChange(GraphicsItemChange change, const QVariant &value) { + if (scene()) { + if (change == QGraphicsItem::ItemPositionChange || change == QGraphicsItem::ItemSelectedChange) { + informations -> updateForm(); + } + } + return(QGraphicsEllipseItem::itemChange(change, value)); +} + +QPointF PartCircle::sceneTopLeft() const { + return(mapToScene(rect().topLeft())); +} + +QPointF PartCircle::sceneCenter() const { + return(mapToScene(rect().center())); +} + +QRectF PartCircle::boundingRect() const { + qreal adjust = 1.5; + QRectF r(QGraphicsEllipseItem::boundingRect()); + r.adjust(-adjust, -adjust, adjust, adjust); + return(r); +} diff --git a/editor/partcircle.h b/editor/partcircle.h new file mode 100644 index 000000000..2bbb55e3b --- /dev/null +++ b/editor/partcircle.h @@ -0,0 +1,33 @@ +#ifndef PART_CIRCLE_H +#define PART_CIRCLE_H +#include +#include "customelementgraphicpart.h" +class CircleEditor; +class PartCircle : public QGraphicsEllipseItem, public CustomElementGraphicPart { + // constructeurs, destructeur + public: + PartCircle(QGraphicsItem * = 0, QGraphicsScene * = 0); + virtual ~PartCircle() { + qDebug() << "~PartCircle()"; + } + + private: + PartCircle(const PartCircle &); + + // attributs + private: + CircleEditor *informations; + + // methodes + public: + virtual void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget * = 0); + virtual const QDomElement toXml(QDomDocument &) const; + virtual void fromXml(const QDomElement &); + virtual QPointF sceneTopLeft() const; + virtual QRectF boundingRect() const; + QPointF sceneCenter() const; + + protected: + QVariant itemChange(GraphicsItemChange, const QVariant &); +}; +#endif diff --git a/editor/partellipse.cpp b/editor/partellipse.cpp new file mode 100644 index 000000000..c2a6f5b14 --- /dev/null +++ b/editor/partellipse.cpp @@ -0,0 +1,66 @@ +#include "partellipse.h" +#include "ellipseeditor.h" + +PartEllipse::PartEllipse(QGraphicsItem *parent, QGraphicsScene *scene) : QGraphicsEllipseItem(parent, scene), CustomElementGraphicPart() { + setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable); + setAcceptedMouseButtons(Qt::LeftButton); + informations = new EllipseEditor(this); + style_editor -> appendWidget(informations); +} + +void PartEllipse::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) { + applyStylesToQPainter(*painter); + QPen t = painter -> pen(); + if (isSelected()) { + t.setColor(Qt::red); + painter -> setPen(t); + } + painter -> drawEllipse(rect()); + if (isSelected()) { + painter -> setRenderHint(QPainter::Antialiasing, false); + painter -> setPen((painter -> brush().color() == QColor(Qt::black) && painter -> brush().isOpaque()) ? Qt::yellow : Qt::blue); + QPointF center = rect().center(); + painter -> drawLine(QLineF(center.x() - 2.0, center.y(), center.x() + 2.0, center.y())); + painter -> drawLine(QLineF(center.x(), center.y() - 2.0, center.x(), center.y() + 2.0)); + } +} + +const QDomElement PartEllipse::toXml(QDomDocument &xml_document) const { + QDomElement xml_element = xml_document.createElement("ellipse"); + QPointF top_left(sceneTopLeft()); + xml_element.setAttribute("x", top_left.x()); + xml_element.setAttribute("y", top_left.y()); + xml_element.setAttribute("width", rect().width()); + xml_element.setAttribute("height", rect().height()); + stylesToXml(xml_element); + return(xml_element); +} + +void PartEllipse::fromXml(const QDomElement &qde) { + stylesFromXml(qde); + setRect( + QRectF( + mapFromScene( + qde.attribute("x", "0").toDouble(), + qde.attribute("y", "0").toDouble() + ), + QSizeF( + qde.attribute("width", "0").toDouble(), + qde.attribute("height", "0").toDouble() + ) + ) + ); +} + +QVariant PartEllipse::itemChange(GraphicsItemChange change, const QVariant &value) { + if (scene()) { + if (change == QGraphicsItem::ItemPositionChange || change == QGraphicsItem::ItemSelectedChange) { + informations -> updateForm(); + } + } + return(QGraphicsEllipseItem::itemChange(change, value)); +} + +QPointF PartEllipse::sceneTopLeft() const { + return(mapToScene(rect().topLeft())); +} diff --git a/editor/partellipse.h b/editor/partellipse.h new file mode 100644 index 000000000..ae27183c2 --- /dev/null +++ b/editor/partellipse.h @@ -0,0 +1,31 @@ +#ifndef PART_ELLIPSE_H +#define PART_ELLIPSE_H +#include +#include "customelementgraphicpart.h" +class EllipseEditor; +class PartEllipse : public QGraphicsEllipseItem, public CustomElementGraphicPart { + // constructeurs, destructeur + public: + PartEllipse(QGraphicsItem * = 0, QGraphicsScene * = 0); + virtual ~PartEllipse() { + qDebug() << "~PartEllipse()"; + } + + private: + PartEllipse(const PartEllipse &); + + // attributs + private: + EllipseEditor *informations; + + // methodes + public: + virtual void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget * = 0); + virtual const QDomElement toXml(QDomDocument &) const; + virtual void fromXml(const QDomElement &); + virtual QPointF sceneTopLeft() const; + + protected: + QVariant itemChange(GraphicsItemChange, const QVariant &); +}; +#endif diff --git a/editor/partline.cpp b/editor/partline.cpp new file mode 100644 index 000000000..5cf0db8b5 --- /dev/null +++ b/editor/partline.cpp @@ -0,0 +1,143 @@ +#include "partline.h" +#include "lineeditor.h" +#include + +PartLine::PartLine(QGraphicsItem *parent, QGraphicsScene *scene) : QGraphicsLineItem(parent, scene), CustomElementGraphicPart() { + setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable); + setAcceptedMouseButtons(Qt::LeftButton); + informations = new LineEditor(this); + style_editor -> appendWidget(informations); +} + +void PartLine::paint(QPainter *painter, const QStyleOptionGraphicsItem */*q*/, QWidget */*w*/) { + applyStylesToQPainter(*painter); + QPen t = painter -> pen(); + if (isSelected()) { + t.setColor(Qt::red); + painter -> setPen(t); + } + painter -> setBrush(Qt::NoBrush); + painter -> drawLine(line()); +} + +const QDomElement PartLine::toXml(QDomDocument &xml_document) const { + QDomElement xml_element = xml_document.createElement("line"); + QPointF p1(sceneP1()); + QPointF p2(sceneP2()); + xml_element.setAttribute("x1", p1.x()); + xml_element.setAttribute("y1", p1.y()); + xml_element.setAttribute("x2", p2.x()); + xml_element.setAttribute("y2", p2.y()); + stylesToXml(xml_element); + return(xml_element); +} + +void PartLine::fromXml(const QDomElement &qde) { + stylesFromXml(qde); + setLine( + QLineF( + mapFromScene( + qde.attribute("x1", "0").toDouble(), + qde.attribute("y1", "0").toDouble() + ), + mapFromScene( + qde.attribute("x2", "0").toDouble(), + qde.attribute("y2", "0").toDouble() + ) + ) + ); +} + +QVariant PartLine::itemChange(GraphicsItemChange change, const QVariant &value) { + if (scene()) { + if (change == QGraphicsItem::ItemPositionChange || change == QGraphicsItem::ItemSelectedChange) { + informations -> updateForm(); + } + } + return(QGraphicsLineItem::itemChange(change, value)); +} + +QPointF PartLine::sceneP1() const { + return(mapToScene(line().p1())); +} + +QPointF PartLine::sceneP2() const { + return(mapToScene(line().p2())); +} + +/* + + + + +*/ + +QPainterPath PartLine::shape() const { + QList points = fourShapePoints(); + QPainterPath t; + t.setFillRule(Qt::WindingFill); + t.moveTo(points.at(0)); + t.lineTo(points.at(1)); + t.lineTo(points.at(2)); + t.lineTo(points.at(3)); + t.lineTo(points.at(0)); + return(t); +} + +/* +QRectF PartLine::boundingRect() const { + QList points = fourShapePoints(); + qreal min_x = points.first().x(); + qreal max_x = points.first().x(); + qreal min_y = points.first().y(); + qreal max_y = points.first().y(); + foreach(QPointF p, points) { + if (p.x() > max_x) max_x = p.x(); + if (p.x() < min_x) min_x = p.x(); + if (p.y() > max_y) max_y = p.y(); + if (p.y() < min_y) min_y = p.y(); + } + QRectF r; + r.setCoords(min_x, min_y, max_x, max_y); + return(r); +} +*/ +/** + @return une liste contenant les deux points de la droite + les 4 points entourant ces deux points +*/ +QList PartLine::fourShapePoints() const { + // on a donc A(xa , ya) et B(xb, yb) + QPointF a = line().p1(); + QPointF b = line().p2(); + + // on calcule le vecteur AB : (xb-xa, yb-ya) + QPointF v_ab = b - a; + + // et la distance AB : racine des coordonnees du vecteur au carre + qreal ab = sqrt(pow(v_ab.x(), 2) + pow(v_ab.y(), 2)); + + // ensuite on definit le vecteur u(a, b) qui est egal au vecteur AB divise + // par sa longueur et multiplie par la longueur de la marge que tu veux + // laisser + QPointF u = v_ab / ab * 2.0; + + // on définit le vecteur v(-b , a) qui est perpendiculaire ŕ AB + QPointF v(-u.y(), u.x()); + QPointF m = -u + v; // on a le vecteur M = -u + v + QPointF n = -u - v; // et le vecteur N=-u-v + QPointF h = a + m; // H = A + M + QPointF k = a + n; // K = A + N + QPointF i = b - n; // I = B - N + QPointF j = b - m; // J = B - M + + QList result; + result << h << i << j << k; + return(result); +} + +QRectF PartLine::boundingRect() const { + qreal adjust = 1.5; + QRectF r(QGraphicsLineItem::boundingRect()); + r.adjust(-adjust, -adjust, adjust, adjust); + return(r); +} diff --git a/editor/partline.h b/editor/partline.h new file mode 100644 index 000000000..13b56aa6d --- /dev/null +++ b/editor/partline.h @@ -0,0 +1,37 @@ +#ifndef PART_LINE_H +#define PART_LINE_H +#include +#include "customelementgraphicpart.h" +class LineEditor; +class PartLine : public QGraphicsLineItem, public CustomElementGraphicPart { + // constructeurs, destructeur + public: + PartLine(QGraphicsItem * = 0, QGraphicsScene * = 0); + virtual ~PartLine() { + qDebug() << "~PartLine()"; + } + + private: + PartLine(const PartLine &); + + // attributs + private: + LineEditor *informations; + + // methodes + public: + virtual void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget * = 0); + virtual const QDomElement toXml(QDomDocument &) const; + virtual void fromXml(const QDomElement &); + virtual QPointF sceneP1() const; + virtual QPointF sceneP2() const; + virtual QPainterPath shape() const; + virtual QRectF boundingRect() const; + + protected: + QVariant itemChange(GraphicsItemChange, const QVariant &); + + private: + QList fourShapePoints() const; +}; +#endif diff --git a/editor/partpolygon.cpp b/editor/partpolygon.cpp new file mode 100644 index 000000000..f26bab61b --- /dev/null +++ b/editor/partpolygon.cpp @@ -0,0 +1,69 @@ +#include "partpolygon.h" +#include "qet.h" +#include "polygoneditor.h" +PartPolygon::PartPolygon(QGraphicsItem *parent, QGraphicsScene *scene) : + QGraphicsPolygonItem(parent, scene), + CustomElementGraphicPart(), + closed(false) +{ + setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable); + setAcceptedMouseButtons(Qt::LeftButton); + informations = new PolygonEditor(this); + style_editor -> appendWidget(informations); +} + +void PartPolygon::fromXml(const QDomElement &qde) { + stylesFromXml(qde); + int i = 1; + while(true) { + if ( + QET::attributeIsAReal(qde, QString("x%1").arg(i)) &&\ + QET::attributeIsAReal(qde, QString("y%1").arg(i)) + ) ++ i; + else break; + } + + QPolygonF temp_polygon; + for (int j = 1 ; j < i ; ++ j) { + temp_polygon << QPointF( + qde.attribute(QString("x%1").arg(j)).toDouble(), + qde.attribute(QString("y%1").arg(j)).toDouble() + ); + } + setPolygon(temp_polygon); + + closed = qde.attribute("closed") != "false"; +} + +const QDomElement PartPolygon::toXml(QDomDocument &xml_document) const { + QDomElement xml_element = xml_document.createElement("polygon"); + int i = 1; + foreach(QPointF point, polygon()) { + xml_element.setAttribute(QString("x%1").arg(i), point.x()); + xml_element.setAttribute(QString("y%1").arg(i), point.y()); + ++ i; + } + if (!closed) xml_element.setAttribute("closed", "false"); + stylesToXml(xml_element); + return(xml_element); +} + +void PartPolygon::paint(QPainter *painter, const QStyleOptionGraphicsItem */*q*/, QWidget */*w*/) { + applyStylesToQPainter(*painter); + QPen t = painter -> pen(); + if (isSelected()) { + t.setColor(Qt::red); + painter -> setPen(t); + } + if (closed) painter -> drawPolygon(polygon()); + else painter -> drawPolyline(polygon()); +} + +QVariant PartPolygon::itemChange(GraphicsItemChange change, const QVariant &value) { + if (scene()) { + if (change == QGraphicsItem::ItemPositionChange || change == QGraphicsItem::ItemSelectedChange) { + informations -> updateForm(); + } + } + return(QGraphicsPolygonItem::itemChange(change, value)); +} diff --git a/editor/partpolygon.h b/editor/partpolygon.h new file mode 100644 index 000000000..edf0880af --- /dev/null +++ b/editor/partpolygon.h @@ -0,0 +1,61 @@ +#ifndef PART_POLYGON_H +#define PART_POLYGON_H +#include +#include "customelementgraphicpart.h" +class PolygonEditor; +class PartPolygon : public QGraphicsPolygonItem, public CustomElementGraphicPart { + // constructeurs, destructeur + public: + PartPolygon(QGraphicsItem * = 0, QGraphicsScene * = 0); + virtual ~PartPolygon() { + qDebug() << "~PartPolygon()"; + } + + private: + PartPolygon(const PartPolygon &); + + // attributs + private: + bool closed; + PolygonEditor *informations; + + /** + constructeur + paint() + widget bidon pour l'edition + methode pour poser le polygone : + -mousePressEvent = pose un nouveau point + -mouseMoveEvent = deplace ce point + -mouveReleaseEvent = finalise ce point + utiliser QPolygonF ; memoriser le point en cours (tout comme le + partploygon en cours) et ne l'ajouter au qpolygonf que lors du + mouseReleaseEvent + */ + // methodes + public: + void fromXml(const QDomElement &); + const QDomElement toXml(QDomDocument &) const; + void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *); + void setClosed(bool c); + bool isClosed() const; + + protected: + QVariant itemChange(GraphicsItemChange, const QVariant &); +}; +/** + Specifie si le polygone doit etre ferme + @param c true pour un polygone ferme, false sinon +*/ +inline void PartPolygon::setClosed(bool c) { + closed = c; +} + +/** + Indique si le polygone est ferme + @return true si le polygone est ferme, false sinon +*/ +inline bool PartPolygon::isClosed() const { + return(closed); +} + +#endif diff --git a/editor/partterminal.cpp b/editor/partterminal.cpp new file mode 100644 index 000000000..4a547b9a7 --- /dev/null +++ b/editor/partterminal.cpp @@ -0,0 +1,117 @@ +#include "partterminal.h" +#include "terminal.h" +#include "terminaleditor.h" + +PartTerminal::PartTerminal(QGraphicsItem *parent, QGraphicsScene *scene) : + CustomElementPart(), + QGraphicsItem(parent, scene), + _orientation(QET::North) +{ + informations = new TerminalEditor(this); + updateSecondPoint(); + setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable); + setZValue(100000); +} + +PartTerminal::~PartTerminal() { + qDebug() << "~PartTerminal()"; + delete informations; +}; + +void PartTerminal::fromXml(const QDomElement &xml_elmt) { + // lit la position de la borne + qreal term_x = 0.0, term_y = 0.0; + QET::attributeIsAReal(xml_elmt, "x", &term_x); + QET::attributeIsAReal(xml_elmt, "y", &term_y); + setPos(QPointF(term_x, term_y)); + + // lit l'orientation de la borne + _orientation = QET::orientationFromString(xml_elmt.attribute("orientation")); + updateSecondPoint(); +} + +const QDomElement PartTerminal::toXml(QDomDocument &xml_document) const { + QDomElement xml_element = xml_document.createElement("terminal"); + + // ecrit la position de la borne + xml_element.setAttribute("x", QString("%1").arg(pos().x())); + xml_element.setAttribute("y", QString("%1").arg(pos().y())); + + // ecrit l'orientation de la borne + xml_element.setAttribute("orientation", orientationToString(_orientation)); + + return(xml_element); +} + +QWidget *PartTerminal::elementInformations() { + return(informations); +} + +void PartTerminal::paint(QPainter *p, const QStyleOptionGraphicsItem *, QWidget *) { + p -> save(); + + // annulation des renderhints + p -> setRenderHint(QPainter::Antialiasing, false); + p -> setRenderHint(QPainter::TextAntialiasing, false); + p -> setRenderHint(QPainter::SmoothPixmapTransform, false); + + QPen t; + t.setWidthF(1.0); + + // dessin de la borne en rouge + t.setColor(Qt::red); + p -> setPen(t); + p -> drawLine(QPointF(0.0, 0.0), second_point); + + // dessin du point d'amarrage au conducteur en bleu + t.setColor(Terminal::couleur_neutre); + p -> setPen(t); + p -> setBrush(Terminal::couleur_neutre); + p -> drawPoint(QPointF(0.0, 0.0)); + p -> restore(); +} + +QRectF PartTerminal::boundingRect() const { + QPointF p1, p2; + if (second_point.x() <= 0.0 && second_point.y() <= 0.0) { + p1 = second_point; + p2 = QPointF(0.0, 0.0); + } else { + p1 = QPointF(0.0, 0.0); + p2 = second_point; + } + QRectF br; + br.setTopLeft (p1 - QPointF(2.0, 2.0)); + br.setBottomRight(p2 + QPointF(2.0, 2.0)); + return(br); +} + +QET::Orientation PartTerminal::orientation() const { + return(_orientation); +} + +void PartTerminal::setOrientation(QET::Orientation ori) { + prepareGeometryChange(); + _orientation = ori; + updateSecondPoint(); + informations -> updateForm(); +} + +QVariant PartTerminal::itemChange(GraphicsItemChange change, const QVariant &value) { + if (scene()) { + if (change == QGraphicsItem::ItemPositionChange || change == QGraphicsItem::ItemSelectedChange) { + informations -> updateForm(); + } + } + return(QGraphicsItem::itemChange(change, value)); +} + +void PartTerminal::updateSecondPoint() { + qreal ts = 4.0; // terminal size + switch(_orientation) { + case QET::North: second_point = QPointF(0.0, ts); break; + case QET::East : second_point = QPointF(-ts, 0.0); break; + case QET::South: second_point = QPointF(0.0, -ts); break; + case QET::West : second_point = QPointF(ts, 0.0); break; + } +} diff --git a/editor/partterminal.h b/editor/partterminal.h new file mode 100644 index 000000000..00f49514d --- /dev/null +++ b/editor/partterminal.h @@ -0,0 +1,37 @@ +#ifndef PART_TERMINAL_H +#define PART_TERMINAL_H +#include "customelementpart.h" +#include "qet.h" +#include +class TerminalEditor; +class PartTerminal : public CustomElementPart, public QGraphicsItem { + public: + // constructeurs, destructeur + PartTerminal(QGraphicsItem * = 0, QGraphicsScene * = 0); + virtual ~PartTerminal(); + private: + PartTerminal(const PartTerminal &); + + // attributs + private: + QET::Orientation _orientation; + QPointF second_point; + TerminalEditor *informations; + + // methodes + public: + virtual void fromXml(const QDomElement &); + virtual const QDomElement toXml(QDomDocument &) const; + virtual QWidget *elementInformations(); + virtual void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *); + virtual QRectF boundingRect() const; + QET::Orientation orientation() const; + void setOrientation(QET::Orientation); + + protected: + QVariant itemChange(GraphicsItemChange, const QVariant &); + + private: + void updateSecondPoint(); +}; +#endif diff --git a/editor/parttext.cpp b/editor/parttext.cpp new file mode 100644 index 000000000..a49e8fb3f --- /dev/null +++ b/editor/parttext.cpp @@ -0,0 +1,104 @@ +#include "parttext.h" +#include "texteditor.h" + +PartText::PartText(QGraphicsItem *parent, QGraphicsScene *scene) : QGraphicsTextItem(parent, scene), CustomElementPart(), can_check_changes(true) { + setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable); + setPlainText(tr("T")); + infos = new TextEditor(this); +} + +PartText::~PartText() { + qDebug() << "~PartText()"; + delete infos; +} + +void PartText::fromXml(const QDomElement &xml_element) { + bool ok; + int font_size = xml_element.attribute("size").toInt(&ok); + if (!ok || font_size < 1) font_size = 20; + + setFont(QFont(QString("Sans Serif"), font_size)); + setPlainText(xml_element.attribute("text")); + setPos( + xml_element.attribute("x").toDouble(), + xml_element.attribute("y").toDouble() + ); +} + +const QDomElement PartText::toXml(QDomDocument &xml_document) const { + QDomElement xml_element = xml_document.createElement("text"); + xml_element.setAttribute("x", QString("%1").arg(pos().x())); + xml_element.setAttribute("y", QString("%1").arg(pos().y())); + xml_element.setAttribute("text", toPlainText()); + xml_element.setAttribute("size", font().pointSize()); + return(xml_element); +} + +QWidget *PartText::elementInformations() { + return(infos); +} + +/** + Retourne la position du texte, l'origine etant le point en bas a gauche du + texte (et pas du cadre) + @return la position du texte +*/ +QPointF PartText::pos() const { + return(QGraphicsTextItem::pos() + margin()); +} + +void PartText::setPos(const QPointF &left_corner_pos) { + QGraphicsTextItem::setPos(left_corner_pos - margin()); +} + +void PartText::setPos(qreal x, qreal y) { + QGraphicsTextItem::setPos(QPointF(x, y) - margin()); +} + +/** + @return Les coordonnees du point situe en bas a gauche du texte. +*/ +QPointF PartText::margin() const { + QFont used_font = font(); + QFontMetrics qfm(used_font); + QPointF margin( + (boundingRect().width () - qfm.width(toPlainText())) / 2.0, + ((boundingRect().height() - used_font.pointSizeF()) / 3.0) + used_font.pointSizeF() + ); + return(margin); +} + +/** + Permet a l'element texte de redevenir deplacable a la fin de l'edition de texte + @param e Le QFocusEvent decrivant la perte de focus +*/ +void PartText::focusOutEvent(QFocusEvent *e) { + QGraphicsTextItem::focusOutEvent(e); + setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable); +} + +/** + Permet a l'element texte de devenir editable lorsqu'on double-clique dessus + @param e Le QGraphicsSceneMouseEvent qui decrit le double-clic +*/ +void PartText::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *e) { + setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsFocusable); + setTextInteractionFlags(Qt::TextEditorInteraction); + QGraphicsTextItem::mouseDoubleClickEvent(e); + setFocus(Qt::MouseFocusReason); +} + +QVariant PartText::itemChange(GraphicsItemChange change, const QVariant &value) { + if (scene() && can_check_changes) { + if (change == QGraphicsItem::ItemPositionChange || change == QGraphicsItem::ItemSelectedChange) { + infos -> updateForm(); + } + } + return(QGraphicsTextItem::itemChange(change, value)); +} + +QRectF PartText::boundingRect() const { + QRectF r = QGraphicsTextItem::boundingRect(); + r.adjust(0.0, -2.0, 0.0, 0.0); + return(r); +} diff --git a/editor/parttext.h b/editor/parttext.h new file mode 100644 index 000000000..323d72355 --- /dev/null +++ b/editor/parttext.h @@ -0,0 +1,39 @@ +#ifndef PART_TEXT +#define PART_TEXT +#include +#include "customelementgraphicpart.h" +class TextEditor; +class PartText : public QGraphicsTextItem, public CustomElementPart { + // constructeurs, destructeur + public: + PartText(QGraphicsItem * = 0, QGraphicsScene * = 0); + virtual ~PartText(); + + private: + PartText(const PartText &); + + // attributs + TextEditor *infos; + + // methodes + public: + void fromXml(const QDomElement &); + const QDomElement toXml(QDomDocument &) const; + QWidget *elementInformations(); + QPointF pos() const; + void setPos(const QPointF &); + void setPos(qreal, qreal); + + protected: + virtual void focusOutEvent(QFocusEvent *); + virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *); + virtual QVariant itemChange(GraphicsItemChange, const QVariant &); + QRectF boundingRect() const; + + public: + bool can_check_changes; + + private: + QPointF margin() const; +}; +#endif diff --git a/editor/polygoneditor.cpp b/editor/polygoneditor.cpp new file mode 100644 index 000000000..4415befb5 --- /dev/null +++ b/editor/polygoneditor.cpp @@ -0,0 +1,89 @@ +#include "polygoneditor.h" +#include "partpolygon.h" + +/** + Constructeur + @param p Le polygone a editer + @param parent le Widget parent +*/ +PolygonEditor::PolygonEditor(PartPolygon *p, QWidget *parent) : + QWidget(parent), + points_list(this), + close_polygon(tr("Polygone ferm\351"), this) +{ + part = p; + // prepare la liste de points + points_list.setColumnCount(2); + QStringList headers; + headers << tr("x") << tr("y"); + points_list.setHeaderLabels(headers); + points_list.setRootIsDecorated(false); + updateForm(); + + // layout + QVBoxLayout *layout = new QVBoxLayout(this); + layout -> addWidget(new QLabel(tr("Points du polygone :"))); + layout -> addWidget(&points_list); + layout -> addWidget(&close_polygon); + + // connexions signaux/slots + connect(&close_polygon, SIGNAL(stateChanged(int)), this, SLOT(updatePolygonClosedState())); + connect(&points_list, SIGNAL(itemChanged(QTreeWidgetItem *, int)), this, SLOT(validColumn(QTreeWidgetItem *, int))); +} + +void PolygonEditor::updatePolygon() { + updatePolygonPoints(); + updatePolygonClosedState(); +} + +void PolygonEditor::updatePolygonPoints() { + QVector points = getPointsFromTree(); + if (points.count() < 2) { + QMessageBox::warning( + this, + tr("Erreur"), + tr("Le polygone doit comporter au moins deux points.") + ); + return; + } + part -> setPolygon(points); +} + +void PolygonEditor::updatePolygonClosedState() { + part -> setClosed(close_polygon.isChecked()); +} + +void PolygonEditor::updateForm() { + while(points_list.takeTopLevelItem(0)); + foreach(QPointF point, part -> polygon()) { + point = part -> mapToScene(point); + QStringList qsl; + qsl << QString("%1").arg(point.x()) << QString("%1").arg(point.y()); + QTreeWidgetItem *qtwi = new QTreeWidgetItem(qsl); + qtwi -> setFlags(Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable); + points_list.addTopLevelItem(qtwi); + } + close_polygon.setChecked(part -> isClosed()); +} + +QVector PolygonEditor::getPointsFromTree() { + QVector points; + for(int i = 0 ; i < points_list.topLevelItemCount() ; ++ i) { + QTreeWidgetItem *qtwi = points_list.topLevelItem(i); + bool x_convert_ok, y_convert_ok; + qreal x = qtwi -> text(0).toDouble(&x_convert_ok); + qreal y = qtwi -> text(1).toDouble(&y_convert_ok); + if (!x_convert_ok || !y_convert_ok) continue; + points << part -> mapFromScene(QPointF(x, y)); + } + return(points); +} + +void PolygonEditor::validColumn(QTreeWidgetItem *qtwi, int column) { + bool convert_ok; + qtwi -> text(column).toDouble(&convert_ok); + if (convert_ok) { + points_list.closePersistentEditor(qtwi, column); + updatePolygonPoints(); + } else points_list.openPersistentEditor(qtwi, column); +} diff --git a/editor/polygoneditor.h b/editor/polygoneditor.h new file mode 100644 index 000000000..0e0b8588b --- /dev/null +++ b/editor/polygoneditor.h @@ -0,0 +1,35 @@ +#ifndef POLYGON_EDITOR_H +#define POLYGON_EDITOR_H +#include +class PartPolygon; +class PolygonEditor : public QWidget { + + Q_OBJECT + + // constructeurs, destructeur + public: + PolygonEditor(PartPolygon *, QWidget * = 0); + ~PolygonEditor() { + qDebug() << "~PolygonEditor()"; + } + private: + PolygonEditor(const PolygonEditor &); + + // attributs + private: + PartPolygon *part; + QTreeWidget points_list; + QCheckBox close_polygon; + + // methodes + private: + QVector getPointsFromTree(); + + public slots: + void updatePolygon(); + void updatePolygonPoints(); + void updatePolygonClosedState(); + void updateForm(); + void validColumn(QTreeWidgetItem *qtwi, int column); +}; +#endif diff --git a/editor/qet.cpp b/editor/qet.cpp new file mode 100644 index 000000000..88563119c --- /dev/null +++ b/editor/qet.cpp @@ -0,0 +1,125 @@ +#include "qet.h" + +/** + Permet de convertir une chaine de caracteres ("n", "s", "e" ou "w") + en orientation. Si la chaine fait plusieurs caracteres, seul le + premier est pris en compte. En cas d'incoherence, QET::North est + retourne. + @param s Chaine de caractere cense representer une orientation + @return l'orientation designee par la chaine de caractere +*/ +QET::Orientation QET::orientationFromString(const QString &s) { + QChar c = s[0]; + if (c == 'e') return(QET::East); + else if (c == 's') return(QET::South); + else if (c == 'w') return (QET::West); + else return(QET::North); +} + +/** + @param o une orientation + @return une chaine de caractere representant l'orientation +*/ +QString QET::orientationToString(QET::Orientation o) { + QString ret; + switch(o) { + case QET::North: ret = "n"; break; + case QET::East : ret = "e"; break; + case QET::South: ret = "s"; break; + case QET::West : ret = "w"; break; + } + return(ret); +} + +/** + Indique si deux orientations de Borne sont sur le meme axe (Vertical / Horizontal). + @param a La premiere orientation de Borne + @param b La seconde orientation de Borne + @return Un booleen a true si les deux orientations de bornes sont sur le meme axe +*/ +bool QET::surLeMemeAxe(QET::Orientation a, QET::Orientation b) { + if ((a == QET::North || a == QET::South) && (b == QET::North || b == QET::South)) return(true); + else if ((a == QET::East || a == QET::West) && (b == QET::East || b == QET::West)) return(true); + else return(false); +} + +/** + Indique si une orientation de borne est horizontale (Est / Ouest). + @param a L'orientation de borne + @return True si l'orientation de borne est horizontale, false sinon +*/ +bool QET::estHorizontale(QET::Orientation a) { + return(a == QET::East || a == QET::West); +} + +/** + Indique si une orientation de borne est verticale (Nord / Sud). + @param a L'orientation de borne + @return True si l'orientation de borne est verticale, false sinon +*/ +bool QET::estVerticale(QET::Orientation a) { + return(a == QET::North || a == QET::South); +} + +/** + Permet de connaitre l'orientation suivante apres celle donnee en parametre. + Les orientations sont generalement presentees dans l'ordre suivant : Nord, + Est, Sud, Ouest. + @param o une orientation + @return l'orientation suivante +*/ +QET::Orientation QET::nextOrientation(QET::Orientation o) { + if (o < 0 || o > 2) return(QET::North); + return((QET::Orientation)(o + 1)); +} + +/** + Permet de connaitre l'orientation precedant celle donnee en parametre. + Les orientations sont generalement presentees dans l'ordre suivant : Nord, + Est, Sud, Ouest. + @param o une orientation + @return l'orientation precedente +*/ +QET::Orientation QET::previousOrientation(QET::Orientation o) { + if (o < 0 || o > 3) return(QET::North); + if (o == QET::North) return(QET::West); + return((QET::Orientation)(o - 1)); +} + +/** + Permet de savoir si l'attribut nom_attribut d'un element XML e est bien un + entier. Si oui, sa valeur est copiee dans entier. + @param e Element XML + @param nom_attribut Nom de l'attribut a analyser + @param entier Pointeur facultatif vers un entier + @return true si l'attribut est bien un entier, false sinon +*/ +bool QET::attributeIsAnInteger(const QDomElement &e, QString nom_attribut, int *entier) { + // verifie la presence de l'attribut + if (!e.hasAttribute(nom_attribut)) return(false); + // verifie la validite de l'attribut + bool ok; + int tmp = e.attribute(nom_attribut).toInt(&ok); + if (!ok) return(false); + if (entier != NULL) *entier = tmp; + return(true); +} + +/** + Permet de savoir si l'attribut nom_attribut d'un element XML e est bien un + reel. Si oui, sa valeur est copiee dans reel. + @param e Element XML + @param nom_attribut Nom de l'attribut a analyser + @param reel Pointeur facultatif vers un double + @return true si l'attribut est bien un reel, false sinon +*/ +bool QET::attributeIsAReal(const QDomElement &e, QString nom_attribut, double *reel) { + // verifie la presence de l'attribut + if (!e.hasAttribute(nom_attribut)) return(false); + // verifie la validite de l'attribut + bool ok; + qreal tmp = e.attribute(nom_attribut).toDouble(&ok); + if (!ok) return(false); + if (reel != NULL) *reel = tmp; + return(true); +} diff --git a/editor/styleeditor.cpp b/editor/styleeditor.cpp new file mode 100644 index 000000000..70724c91d --- /dev/null +++ b/editor/styleeditor.cpp @@ -0,0 +1,121 @@ +#include "styleeditor.h" +#include "customelementgraphicpart.h" + +StyleEditor::StyleEditor(CustomElementGraphicPart *p, QWidget *parent) : QWidget(parent), part(p) { + // couleur + color = new QButtonGroup(this); + color -> addButton(black_color = new QRadioButton(tr("Noir")), CustomElementGraphicPart::BlackColor); + color -> addButton(white_color = new QRadioButton(tr("Blanc")), CustomElementGraphicPart::WhiteColor); + connect(color, SIGNAL(buttonClicked(int)), this, SLOT(updatePart())); + + // style + style = new QButtonGroup(this); + style -> addButton(normal_style = new QRadioButton(tr("Normal")), CustomElementGraphicPart::NormalStyle); + style -> addButton(dashed_style = new QRadioButton(tr("Pointill\351")), CustomElementGraphicPart::DashedStyle); + style -> button(part -> lineStyle()) -> setChecked(true); + connect(style, SIGNAL(buttonClicked(int)), this, SLOT(updatePart())); + + // epaisseur + weight = new QButtonGroup(this); + weight -> addButton(none_weight = new QRadioButton(tr("Nulle")), CustomElementGraphicPart::NoneWeight); + weight -> addButton(thin_weight = new QRadioButton(tr("Fine")), CustomElementGraphicPart::ThinWeight); + weight -> addButton(normal_weight = new QRadioButton(tr("Normale")), CustomElementGraphicPart::NormalWeight); + connect(weight, SIGNAL(buttonClicked(int)), this, SLOT(updatePart())); + + // remplissage + filling = new QButtonGroup(this); + filling -> addButton(no_filling = new QRadioButton(tr("Aucun")), CustomElementGraphicPart::NoneFilling ); + filling -> addButton(black_filling = new QRadioButton(tr("Noir")), CustomElementGraphicPart::BlackFilling); + filling -> addButton(white_filling = new QRadioButton(tr("Blanc")), CustomElementGraphicPart::WhiteFilling); + connect(filling, SIGNAL(buttonClicked(int)), this, SLOT(updatePart())); + + // antialiasing + antialiasing = new QCheckBox(tr("Antialiasing")); + connect(antialiasing, SIGNAL(stateChanged(int)), this, SLOT(updatePart())); + + updateForm(); + + main_layout = new QVBoxLayout(); + main_layout -> addWidget(antialiasing); + + main_layout -> addWidget(new QLabel("" + tr("Trait :") + " ")); + + QHBoxLayout *color_layout = new QHBoxLayout(); + color_layout -> addWidget(new QLabel(tr("Couleur : "))); + color_layout -> addWidget(black_color); + color_layout -> addWidget(white_color); + color_layout -> addStretch(); + main_layout -> addItem(color_layout); + + QHBoxLayout *style_layout = new QHBoxLayout(); + style_layout -> addWidget(new QLabel(tr("Style : "))); + style_layout -> addWidget(normal_style); + style_layout -> addWidget(dashed_style); + style_layout -> addStretch(); + main_layout -> addItem(style_layout); + + QHBoxLayout *weight_layout = new QHBoxLayout(); + weight_layout -> addWidget(new QLabel(tr("\311paisseur : "))); + weight_layout -> addWidget(none_weight); + weight_layout -> addWidget(thin_weight); + weight_layout -> addWidget(normal_weight); + weight_layout -> addStretch(); + main_layout -> addItem(weight_layout); + + main_layout -> addWidget(new QLabel("" + tr("Remplissage :") + " ")); + + QHBoxLayout *filling_layout = new QHBoxLayout(); + filling_layout -> addWidget(no_filling); + filling_layout -> addWidget(black_filling); + filling_layout -> addWidget(white_filling); + filling_layout -> addStretch(); + main_layout -> addItem(filling_layout); + + main_layout -> addStretch(); + + setLayout(main_layout); +} + +StyleEditor::~StyleEditor() { + qDebug() << "~StyleEditor()"; +} + +void StyleEditor::updatePart() { + // applique l'antialiasing + part -> setAntialiased(antialiasing -> isChecked()); + + // applique la couleur + part -> setColor(static_cast(color -> checkedId())); + + // applique le style + part -> setLineStyle(static_cast(style -> checkedId())); + + // applique l'epaisseur + part -> setLineWeight(static_cast(weight -> checkedId())); + + // applique le remplissage + part -> setFilling(static_cast(filling -> checkedId())); +} + +void StyleEditor::updateForm() { + // lit l'antialiasing : deconnexion du slot pour eviter l'appel a updatePart() + disconnect(antialiasing, SIGNAL(stateChanged(int)), this, SLOT(updatePart())); + antialiasing -> setChecked(part -> antialiased()); + connect(antialiasing, SIGNAL(stateChanged(int)), this, SLOT(updatePart())); + + // lit la couleur + color -> button(part -> color()) -> setChecked(true); + + // lit le style + style -> button(part -> lineStyle()) -> setChecked(true); + + // lit l'epaisseur + weight -> button(part -> lineWeight()) -> setChecked(true); + + // lit le remplissage + filling -> button(part -> filling()) -> setChecked(true); +} + +void StyleEditor::appendWidget(QWidget *w) { + main_layout -> insertWidget(7, w); +} diff --git a/editor/styleeditor.h b/editor/styleeditor.h new file mode 100644 index 000000000..0fc4e5773 --- /dev/null +++ b/editor/styleeditor.h @@ -0,0 +1,33 @@ +#ifndef STYLE_EDITOR_H +#define STYLE_EDITOR_H +#include +class CustomElementGraphicPart; +class StyleEditor : public QWidget { + Q_OBJECT + // constructeurs, destructeur + public: + StyleEditor(CustomElementGraphicPart *, QWidget * = 0); + virtual ~StyleEditor(); + + private: + StyleEditor(const StyleEditor &); + + // attributs + private: + CustomElementGraphicPart *part; + QVBoxLayout *main_layout; + QButtonGroup *color, *style, *weight, *filling; + QRadioButton *black_color, *white_color, *normal_style, *dashed_style; + QRadioButton *none_weight, *thin_weight, *normal_weight, *no_filling; + QRadioButton *black_filling, *white_filling; + QCheckBox *antialiasing; + + //methodes + public: + void appendWidget(QWidget *w); + + public slots: + void updatePart(); + void updateForm(); +}; +#endif diff --git a/editor/terminaleditor.cpp b/editor/terminaleditor.cpp new file mode 100644 index 000000000..911daed95 --- /dev/null +++ b/editor/terminaleditor.cpp @@ -0,0 +1,67 @@ +#include "terminaleditor.h" +#include "partterminal.h" + +/** + Constructeur + @param term Borne a editer + @param parent QWidget parent de ce widget +*/ +TerminalEditor::TerminalEditor(PartTerminal *term, QWidget *parent) : QWidget(parent) { + part = term; + + qle_x = new QLineEdit(); + qle_y = new QLineEdit(); + + orientation = new QComboBox(); + orientation -> addItem(QIcon(":/ico/north.png"), tr("Nord"), QET::North); + orientation -> addItem(QIcon(":/ico/east.png"), tr("Est"), QET::East); + orientation -> addItem(QIcon(":/ico/south.png"), tr("Sud"), QET::South); + orientation -> addItem(QIcon(":/ico/west.png"), tr("Ouest"), QET::West); + + QVBoxLayout *main_layout = new QVBoxLayout(); + main_layout -> addWidget(new QLabel(tr("Postion : "))); + + QHBoxLayout *position = new QHBoxLayout(); + position -> addWidget(new QLabel(tr("x : "))); + position -> addWidget(qle_x ); + position -> addWidget(new QLabel(tr("y : "))); + position -> addWidget(qle_y ); + main_layout -> addLayout(position); + + QHBoxLayout *ori = new QHBoxLayout(); + ori -> addWidget(new QLabel(tr("Orientation : "))); + ori -> addWidget(orientation ); + main_layout -> addLayout(ori); + main_layout -> addStretch(); + setLayout(main_layout); + + connect(qle_x, SIGNAL(textEdited(const QString &)), this, SLOT(updateTerminal())); + connect(qle_y, SIGNAL(textEdited(const QString &)), this, SLOT(updateTerminal())); + connect(orientation, SIGNAL(activated(int)), this, SLOT(updateTerminal())); + + updateForm(); +} + +/** + Destructeur +*/ +TerminalEditor::~TerminalEditor() { + qDebug() << "~TerminalEditor()"; +}; + +void TerminalEditor::updateTerminal() { + part -> setPos(qle_x -> text().toDouble(), qle_y -> text().toDouble()); + part -> setOrientation( + static_cast( + orientation -> itemData( + orientation -> currentIndex() + ).toInt() + ) + ); +} + +void TerminalEditor::updateForm() { + qle_x -> setText(QString("%1").arg(part -> pos().x())); + qle_y -> setText(QString("%1").arg(part -> pos().y())); + orientation -> setCurrentIndex(static_cast(part -> orientation())); +} diff --git a/editor/terminaleditor.h b/editor/terminaleditor.h new file mode 100644 index 000000000..12316d2d7 --- /dev/null +++ b/editor/terminaleditor.h @@ -0,0 +1,30 @@ +#ifndef TERMINAL_EDITOR_H +#define TERMINAL_EDITOR_H +#include +class PartTerminal; +/** + Cette classe represente un editeur de borne. + Elle permet d'editer a travers une interface graphique les + proprietes d'une borne d'element. +*/ +class TerminalEditor : public QWidget { + Q_OBJECT + // Constructeurs, destructeur + public: + TerminalEditor(PartTerminal *, QWidget * = 0); + virtual ~TerminalEditor(); + private: + TerminalEditor(const TerminalEditor &); + + // attributs + private: + PartTerminal *part; + QLineEdit *qle_x, *qle_y; + QComboBox *orientation; + + // methodes + public slots: + void updateTerminal(); + void updateForm(); +}; +#endif diff --git a/editor/texteditor.cpp b/editor/texteditor.cpp new file mode 100644 index 000000000..d2cee729b --- /dev/null +++ b/editor/texteditor.cpp @@ -0,0 +1,68 @@ +#include "texteditor.h" +#include "parttext.h" + +/** + Constructeur + @param term Champ de texte a editer + @param parent QWidget parent de ce widget +*/ +TextEditor::TextEditor(PartText *text, QWidget *parent) : QWidget(parent) { + part = text; + + qle_x = new QLineEdit(); + qle_y = new QLineEdit(); + qle_text = new QLineEdit(); + font_size = new QSpinBox(); + font_size -> setRange(0, 144); + + QVBoxLayout *main_layout = new QVBoxLayout(); + main_layout -> addWidget(new QLabel(tr("Postion : "))); + + QHBoxLayout *position = new QHBoxLayout(); + position -> addWidget(new QLabel(tr("x : "))); + position -> addWidget(qle_x ); + position -> addWidget(new QLabel(tr("y : "))); + position -> addWidget(qle_y ); + main_layout -> addLayout(position); + + QHBoxLayout *fs = new QHBoxLayout(); + fs -> addWidget(new QLabel(tr("Taille : "))); + fs -> addWidget(font_size); + main_layout -> addLayout(fs); + + QHBoxLayout *t = new QHBoxLayout(); + t -> addWidget(new QLabel(tr("Texte : "))); + t -> addWidget(qle_text); + main_layout -> addLayout(t); + main_layout -> addStretch(); + setLayout(main_layout); + + connect(qle_x, SIGNAL(textEdited(const QString &)), this, SLOT(updateText())); + connect(qle_y, SIGNAL(textEdited(const QString &)), this, SLOT(updateText())); + connect(qle_text, SIGNAL(textEdited(const QString &)), this, SLOT(updateText())); + connect(font_size, SIGNAL(valueChanged(int)), this, SLOT(updateText())); + + //updateForm(); +} + +/** + Destructeur +*/ +TextEditor::~TextEditor() { + qDebug() << "~TextEditor()"; +} + +void TextEditor::updateText() { + part -> can_check_changes = false; + part -> setFont(QFont(part -> font().family(), font_size -> value())); + part -> setPlainText(qle_text -> text()); + part -> setPos(qle_x -> text().toDouble(), qle_y -> text().toDouble()); + part -> can_check_changes = true; +} + +void TextEditor::updateForm() { + qle_x -> setText(QString("%1").arg(part -> pos().x())); + qle_y -> setText(QString("%1").arg(part -> pos().y())); + qle_text -> setText(part -> toPlainText()); + font_size -> setValue(part -> font().pointSize()); +} diff --git a/editor/texteditor.h b/editor/texteditor.h new file mode 100644 index 000000000..d312b6d53 --- /dev/null +++ b/editor/texteditor.h @@ -0,0 +1,30 @@ +#ifndef TEXT_EDITOR_H +#define TEXT_EDITOR_H +#include +class PartText; +/** + Cette classe represente un editeur de champ de texte non editable + Elle permet d'editer a travers une interface graphique les + proprietes d'un champ de texte non editable. +*/ +class TextEditor : public QWidget { + Q_OBJECT + // Constructeurs, destructeur + public: + TextEditor(PartText *, QWidget * = 0); + virtual ~TextEditor(); + private: + TextEditor(const TextEditor &); + + // attributs + private: + PartText *part; + QLineEdit *qle_x, *qle_y, *qle_text; + QSpinBox *font_size; + + // methodes + public slots: + void updateText(); + void updateForm(); +}; +#endif diff --git a/element.cpp b/element.cpp index 380652a39..a03ed8133 100644 --- a/element.cpp +++ b/element.cpp @@ -123,14 +123,14 @@ QVariant Element::itemChange(GraphicsItemChange change, const QVariant &value) { @param o la nouvelle orientation de l'objet @return true si l'orientation a pu etre appliquee, false sinon */ -bool Element::setOrientation(Terminal::Orientation o) { +bool Element::setOrientation(QET::Orientation o) { // verifie que l'orientation demandee est acceptee - if (!acceptOrientation(o)) return(false); + if (!ori.accept(o)) return(false); prepareGeometryChange(); // rotation en consequence et rafraichissement de l'element graphique - qreal rotation_value = 90.0 * (o - ori); + qreal rotation_value = 90.0 * (o - ori.current()); rotate(rotation_value); - ori = o; + ori.setCurrent(o); update(); foreach(QGraphicsItem *qgi, children()) { if (Terminal *p = qgraphicsitem_cast(qgi)) p -> updateConducer(); @@ -353,8 +353,8 @@ bool Element::fromXml(QDomElement &e, QHash &table_id_adr) { setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable); bool conv_ok; int read_ori = e.attribute("orientation").toInt(&conv_ok); - if (!conv_ok || read_ori < 0 || read_ori > 3) read_ori = defaultOrientation(); - setOrientation((Terminal::Orientation)read_ori); + if (!conv_ok || read_ori < 0 || read_ori > 3) read_ori = ori.defaultOrientation(); + setOrientation((QET::Orientation)read_ori); setSelected(e.attribute("selected") == "selected"); return(true); @@ -380,7 +380,7 @@ QDomElement Element::toXml(QDomDocument &document, QHash &table element.setAttribute("x", pos().x()); element.setAttribute("y", pos().y()); if (isSelected()) element.setAttribute("selected", "selected"); - element.setAttribute("orientation", QString("%1").arg(orientation())); + element.setAttribute("orientation", QString("%1").arg(ori.current())); /* recupere le premier id a utiliser pour les bornes de cet element */ int id_terminal = 0; diff --git a/element.h b/element.h index 1a1efd389..5a7f0a87a 100644 --- a/element.h +++ b/element.h @@ -2,6 +2,7 @@ #define ELEMENT_H #include #include "terminal.h" +#include "orientationset.h" /** Cette classe abstraite represente un element electrique. */ @@ -21,12 +22,7 @@ class Element : public QGraphicsItem { enum { Type = UserType + 1000 }; protected: - bool ori_n; - bool ori_s; - bool ori_e; - bool ori_w; - Terminal::Orientation ori_d; - Terminal::Orientation ori; + OrientationSet ori; private: QSize dimensions; @@ -74,12 +70,8 @@ class Element : public QGraphicsItem { virtual QDomElement toXml(QDomDocument &, QHash&) const; // methodes d'acces aux possibilites d'orientation - Terminal::Orientation orientation() const; - Terminal::Orientation defaultOrientation() const; - bool acceptOrientation(Terminal::Orientation o) const; - Terminal::Orientation nextAcceptableOrientation() const; - Terminal::Orientation previousAcceptableOrientation() const; - bool setOrientation(Terminal::Orientation o); + bool setOrientation(QET::Orientation o); + const OrientationSet &orientation() const; protected: void drawAxes(QPainter *, const QStyleOptionGraphicsItem *); @@ -89,8 +81,6 @@ class Element : public QGraphicsItem { bool peut_relier_ses_propres_terminals; void drawSelection(QPainter *, const QStyleOptionGraphicsItem *); void updatePixmap(); - Terminal::Orientation nextOrientation(Terminal::Orientation o) const; - Terminal::Orientation previousOrientation(Terminal::Orientation o) const; static QList findInDomElement(QDomElement, QString, QString); }; @@ -117,85 +107,8 @@ inline void Element::setConnexionsInternesAcceptees(bool cia) { Permet de connaitre l'orientation actuelle de l'element @return L'orientation actuelle de l'element */ -inline Terminal::Orientation Element::orientation() const { +inline const OrientationSet & Element::orientation() const { return(ori); } -/** - Permet de savoir si l'element peut etre positionne dans une orientation - donnee. - @param o L'orientation en question - @return true si l'orientation est utilisable, false sinon -*/ -inline bool Element::acceptOrientation(Terminal::Orientation o) const { - switch(o) { - case Terminal::Nord: return(ori_n); - case Terminal::Est: return(ori_e); - case Terminal::Sud: return(ori_s); - case Terminal::Ouest: return(ori_w); - default: return(false); - } -} - -/** - Permet de connaitre l'orientation par defaut de l'element - @return l'orientation par defaut de l'element -*/ -inline Terminal::Orientation Element::defaultOrientation() const { - return(ori_d); -} - -/** - Permet de connaitre la prochaine orientation autorisee pour cet element - @return la prochaine orientation autorisee pour cet element -*/ -inline Terminal::Orientation Element::nextAcceptableOrientation() const { - Terminal::Orientation retour = nextOrientation(ori); - for (int i = 0 ; i < 4 ; ++ i) { - if (acceptOrientation(retour)) return(retour); - retour = nextOrientation(retour); - } - // on ne devrait pas arriver la : renvoi d'une valeur par defaut = nord - return(Terminal::Nord); -} - -/** - Permet de connaitre la precedente orientation autorisee pour cet element - @return la precedente orientation autorisee pour cet element -*/ -inline Terminal::Orientation Element::previousAcceptableOrientation() const { - Terminal::Orientation retour = previousOrientation(ori); - for (int i = 0 ; i < 4 ; ++ i) { - if (acceptOrientation(retour)) return(retour); - retour = previousOrientation(retour); - } - // on ne devrait pas arriver la : renvoi d'une valeur par defaut = nord - return(Terminal::Nord); -} - -/** - Permet de connaitre l'orientation suivante apres celle donnee en parametre. - Les orientations sont generalement presentees dans l'ordre suivant : Nord, - Est, Sud, Ouest. - @param o une orientation - @return l'orientation suivante -*/ -inline Terminal::Orientation Element::nextOrientation(Terminal::Orientation o) const { - if (o < 0 || o > 2) return(Terminal::Nord); - return((Terminal::Orientation)(o + 1)); -} - -/** - Permet de connaitre l'orientation precedant celle donnee en parametre. - Les orientations sont generalement presentees dans l'ordre suivant : Nord, - Est, Sud, Ouest. - @param o une orientation - @return l'orientation precedente -*/ -inline Terminal::Orientation Element::previousOrientation(Terminal::Orientation o) const { - if (o < 0 || o > 3) return(Terminal::Nord); - if (o == Terminal::Nord) return(Terminal::Ouest); - return((Terminal::Orientation)(o - 1)); -} - #endif diff --git a/elementscategory.cpp b/elementscategory.cpp index d5d6e6dc3..2d60031fb 100644 --- a/elementscategory.cpp +++ b/elementscategory.cpp @@ -135,3 +135,20 @@ bool ElementsCategory::remove() const { return(rmdir(absolutePath())); } +/** + @return true s'il est possible d'ecrire le fichier qet_directory dans la + categorie +*/ +bool ElementsCategory::isWritable() const { + // informations sur le dossier de la categorie + QFileInfo category(canonicalPath()); + QFileInfo qet_directory(canonicalPath() + "/.qet_directory"); + /* + soit .qet_directory n'existe pas et le dossier est accessible en ecriture, + soit .qet_directory existe et est accessible en ecriture + */ + return( + (!qet_directory.exists() && category.isWritable()) ||\ + (qet_directory.exists() && qet_directory.isWritable()) + ); +} diff --git a/elementscategory.h b/elementscategory.h index fb2194169..c8bf1bd13 100644 --- a/elementscategory.h +++ b/elementscategory.h @@ -28,6 +28,7 @@ class ElementsCategory : public QDir { void addName(const QString &, const QString &); bool write() const; bool remove() const; + bool isWritable() const; //bool move(const QString &new_parent); private: diff --git a/elementscategoryeditor.cpp b/elementscategoryeditor.cpp index 075570bc6..1172714f3 100644 --- a/elementscategoryeditor.cpp +++ b/elementscategoryeditor.cpp @@ -29,6 +29,16 @@ ElementsCategoryEditor::ElementsCategoryEditor(const QString &category_path, boo names_list -> setNames(cat_names); //names_list -> openPersistentEditor(qtwi, 1); } + + // gestion de la lecture seule + if (!category -> isWritable()) { + QMessageBox::warning( + this, + tr("\311dition en lecture seule"), + tr("Vous n'avez pas les privil\350ges n\351cessaires pour modifier cette cat\351gorie. Elle sera donc ouverte en lecture seule.") + ); + names_list -> setReadOnly(true); + } } /** @@ -60,6 +70,8 @@ void ElementsCategoryEditor::buildDialog() { categorie */ void ElementsCategoryEditor::acceptCreation() { + if (!category -> isWritable()) QDialog::accept(); + // il doit y avoir au moins un nom if (!names_list -> checkOneName()) return; @@ -83,6 +95,8 @@ void ElementsCategoryEditor::acceptCreation() { categorie */ void ElementsCategoryEditor::acceptUpdate() { + if (!category -> isWritable()) QDialog::accept(); + // il doit y avoir au moins un nom if (!names_list -> checkOneName()) return; diff --git a/elementspanel.cpp b/elementspanel.cpp index 737256adf..b056d4ce7 100644 --- a/elementspanel.cpp +++ b/elementspanel.cpp @@ -1,6 +1,8 @@ #include "elementspanel.h" -#include "customelement.h" #include "elementscategory.h" +#include "elementscategoryeditor.h" +#include "customelement.h" +#include "customelementeditor.h" /** Constructeur @@ -33,6 +35,9 @@ ElementsPanel::ElementsPanel(QWidget *parent) : QTreeWidget(parent) { qp.setColor(QPalette::Highlight, QColor("#678db2")); qp.setColor(QPalette::HighlightedText, Qt::white); setPalette(qp); + + // double-cliquer sur un element permet de l'editer + connect(this, SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)), this, SLOT(slot_doubleClick(QTreeWidgetItem *, int))); } /** @@ -114,6 +119,7 @@ void ElementsPanel::addDir(QTreeWidgetItem *qtwi_parent, QString adr_dossier, QS t.setColorAt(1, QColor("#ffffff")); qtwi_dossier -> setBackground(0, QBrush(t)); qtwi_dossier -> setExpanded(true); + qtwi_dossier -> setData(0, 42, adr_dossier); // ajout des sous-categories / sous-dossiers QStringList dossiers = category.entryList(QStringList(), QDir::AllDirs | QDir::NoSymLinks | QDir::NoDotAndDotDot, QDir::Name); @@ -160,3 +166,25 @@ void ElementsPanel::reload() { // chargement des elements de la collection utilisateur addDir(invisibleRootItem(), QETApp::customElementsDir(), tr("Collection utilisateur")); } + +void ElementsPanel::slot_doubleClick(QTreeWidgetItem *qtwi, int) { + // recupere le fichier ou le dossier correspondant au QTreeWidgetItem + QString filename = qtwi -> data(0, 42).toString(); + + // le fichier doit exister + QFileInfo infos_file(filename); + if (!infos_file.exists()) return; + + + if (infos_file.isFile()) { + // il s'agit d'un element + CustomElementEditor *cee = new CustomElementEditor(); + cee -> fromFile(filename); + cee -> show(); + } else if (infos_file.isDir()) { + // il s'agit d'une categorie + ElementsCategory c(filename); + ElementsCategoryEditor ece(filename, true); + if (ece.exec() == QDialog::Accepted) reload(); + } +} diff --git a/elementspanel.h b/elementspanel.h index 31e9f039a..c7bb510e9 100644 --- a/elementspanel.h +++ b/elementspanel.h @@ -24,6 +24,7 @@ class ElementsPanel : public QTreeWidget { void addDir(QTreeWidgetItem *, QString, QString = QString()); public slots: + void slot_doubleClick(QTreeWidgetItem *, int); void dragMoveEvent(QDragMoveEvent *); void dropEvent(QDropEvent *); void startDrag(Qt::DropActions); diff --git a/elementspanelwidget.cpp b/elementspanelwidget.cpp index 83a3a989d..37df6a2e3 100644 --- a/elementspanelwidget.cpp +++ b/elementspanelwidget.cpp @@ -35,6 +35,6 @@ ElementsPanelWidget::~ElementsPanelWidget() { Appelle l'assistant de creation de nouvel element */ void ElementsPanelWidget::newElement() { - NewElementWizard *new_element_wizard = new NewElementWizard(); - new_element_wizard -> exec(); + NewElementWizard new_element_wizard; + new_element_wizard.exec(); } diff --git a/ico/add_col.png b/ico/add_col.png new file mode 100755 index 000000000..02a70edf7 Binary files /dev/null and b/ico/add_col.png differ diff --git a/ico/allowed.png b/ico/allowed.png new file mode 100755 index 000000000..0e107887f Binary files /dev/null and b/ico/allowed.png differ diff --git a/ico/arc.png b/ico/arc.png new file mode 100644 index 000000000..9ca8d2d2b Binary files /dev/null and b/ico/arc.png differ diff --git a/ico/circle.png b/ico/circle.png new file mode 100644 index 000000000..ea47ef865 Binary files /dev/null and b/ico/circle.png differ diff --git a/ico/east.png b/ico/east.png new file mode 100644 index 000000000..3851c0cc5 Binary files /dev/null and b/ico/east.png differ diff --git a/ico/ellipse.png b/ico/ellipse.png new file mode 100644 index 000000000..93bea86d5 Binary files /dev/null and b/ico/ellipse.png differ diff --git a/ico/forbidden.png b/ico/forbidden.png new file mode 100755 index 000000000..98674ef54 Binary files /dev/null and b/ico/forbidden.png differ diff --git a/ico/line.png b/ico/line.png new file mode 100644 index 000000000..36e523fd0 Binary files /dev/null and b/ico/line.png differ diff --git a/ico/north.png b/ico/north.png new file mode 100644 index 000000000..0f13c06d6 Binary files /dev/null and b/ico/north.png differ diff --git a/ico/orientations.png b/ico/orientations.png new file mode 100644 index 000000000..9b982af54 Binary files /dev/null and b/ico/orientations.png differ diff --git a/ico/polygon.png b/ico/polygon.png new file mode 100644 index 000000000..cc558f3b3 Binary files /dev/null and b/ico/polygon.png differ diff --git a/ico/remove_col.png b/ico/remove_col.png new file mode 100755 index 000000000..9993b3740 Binary files /dev/null and b/ico/remove_col.png differ diff --git a/ico/south.png b/ico/south.png new file mode 100644 index 000000000..e9fba42a7 Binary files /dev/null and b/ico/south.png differ diff --git a/ico/terminal.png b/ico/terminal.png new file mode 100644 index 000000000..436455af1 Binary files /dev/null and b/ico/terminal.png differ diff --git a/ico/text.png b/ico/text.png new file mode 100644 index 000000000..7ea4eb4c4 Binary files /dev/null and b/ico/text.png differ diff --git a/ico/textfield.png b/ico/textfield.png new file mode 100644 index 000000000..f4ef84c73 Binary files /dev/null and b/ico/textfield.png differ diff --git a/ico/west.png b/ico/west.png new file mode 100644 index 000000000..8b6cc8a26 Binary files /dev/null and b/ico/west.png differ diff --git a/nameslistwidget.cpp b/nameslistwidget.cpp index 605546db4..dbc94371c 100644 --- a/nameslistwidget.cpp +++ b/nameslistwidget.cpp @@ -4,7 +4,7 @@ Constructeur @param parent QWidget parent de la liste de noms */ -NamesListWidget::NamesListWidget(QWidget *parent) : QWidget(parent) { +NamesListWidget::NamesListWidget(QWidget *parent) : QWidget(parent), read_only(false) { QVBoxLayout *names_list_layout = new QVBoxLayout(); setLayout(names_list_layout); @@ -32,6 +32,7 @@ NamesListWidget::~NamesListWidget() { */ void NamesListWidget::addLine() { clean(); + if (read_only) return; QTreeWidgetItem *qtwi = new QTreeWidgetItem(); qtwi -> setFlags(Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable); tree_names -> addTopLevelItem(qtwi); @@ -45,8 +46,8 @@ bool NamesListWidget::checkOneName() { if (!hash_names.count()) { QMessageBox::critical( this, - tr("La cat\351gorie doit avoir au moins un nom."), - tr("Vous devez entrer au moins un nom pour la cat\351gorie.") + tr("Il doit y avoir au moins un nom."), + tr("Vous devez entrer au moins un nom.") ); return(false); } @@ -62,7 +63,7 @@ void NamesListWidget::updateHash() { for (int i = 0 ; i < names_count ; ++ i) { QString lang = tree_names -> topLevelItem(i) -> text(0); QString value = tree_names -> topLevelItem(i) -> text(1); - hash_names.addName(lang, value); + if (lang != "" && value != "") hash_names.addName(lang, value); } } @@ -95,7 +96,25 @@ void NamesListWidget::setNames(const NamesList &provided_names) { QStringList values; values << lang << value; QTreeWidgetItem *qtwi = new QTreeWidgetItem(values); - qtwi -> setFlags(Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable); + if (!read_only) qtwi -> setFlags(Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable); tree_names -> addTopLevelItem(qtwi); } } + +void NamesListWidget::check() { + if (checkOneName()) emit(inputChecked()); +} + +void NamesListWidget::setReadOnly(bool ro) { + read_only = ro; + int names_count = tree_names -> topLevelItemCount() - 1; + for (int i = names_count ; i >= 0 ; -- i) { + Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable; + if (!read_only) flags |= Qt::ItemIsEditable; + tree_names -> topLevelItem(i) -> setFlags(flags); + } +} + +bool NamesListWidget::isReadOnly() const { + return(read_only); +} diff --git a/nameslistwidget.h b/nameslistwidget.h index a7c478206..90c444eb2 100644 --- a/nameslistwidget.h +++ b/nameslistwidget.h @@ -22,12 +22,15 @@ class NamesListWidget : public QWidget { QTreeWidget *tree_names; QPushButton *button_add_line; NamesList hash_names; + bool read_only; // methodes public: bool checkOneName(); NamesList names(); void setNames(const NamesList &); + void setReadOnly(bool); + bool isReadOnly() const; private: void clean(); @@ -35,5 +38,9 @@ class NamesListWidget : public QWidget { public slots: void addLine(); + void check(); + + signals: + void inputChecked(); }; #endif diff --git a/newelementwizard.cpp b/newelementwizard.cpp index 7c6c9057f..33c8044cd 100644 --- a/newelementwizard.cpp +++ b/newelementwizard.cpp @@ -2,8 +2,10 @@ #include "elementscategorieswidget.h" #include "elementscategorieslist.h" #include "nameslistwidget.h" +#include "orientationsetwidget.h" #include "diagram.h" #include "element.h" +#include "customelementeditor.h" /** Constructeur @@ -76,6 +78,7 @@ void NewElementWizard::previous() { case Names: current_state = Filename; step2 -> show(); + qle_filename -> setFocus(); step3 -> hide(); break; case Dimensions: @@ -102,6 +105,7 @@ void NewElementWizard::next() { current_state = Filename; step1 -> hide(); step2 -> show(); + qle_filename -> setFocus(); button_previous -> setEnabled(true); break; case Filename: @@ -158,7 +162,9 @@ void NewElementWizard::buildStep2() { explication2 -> setAlignment(Qt::AlignJustify | Qt::AlignVCenter); explication2 -> setWordWrap(true); step2_layout -> addWidget(explication1); - step2_layout -> addWidget(qle_filename = new QLineEdit()); + qle_filename = new QLineEdit(tr("nouvel_element")); + qle_filename -> selectAll(); + step2_layout -> addWidget(qle_filename); step2_layout -> addWidget(explication2); step2_layout -> addSpacing(100); step2 -> setLayout(step2_layout); @@ -266,37 +272,12 @@ void NewElementWizard::buildStep5() { explication -> setAlignment(Qt::AlignJustify | Qt::AlignVCenter); explication -> setWordWrap(true); - #define MK_COMBO_BOX(a) a##_orientation = new QComboBox(); \ - a##_orientation -> addItem(tr("Par d\351faut"), "d"); \ - a##_orientation -> addItem(tr("Possible"), "y"); \ - a##_orientation -> addItem(tr("Impossible"), "n"); - - // 4 combo box - MK_COMBO_BOX(north) - MK_COMBO_BOX(east) - MK_COMBO_BOX(south) - MK_COMBO_BOX(west) - - #undef MK_COMBO_BOX - - east_orientation -> setCurrentIndex(1); - south_orientation -> setCurrentIndex(1); - west_orientation -> setCurrentIndex(1); - - QGridLayout *qgl = new QGridLayout(); - qgl -> addWidget(new QLabel(tr("Nord :")), 0, 0); - qgl -> addWidget(north_orientation, 0, 1); - qgl -> addWidget(new QLabel(tr("Est :")), 1, 0); - qgl -> addWidget(east_orientation, 1, 1); - qgl -> addWidget(new QLabel(tr("Sud :")), 2, 0); - qgl -> addWidget(south_orientation, 2, 1); - qgl -> addWidget(new QLabel(tr("Ouest :")), 3, 0); - qgl -> addWidget(west_orientation, 3, 1); + orientation_set = new OrientationSetWidget(); QVBoxLayout *step5_layout = new QVBoxLayout(); step5_layout -> addWidget(explication); - step5_layout -> addLayout(qgl); - step5_layout -> addSpacing(75); + step5_layout -> addWidget(orientation_set); + step5_layout -> addSpacing(25); step5 -> setLayout(step5_layout); } @@ -349,6 +330,7 @@ bool NewElementWizard::validStep2() { return(answer == QMessageBox::Yes); } + chosen_file = dir_path + "/" + file_name; return(true); } @@ -377,19 +359,7 @@ bool NewElementWizard::validStep4() { @return true si l'etape est validee, false sinon */ bool NewElementWizard::validStep5() { - int nb_orientations = 0; - if (!north_orientation -> currentIndex()) ++ nb_orientations; - if (!east_orientation -> currentIndex()) ++ nb_orientations; - if (!south_orientation -> currentIndex()) ++ nb_orientations; - if (!west_orientation -> currentIndex()) ++ nb_orientations; - if (nb_orientations != 1) { - QMessageBox::critical( - this, - tr("Erreur"), - tr("Il doit y avoir exactement une orientation par d\351faut.") - ); - return(false); - } + // l'editeur d'orientations se charge deja de valider tout ca return(true); } @@ -445,6 +415,12 @@ void NewElementWizard::updateHotspotLimits() { Cree le nouvel element */ void NewElementWizard::createNewElement() { - /// @todo - QMessageBox::warning(this, "Creation de l'element", "Not Implemented Yet"); + CustomElementEditor *edit_new_element = new CustomElementEditor(parentWidget()); + edit_new_element -> setSize(QSize(sb_width -> value() * 10, sb_height -> value() * 10)); + edit_new_element -> setHotspot(QPoint(sb_hotspot_x -> value(), sb_hotspot_y -> value())); + edit_new_element -> setNames(element_names -> names()); + edit_new_element -> setOrientations(orientation_set -> orientationSet()); + edit_new_element -> setFileName(chosen_file); + edit_new_element -> show(); + accept(); } diff --git a/newelementwizard.h b/newelementwizard.h index 3355e61e7..fdf6fa971 100644 --- a/newelementwizard.h +++ b/newelementwizard.h @@ -14,6 +14,7 @@ */ class ElementsCategoriesWidget; class NamesListWidget; +class OrientationSetWidget; class Diagram; class NewElementWizard : public QDialog { Q_OBJECT @@ -38,6 +39,7 @@ class NewElementWizard : public QDialog { QSpinBox *sb_hotspot_x; QSpinBox *sb_hotspot_y; NamesListWidget *element_names; + OrientationSetWidget *orientation_set; QPushButton *button_previous; QPushButton *button_next; WizardState current_state; @@ -47,6 +49,7 @@ class NewElementWizard : public QDialog { QComboBox *east_orientation; QComboBox *south_orientation; QComboBox *west_orientation; + QString chosen_file; // methodes private: diff --git a/orientationset.cpp b/orientationset.cpp new file mode 100644 index 000000000..4eb5c322a --- /dev/null +++ b/orientationset.cpp @@ -0,0 +1,164 @@ +#include "orientationset.h" + +OrientationSet::OrientationSet() : + north_ori(true), + east_ori(true), + south_ori(true), + west_ori(true), + default_ori(QET::North), + current_ori(QET::North) +{} + +bool OrientationSet::setNorth (bool ori) { + // pour desactiver une orientation, il doit y avoir au moins une autre orientation possible + bool can_set_ori = ori ? true : east_ori || south_ori || west_ori; + if (can_set_ori) { + north_ori = ori; + // en cas de desactivation d'une orientation, il faut verifier voire corriger les orientations courante et par defaut + if (!ori) { + if (default_ori == QET::North) default_ori = next(); + if (current_ori == QET::North) current_ori = next(); + } + } + return(can_set_ori); +} + +bool OrientationSet::setEast (bool ori) { + // pour desactiver une orientation, il doit y avoir au moins une autre orientation possible + bool can_set_ori = ori ? true : south_ori || west_ori || north_ori; + if (can_set_ori) { + east_ori = ori; + // en cas de desactivation d'une orientation, il faut verifier voire corriger les orientations courante et par defaut + if (!ori) { + if (default_ori == QET::East) default_ori = next(); + if (current_ori == QET::East) current_ori = next(); + } + } + return(can_set_ori); +} + +bool OrientationSet::setSouth (bool ori) { + // pour desactiver une orientation, il doit y avoir au moins une autre orientation possible + bool can_set_ori = ori ? true : west_ori || north_ori || east_ori; + if (can_set_ori) { + south_ori = ori; + // en cas de desactivation d'une orientation, il faut verifier voire corriger les orientations courante et par defaut + if (!ori) { + if (default_ori == QET::South) default_ori = next(); + if (current_ori == QET::South) current_ori = next(); + } + } + return(can_set_ori); +} + +bool OrientationSet::setWest (bool ori) { + // pour desactiver une orientation, il doit y avoir au moins une autre orientation possible + bool can_set_ori = ori ? true : north_ori || east_ori || south_ori; + if (can_set_ori) { + west_ori = ori; + // en cas de desactivation d'une orientation, il faut verifier voire corriger les orientations courante et par defaut + if (!ori) { + if (default_ori == QET::West) default_ori = next(); + if (current_ori == QET::West) current_ori = next(); + } + } + return(can_set_ori); +} + +bool OrientationSet::setCurrent(QET::Orientation ori) { + bool can_set_ori = accept(ori); + if (can_set_ori) current_ori = ori; + return(can_set_ori); +} + +QET::Orientation OrientationSet::next() const { + QET::Orientation result = current_ori; + do result = QET::nextOrientation(result); while (!accept(result)); + return(result); +} + +QET::Orientation OrientationSet::previous() const { + QET::Orientation result = current_ori; + do result = QET::previousOrientation(result); while (!accept(result)); + return(result); +} + +const OrientationSet OrientationSet::operator++(int) { + OrientationSet before(*this); + setNext(); + return(before); +} + +const OrientationSet OrientationSet::operator--(int) { + OrientationSet before(*this); + setPrevious(); + return(before); +} + +/** + Permet de savoir si une orientation donnee peut etre utilisee. + @param o L'orientation en question + @return true si l'orientation est utilisable, false sinon +*/ +bool OrientationSet::accept(QET::Orientation ori) const { + bool accepted_ori = false; + switch(ori) { + case QET::North: accepted_ori = north_ori; break; + case QET::East : accepted_ori = east_ori; break; + case QET::South: accepted_ori = south_ori; break; + case QET::West : accepted_ori = west_ori; break; + } + return(accepted_ori); +} + +QET::Orientation OrientationSet::setNext() { + setCurrent(next()); + return(current_ori); +} + +QET::Orientation OrientationSet::setPrevious() { + setCurrent(previous()); + return(current_ori); +} + +const OrientationSet OrientationSet::operator++() { + setNext(); + return(*this); +} + +const OrientationSet OrientationSet::operator--() { + setPrevious(); + return(*this); +} + +bool OrientationSet::fromString(const QString &str) { + QRegExp osv("^([dyn])([dyn])([dyn])([dyn])$"); // osv : Orientation String Validator + if (osv.indexIn(str) == -1) return(false); + QStringList matches = osv.capturedTexts(); + + // il doit y avoir exactement UN d dans les 4 lettres capturees + if (matches.count("d") != 1) return(false); + + bool *ori_pointers[4] = { &north_ori, &east_ori, &south_ori, &west_ori }; + QET::Orientation ori_ints[4] = { QET::North, QET::East, QET::South, QET::West }; + for(int i = 0 ; i < 4 ; ++ i) { + QString current = matches.at(i + 1); + if (current == "d") { + current_ori = default_ori = ori_ints[i]; + current = "y"; + } + *(ori_pointers[i]) = (current == "y"); + } + return(true); +} + +QString OrientationSet::toString() const { + bool ori_pointers[4] = { north_ori, east_ori, south_ori, west_ori }; + QET::Orientation ori_ints[4] = { QET::North, QET::East, QET::South, QET::West }; + QString result(""); + for(int i = 0 ; i < 4 ; ++ i) { + if (default_ori == ori_ints[i]) result += "d"; + else result += (ori_pointers[i] ? "y" : "n"); + } + return(result); +} diff --git a/orientationset.h b/orientationset.h new file mode 100644 index 000000000..94ddc43e6 --- /dev/null +++ b/orientationset.h @@ -0,0 +1,76 @@ +#ifndef ORIENTATION_SET_H +#define ORIENTATION_SET_H +#include "qet.h" +class OrientationSet { + + // constructeurs, destructeur + public: + OrientationSet(); + virtual ~OrientationSet() {}; + + // attributs + private: + bool north_ori; + bool east_ori; + bool south_ori; + bool west_ori; + QET::Orientation default_ori; + QET::Orientation current_ori; + + // methodes + public: + bool north() const; + bool east() const; + bool south() const; + bool west() const; + bool setNorth(bool); + bool setEast(bool); + bool setSouth(bool); + bool setWest(bool); + QET::Orientation defaultOrientation() const; + void setDefaultOrientation(const QET::Orientation &); + QET::Orientation current() const; + bool setCurrent(QET::Orientation); + QET::Orientation next() const; + QET::Orientation previous() const; + QET::Orientation setNext(); + QET::Orientation setPrevious(); + bool accept(QET::Orientation) const; + const OrientationSet operator++(int); + const OrientationSet operator--(int); + const OrientationSet operator++(); + const OrientationSet operator--(); + bool fromString(const QString &); + QString toString() const; +}; + +inline bool OrientationSet::north() const { + return(north_ori); +} + +inline bool OrientationSet::east() const { + return(east_ori); +} + +inline bool OrientationSet::south() const { + return(south_ori); +} + +inline bool OrientationSet::west() const { + return(west_ori); +} + +inline void OrientationSet::setDefaultOrientation(const QET::Orientation& theValue) { + default_ori = theValue; + +} + +inline QET::Orientation OrientationSet::defaultOrientation() const { + return(default_ori); +} + +inline QET::Orientation OrientationSet::current() const { + return(current_ori); +} + +#endif diff --git a/orientationsetwidget.cpp b/orientationsetwidget.cpp new file mode 100644 index 000000000..2bf17fa84 --- /dev/null +++ b/orientationsetwidget.cpp @@ -0,0 +1,111 @@ +#include "orientationsetwidget.h" + +OrientationSetWidget::OrientationSetWidget(QWidget *parent) : QWidget(parent) { + + default_radios = new QButtonGroup(this); + + #define MK_COMBO_BOX(a) a##_orientation = new QComboBox();\ + a##_orientation -> addItem(QIcon(":/ico/allowed.png"), tr("Possible"), "y");\ + a##_orientation -> addItem(QIcon(":/ico/forbidden.png"),tr("Impossible"), "n");\ + connect(a##_orientation, SIGNAL(activated(int)), this, SLOT(updateOrientationSet()));\ + a##_default = new QRadioButton(); + + // 4 combo box, 4 boutons radios + MK_COMBO_BOX(north) + MK_COMBO_BOX(east) + MK_COMBO_BOX(south) + MK_COMBO_BOX(west) + + #undef MK_COMBO_BOX + + default_radios -> addButton(north_default, QET::North); + default_radios -> addButton(east_default, QET::East); + default_radios -> addButton(south_default, QET::South); + default_radios -> addButton(west_default, QET::West); + connect(default_radios, SIGNAL(buttonClicked(QAbstractButton *)), this, SLOT(slot_defaultChanged(QAbstractButton *))); + + // petites icones symbolisant les orientations + QLabel *north_pixmap = new QLabel(tr("Nord :")); + north_pixmap -> setPixmap(QPixmap(":/ico/north.png")); + QLabel *east_pixmap = new QLabel(tr("Est :")); + east_pixmap -> setPixmap(QPixmap(":/ico/east.png")); + QLabel *south_pixmap = new QLabel(tr("Sud :")); + south_pixmap -> setPixmap(QPixmap(":/ico/south.png")); + QLabel *west_pixmap = new QLabel(tr("Ouest :")); + west_pixmap -> setPixmap(QPixmap(":/ico/west.png")); + + QGridLayout *qgl = new QGridLayout(this); + qgl -> addWidget(new QLabel(tr("Par d\351faut")), 0, 3); + qgl -> addWidget(north_pixmap, 1, 0); + qgl -> addWidget(new QLabel(tr("Nord :")), 1, 1); + qgl -> addWidget(north_orientation, 1, 2); + qgl -> addWidget(north_default, 1, 3, Qt::AlignHCenter); + qgl -> addWidget(east_pixmap, 2, 0); + qgl -> addWidget(new QLabel(tr("Est :")), 2, 1); + qgl -> addWidget(east_orientation, 2, 2); + qgl -> addWidget(east_default, 2, 3, Qt::AlignHCenter); + qgl -> addWidget(south_pixmap, 3, 0); + qgl -> addWidget(new QLabel(tr("Sud :")), 3, 1); + qgl -> addWidget(south_orientation, 3, 2); + qgl -> addWidget(south_default, 3, 3, Qt::AlignHCenter); + qgl -> addWidget(west_pixmap, 4, 0); + qgl -> addWidget(new QLabel(tr("Ouest :")), 4, 1); + qgl -> addWidget(west_orientation, 4, 2); + qgl -> addWidget(west_default, 4, 3, Qt::AlignHCenter); + + // les combobox s'etendent autant que possible + qgl -> setColumnStretch(2, 1); + + // l'orientation par defaut par defaut est le Nord + north_default -> setChecked(true); + slot_defaultChanged(north_default); +} + +OrientationSet OrientationSetWidget::orientationSet() const { + return(ori); +} + +void OrientationSetWidget::setOrientationSet(const OrientationSet &os) { + ori = os; + updateForm(); +} + +void OrientationSetWidget::slot_defaultChanged(QAbstractButton *button) { + if (button == north_default) north_orientation -> setCurrentIndex(0); + else if (button == east_default) east_orientation -> setCurrentIndex(0); + else if (button == south_default) south_orientation -> setCurrentIndex(0); + else if (button == west_default) west_orientation -> setCurrentIndex(0); + + north_orientation -> setEnabled(button != north_default); + east_orientation -> setEnabled(button != east_default); + south_orientation -> setEnabled(button != south_default); + west_orientation -> setEnabled(button != west_default); + + updateOrientationSet(); +} + +void OrientationSetWidget::updateOrientationSet() { + ori.setNorth(!north_orientation -> currentIndex()); + ori.setEast (!east_orientation -> currentIndex()); + ori.setSouth(!south_orientation -> currentIndex()); + ori.setWest (!west_orientation -> currentIndex()); + ori.setDefaultOrientation(static_cast(default_radios -> checkedId())); +} + +void OrientationSetWidget::updateForm() { + north_orientation -> setCurrentIndex(ori.north() ? 0 : 1); + east_orientation -> setCurrentIndex(ori.east() ? 0 : 1); + south_orientation -> setCurrentIndex(ori.south() ? 0 : 1); + west_orientation -> setCurrentIndex(ori.west() ? 0 : 1); + QRadioButton *default_button = NULL; + switch(ori.defaultOrientation()) { + case QET::North: default_button = north_default; break; + case QET::East : default_button = east_default ; break; + case QET::South: default_button = south_default; break; + case QET::West : default_button = west_default ; break; + } + if (default_button != NULL) { + default_button -> setChecked(true); + slot_defaultChanged(default_button); + } +} diff --git a/orientationsetwidget.h b/orientationsetwidget.h new file mode 100644 index 000000000..bc50223e9 --- /dev/null +++ b/orientationsetwidget.h @@ -0,0 +1,40 @@ +#ifndef ORIENTATION_SET_WIDGET_H +#define ORIENTATION_SET_WIDGET_H +#include +#include "orientationset.h" +class OrientationSetWidget : public QWidget { + Q_OBJECT + // constructeurs, destructeur + public: + OrientationSetWidget(QWidget * = 0); + virtual ~OrientationSetWidget() {}; + + private: + OrientationSetWidget(const OrientationSetWidget &); + + // attributs + private: + OrientationSet ori; + QComboBox *north_orientation; + QComboBox *east_orientation; + QComboBox *south_orientation; + QComboBox *west_orientation; + QRadioButton *north_default; + QRadioButton *east_default; + QRadioButton *south_default; + QRadioButton *west_default; + QButtonGroup *default_radios; + + // methodes + public: + OrientationSet orientationSet() const; + void setOrientationSet(const OrientationSet &); + + private: + void updateForm(); + + public slots: + void slot_defaultChanged(QAbstractButton *); + void updateOrientationSet(); +}; +#endif diff --git a/qelectrotech.pro b/qelectrotech.pro index 198e77019..df9740a8c 100644 --- a/qelectrotech.pro +++ b/qelectrotech.pro @@ -1,11 +1,11 @@ ###################################################################### -# Automatically generated by qmake (2.01a) ven. avr. 6 18:45:47 2007 +# Automatically generated by qmake (2.01a) dim. avr. 29 22:04:08 2007 ###################################################################### TEMPLATE = app TARGET = -DEPENDPATH += . lang -INCLUDEPATH += . +DEPENDPATH += . editor lang +INCLUDEPATH += . editor # Input HEADERS += aboutqet.h \ @@ -28,8 +28,28 @@ HEADERS += aboutqet.h \ nameslist.h \ nameslistwidget.h \ newelementwizard.h \ + qet.h \ qetapp.h \ - terminal.h + terminal.h \ + editor/customelementeditor.h \ + editor/customelementgraphicpart.h \ + editor/customelementpart.h \ + editor/editorscene.h \ + editor/ellipseeditor.h \ + editor/lineeditor.h \ + editor/partellipse.h \ + editor/partline.h \ + editor/styleeditor.h \ + editor/partcircle.h \ + editor/circleeditor.h \ + orientationset.h \ + orientationsetwidget.h \ + editor/partpolygon.h \ + editor/polygoneditor.h \ + editor/partterminal.h \ + editor/terminaleditor.h \ + editor/parttext.h \ + editor/texteditor.h SOURCES += aboutqet.cpp \ borderinset.cpp \ conducer.cpp \ @@ -52,9 +72,27 @@ SOURCES += aboutqet.cpp \ nameslistwidget.cpp \ newelementwizard.cpp \ qetapp.cpp \ - terminal.cpp + terminal.cpp \ + editor/customelementeditor.cpp \ + editor/customelementgraphicpart.cpp \ + editor/customelementpart.cpp \ + editor/editorscene.cpp \ + editor/ellipseeditor.cpp \ + editor/lineeditor.cpp \ + editor/partellipse.cpp \ + editor/partline.cpp \ + editor/styleeditor.cpp \ + editor/qet.cpp \ + editor/partcircle.cpp \ + editor/circleeditor.cpp \ + orientationset.cpp \ + orientationsetwidget.cpp \ + editor/partpolygon.cpp \ + editor/polygoneditor.cpp \ + editor/partterminal.cpp \ + editor/terminaleditor.cpp \ + editor/parttext.cpp \ + editor/texteditor.cpp RESOURCES += qelectrotech.qrc TRANSLATIONS += lang/qet_en.ts lang/qt_fr.ts -CONFIG += debug warn_on QT += xml - diff --git a/qelectrotech.qrc b/qelectrotech.qrc index 42fc91d8c..87423359d 100644 --- a/qelectrotech.qrc +++ b/qelectrotech.qrc @@ -2,39 +2,56 @@ ico/qet.png ico/qelectrotech.png + ico/allowed.png + ico/add_col.png + ico/arc.png ico/button_cancel.png ico/button_ok.png + ico/circle.png ico/configure.png ico/copy.png ico/cut.png ico/delete.png + ico/east.png ico/editdelete.png + ico/ellipse.png ico/entrer_fs.png ico/exit.png ico/export.png ico/fileclose.png + ico/forbidden.png ico/import.png ico/info.png + ico/line.png ico/masquer.png ico/move.png ico/new.png + ico/north.png ico/open.png + ico/orientations.png ico/paste.png ico/pivoter.png + ico/polygon.png ico/print.png ico/qt.png ico/redo.png ico/reload.png + ico/remove_col.png ico/restaurer.png ico/saveas.png ico/save.png ico/select.png ico/sortir_fs.png + ico/south.png + ico/terminal.png + ico/text.png + ico/textfield.png ico/toolbars.png ico/undo.png ico/viewmagfit.png ico/viewmag-.png ico/viewmag.png ico/viewmag+.png + ico/west.png diff --git a/qet.h b/qet.h new file mode 100644 index 000000000..1341c994f --- /dev/null +++ b/qet.h @@ -0,0 +1,21 @@ +#ifndef _QET_H +#define _QET_H +#include +/** + Ce fichier contient des fonctions utiles pouvant etre appelees depuis + n'importe ou. Il contient egalement des enums utilises dans plusieurs + classes de l'application +*/ +namespace QET { + enum Orientation {North, East, South, West}; + QET::Orientation nextOrientation(QET::Orientation); + QET::Orientation previousOrientation(QET::Orientation); + QET::Orientation orientationFromString(const QString &); + QString orientationToString(QET::Orientation); + bool surLeMemeAxe(QET::Orientation, QET::Orientation); + bool estHorizontale(QET::Orientation); + bool estVerticale(QET::Orientation); + bool attributeIsAnInteger(const QDomElement &, QString , int * = NULL); + bool attributeIsAReal(const QDomElement &, QString , double * = NULL); +} +#endif diff --git a/qetapp.cpp b/qetapp.cpp index dabfaa087..4cd9dfbd0 100644 --- a/qetapp.cpp +++ b/qetapp.cpp @@ -221,8 +221,8 @@ void QETApp::actions() { supprimer = new QAction(QIcon(":/ico/delete.png"), tr("Supprimer"), this); pivoter = new QAction(QIcon(":/ico/pivoter.png"), tr("Pivoter"), this); infos_diagram = new QAction(QIcon(":/ico/info.png"), tr("Informations sur le sch\351ma"), this); - add_column = new QAction( tr("Ajouter une colonne"), this); - remove_column = new QAction( tr("Enlever une colonne"), this); + add_column = new QAction(QIcon(":/ico/add_col.png"), tr("Ajouter une colonne"), this); + remove_column = new QAction(QIcon(":/ico/remove_col.png"), tr("Enlever une colonne"), this); expand_diagram = new QAction( tr("Agrandir le sch\351ma"), this); shrink_diagram = new QAction( tr("R\351tr\351cir le sch\351ma"), this); diff --git a/terminal.cpp b/terminal.cpp index 02ba717a7..b032c81a2 100644 --- a/terminal.cpp +++ b/terminal.cpp @@ -3,27 +3,32 @@ #include "element.h" #include "conducer.h" +QColor Terminal::couleur_neutre = QColor(Qt::blue); +QColor Terminal::couleur_autorise = QColor(Qt::darkGreen); +QColor Terminal::couleur_prudence = QColor("#ff8000"); +QColor Terminal::couleur_interdit = QColor(Qt::red); + /** Fonction privee pour initialiser la borne. @param pf position du point d'amarrage pour un conducteur @param o orientation de la borne : Qt::Horizontal ou Qt::Vertical */ -void Terminal::initialise(QPointF pf, Terminal::Orientation o) { +void Terminal::initialise(QPointF pf, QET::Orientation o) { // definition du pount d'amarrage pour un conducteur amarrage_conducer = pf; // definition de l'orientation de la terminal (par defaut : sud) - if (o < Terminal::Nord || o > Terminal::Ouest) sens = Terminal::Sud; + if (o < QET::North || o > QET::West) sens = QET::South; else sens = o; // calcul de la position du point d'amarrage a l'element amarrage_elmt = amarrage_conducer; switch(sens) { - case Terminal::Nord : amarrage_elmt += QPointF(0, TAILLE_BORNE); break; - case Terminal::Est : amarrage_elmt += QPointF(-TAILLE_BORNE, 0); break; - case Terminal::Ouest : amarrage_elmt += QPointF(TAILLE_BORNE, 0); break; - case Terminal::Sud : - default : amarrage_elmt += QPointF(0, -TAILLE_BORNE); + case QET::North: amarrage_elmt += QPointF(0, TAILLE_BORNE); break; + case QET::East : amarrage_elmt += QPointF(-TAILLE_BORNE, 0); break; + case QET::West : amarrage_elmt += QPointF(TAILLE_BORNE, 0); break; + case QET::South: + default : amarrage_elmt += QPointF(0, -TAILLE_BORNE); } // par defaut : pas de conducteur @@ -36,18 +41,16 @@ void Terminal::initialise(QPointF pf, Terminal::Orientation o) { setAcceptedMouseButtons(Qt::LeftButton); hovered = false; setToolTip("Terminal"); - couleur_neutre = QColor(Qt::blue); - couleur_autorise = QColor(Qt::darkGreen); - couleur_prudence = QColor("#ff8000"); - couleur_interdit = QColor(Qt::red); - couleur_hovered = couleur_neutre; } /** Constructeur par defaut */ -Terminal::Terminal() : QGraphicsItem(0, 0) { - initialise(QPointF(0.0, 0.0), Terminal::Sud); +Terminal::Terminal() : + QGraphicsItem(0, 0), + couleur_hovered(Terminal::couleur_neutre) +{ + initialise(QPointF(0.0, 0.0), QET::South); diagram_scene = 0; } @@ -58,7 +61,10 @@ Terminal::Terminal() : QGraphicsItem(0, 0) { @param e Element auquel cette borne appartient @param s Scene sur laquelle figure cette borne */ -Terminal::Terminal(QPointF pf, Terminal::Orientation o, Element *e, Diagram *s) : QGraphicsItem(e, s) { +Terminal::Terminal(QPointF pf, QET::Orientation o, Element *e, Diagram *s) : + QGraphicsItem(e, s), + couleur_hovered(Terminal::couleur_neutre) +{ initialise(pf, o); diagram_scene = s; } @@ -71,7 +77,10 @@ Terminal::Terminal(QPointF pf, Terminal::Orientation o, Element *e, Diagram *s) @param e Element auquel cette borne appartient @param s Scene sur laquelle figure cette borne */ -Terminal::Terminal(qreal pf_x, qreal pf_y, Terminal::Orientation o, Element *e, Diagram *s) : QGraphicsItem(e, s) { +Terminal::Terminal(qreal pf_x, qreal pf_y, QET::Orientation o, Element *e, Diagram *s) : + QGraphicsItem(e, s), + couleur_hovered(Terminal::couleur_neutre) +{ initialise(QPointF(pf_x, pf_y), o); } @@ -93,19 +102,18 @@ Terminal::~Terminal() { pivote. Sinon elle renvoie son sens normal. @return L'orientation actuelle de la Terminal. */ -Terminal::Orientation Terminal::orientation() const { - //true pour une orientation verticale, false pour une orientation horizontale +QET::Orientation Terminal::orientation() const { if (Element *elt = qgraphicsitem_cast(parentItem())) { // orientations actuelle et par defaut de l'element - Terminal::Orientation ori_cur = elt -> orientation(); - Terminal::Orientation ori_def = elt -> defaultOrientation(); + QET::Orientation ori_cur = elt -> orientation().current(); + QET::Orientation ori_def = elt -> orientation().defaultOrientation(); if (ori_cur == ori_def) return(sens); else { // calcul l'angle de rotation implique par l'orientation de l'element parent // angle de rotation de la borne sur la scene, divise par 90 int angle = ori_cur - ori_def + sens; while (angle >= 4) angle -= 4; - return((Terminal::Orientation)angle); + return((QET::Orientation)angle); } } else return(sens); } @@ -410,7 +418,7 @@ bool Terminal::valideXml(QDomElement &terminal) { // parse l'orientation int terminal_or = terminal.attribute("orientation").toInt(&conv_ok); if (!conv_ok) return(false); - if (terminal_or != Terminal::Nord && terminal_or != Terminal::Sud && terminal_or != Terminal::Est && terminal_or != Terminal::Ouest) return(false); + if (terminal_or != QET::North && terminal_or != QET::South && terminal_or != QET::East && terminal_or != QET::West) return(false); // a ce stade, la borne est syntaxiquement correcte return(true); diff --git a/terminal.h b/terminal.h index 9dddec00f..2cc97aebc 100644 --- a/terminal.h +++ b/terminal.h @@ -3,6 +3,7 @@ #define TAILLE_BORNE 4 #include #include +#include "qet.h" class Conducer; class Diagram; class Element; @@ -14,10 +15,9 @@ class Terminal : public QGraphicsItem { // constructeurs, destructeur public: - enum Orientation {Nord, Est, Sud, Ouest}; Terminal(); - Terminal(QPointF, Terminal::Orientation, Element * = 0, Diagram * = 0); - Terminal(qreal, qreal, Terminal::Orientation, Element * = 0, Diagram * = 0); + Terminal(QPointF, QET::Orientation, Element * = 0, Diagram * = 0); + Terminal(qreal, qreal, QET::Orientation, Element * = 0, Diagram * = 0); virtual ~Terminal(); private: @@ -39,7 +39,7 @@ class Terminal : public QGraphicsItem { // methodes de lecture QList conducers() const; - Terminal::Orientation orientation() const; + QET::Orientation orientation() const; QPointF amarrageConducer() const; void updateConducer(QPointF = QPointF()); @@ -61,6 +61,12 @@ class Terminal : public QGraphicsItem { public: enum { Type = UserType + 1002 }; + // differentes couleurs statiques utilisables pour l'effet "hover" + static QColor couleur_neutre; + static QColor couleur_autorise; + static QColor couleur_prudence; + static QColor couleur_interdit; + private: // pointeur vers la QGraphicsScene de type Diagram (evite quelques casts en interne) Diagram *diagram_scene; @@ -68,7 +74,7 @@ class Terminal : public QGraphicsItem { QPointF amarrage_conducer; QPointF amarrage_elmt; // orientation de la borne - Terminal::Orientation sens; + QET::Orientation sens; // liste des conducers lies a cette borne QList liste_conducers; // pointeur vers un rectangle correspondant au bounding rect ; permet de ne calculer le bounding rect qu'une seule fois ; le pointeur c'est parce que le compilo exige une methode const @@ -76,13 +82,9 @@ class Terminal : public QGraphicsItem { Terminal *terminal_precedente; bool hovered; // methode initialisant les differents membres de la borne - void initialise(QPointF, Terminal::Orientation); - // differentes couleurs utilisables pour l'effet "hover" + void initialise(QPointF, QET::Orientation); + // couleur de l'effet hover de la patte QColor couleur_hovered; - QColor couleur_neutre; - QColor couleur_autorise; - QColor couleur_prudence; - QColor couleur_interdit; }; /**