diff --git a/sources/diagramevent/diagrameventaddelement.cpp b/sources/diagramevent/diagrameventaddelement.cpp index c6ff54a1d..ab0d9ad7b 100644 --- a/sources/diagramevent/diagrameventaddelement.cpp +++ b/sources/diagramevent/diagrameventaddelement.cpp @@ -216,6 +216,11 @@ void DiagramEventAddElement::addElement() element -> setPos(m_element->pos()); element -> setRotation(m_element -> rotation()); m_diagram -> addItem(element); + + //The element is dropped by the user, the dynamic text field stored in m_converted_text_from_xml_description + //can be moved to m_dynamic_text_list, because we are sure fromXml will be not called. + element->m_dynamic_text_list.append(element->m_converted_text_from_xml_description.keys()); + element->m_converted_text_from_xml_description.clear(); QUndoCommand *undo_object = new QUndoCommand(tr("Ajouter %1").arg(element->name())); new AddItemCommand(element, m_diagram, m_element -> pos(), undo_object); diff --git a/sources/qetgraphicsitem/customelement.cpp b/sources/qetgraphicsitem/customelement.cpp index a59801760..809ad0d94 100644 --- a/sources/qetgraphicsitem/customelement.cpp +++ b/sources/qetgraphicsitem/customelement.cpp @@ -59,11 +59,11 @@ CustomElement::CustomElement(const ElementsLocation &location, QGraphicsItem *qg } //Start from empty lists. - list_lines_.clear(); - list_rectangles_.clear(); - list_circles_.clear(); - list_polygons_.clear(); - list_arcs_.clear(); + m_lines.clear(); + m_rectangles.clear(); + m_circles.clear(); + m_polygons.clear(); + m_arcs.clear(); setPrefix(autonum::elementPrefixForLocation(location)); int elmt_state; @@ -219,62 +219,62 @@ bool CustomElement::buildFromXml(const QDomElement &xml_def_elmt, int *state) { Destructeur */ CustomElement::~CustomElement() { - qDeleteAll (list_lines_); - qDeleteAll (list_rectangles_); - qDeleteAll (list_circles_); - qDeleteAll (list_polygons_); - qDeleteAll (list_arcs_); - qDeleteAll (list_texts_); - qDeleteAll (list_terminals); + qDeleteAll (m_lines); + qDeleteAll (m_rectangles); + qDeleteAll (m_circles); + qDeleteAll (m_polygons); + qDeleteAll (m_arcs); + qDeleteAll (m_texts); + qDeleteAll (m_terminals); } /// @return la liste des bornes de cet element QList CustomElement::terminals() const { - return(list_terminals); + return(m_terminals); } /// @return la liste des conducteurs rattaches a cet element QList CustomElement::conductors() const { QList conductors; - foreach(Terminal *t, list_terminals) conductors << t -> conductors(); + foreach(Terminal *t, m_terminals) conductors << t -> conductors(); return(conductors); } /// @return la liste des textes de cet element QList CustomElement::texts() const { - return(list_texts_); + return(m_texts); } /// @return the list of lines QList CustomElement::lines() const { - return(list_lines_); + return(m_lines); } /// @return the list of rectangles QList CustomElement::rectangles() const { - return(list_rectangles_); + return(m_rectangles); } /// @return the list of bounding rectangles for circles QList CustomElement::circles() const { - return(list_circles_); + return(m_circles); } /// @return the list of bounding rectangles for circles QList *> CustomElement::polygons() const { - return(list_polygons_); + return(m_polygons); } /// @return the list of arcs QList *> CustomElement::arcs() const { - return(list_arcs_); + return(m_arcs); } /** @return Le nombre de bornes que l'element possede */ int CustomElement::terminalsCount() const { - return(list_terminals.size()); + return(m_terminals.size()); } /** @@ -352,7 +352,7 @@ bool CustomElement::parseLine(QDomElement &e, QPainter &qp) { //Add line to the list QLineF *newLine = new QLineF(line); - list_lines_ << newLine; + m_lines << newLine; QPointF point1(line.p1()); QPointF point2(line.p2()); @@ -452,7 +452,7 @@ bool CustomElement::parseRect(QDomElement &e, QPainter &qp) { //Add rectangle to the list QRectF *rect = new QRectF(rect_x, rect_y, rect_w, rect_h); - list_rectangles_ << rect; + m_rectangles << rect; qp.save(); setPainterStyle(e, qp); @@ -491,7 +491,7 @@ bool CustomElement::parseCircle(QDomElement &e, QPainter &qp) { // Add circle to list QRectF *circle = new QRectF(circle_bounding_rect); - list_circles_ << circle; + m_circles << circle; qp.drawEllipse(circle_bounding_rect); qp.restore(); @@ -528,7 +528,7 @@ bool CustomElement::parseEllipse(QDomElement &e, QPainter &qp) { arc -> push_back(ellipse_h); arc -> push_back(0); arc -> push_back(360); - list_arcs_ << arc; + m_arcs << arc; qp.drawEllipse(QRectF(ellipse_x, ellipse_y, ellipse_l, ellipse_h)); qp.restore(); @@ -569,7 +569,7 @@ bool CustomElement::parseArc(QDomElement &e, QPainter &qp) { arc -> push_back(arc_h); arc -> push_back(arc_s); arc -> push_back(arc_a); - list_arcs_ << arc; + m_arcs << arc; qp.drawArc(QRectF(arc_x, arc_y, arc_l, arc_h), (int)(arc_s * 16), (int)(arc_a * 16)); qp.restore(); @@ -617,7 +617,7 @@ bool CustomElement::parsePolygon(QDomElement &e, QPainter &qp) { // Add to list of polygons. QVector *poly = new QVector(points); - list_polygons_ << poly; + m_polygons << poly; qp.restore(); return(true); @@ -666,7 +666,7 @@ bool CustomElement::parseText(QDomElement &e, QPainter &qp) { eti -> setOriginalRotationAngle(original_rotation_angle); eti -> setRotationAngle(original_rotation_angle); eti -> setFollowParentRotations(e.attribute("rotate") == "true"); - list_texts_ << eti; + m_texts << eti; // Se positionne aux coordonnees indiquees dans la description du texte qp.setTransform(QTransform(), false); @@ -709,41 +709,74 @@ bool CustomElement::parseText(QDomElement &e, QPainter &qp) { - une chaine de caracteres facultative utilisee comme valeur par defaut - une taille - le fait de subir les rotations de l'element ou non - @param e L'element XML a analyser + @param dom_element L'element XML a analyser @return Un pointeur vers l'objet ElementTextItem ainsi cree si l'analyse reussit, 0 sinon */ -ElementTextItem *CustomElement::parseInput(QDomElement &e) { +bool CustomElement::parseInput(QDomElement &dom_element) { qreal pos_x, pos_y; int size; if ( - !QET::attributeIsAReal(e, "x", &pos_x) ||\ - !QET::attributeIsAReal(e, "y", &pos_y) ||\ - !QET::attributeIsAnInteger(e, "size", &size) - ) return(nullptr); - - ElementTextItem *eti = new ElementTextItem(e.attribute("text"), this); - eti -> setFont(QETApp::diagramTextsFont(size)); - eti -> setTagg(e.attribute("tagg", "other")); - m_element_informations.addValue(e.attribute("tagg", "other"), e.attribute("text")); - + !QET::attributeIsAReal(dom_element, "x", &pos_x) ||\ + !QET::attributeIsAReal(dom_element, "y", &pos_y) ||\ + !QET::attributeIsAnInteger(dom_element, "size", &size) + ) return(false); + + //The text have a tagg, we create an element text item + if (dom_element.attribute("tagg", "none") != "none") + { + ElementTextItem *eti = new ElementTextItem(dom_element.attribute("text"), this); + eti -> setFont(QETApp::diagramTextsFont(size)); + eti -> setTagg(dom_element.attribute("tagg", "other")); + m_element_informations.addValue(dom_element.attribute("tagg", "other"), dom_element.attribute("text")); + // position the text field - eti -> setOriginalPos(QPointF(pos_x, pos_y)); - eti -> setPos(pos_x, pos_y); - + eti -> setOriginalPos(QPointF(pos_x, pos_y)); + eti -> setPos(pos_x, pos_y); + // rotation of the text field - qreal original_rotation_angle = 0.0; - QET::attributeIsAReal(e, "rotation", &original_rotation_angle); - eti -> setOriginalRotationAngle(original_rotation_angle); - eti -> setRotationAngle(original_rotation_angle); - + qreal original_rotation_angle = 0.0; + QET::attributeIsAReal(dom_element, "rotation", &original_rotation_angle); + eti -> setOriginalRotationAngle(original_rotation_angle); + eti -> setRotationAngle(original_rotation_angle); + // behavior when the parent element is rotated - eti -> setFollowParentRotations(e.attribute("rotate") == "true"); - - list_texts_ << eti; - - connect(eti, &ElementTextItem::diagramTextChanged, this, &Element::textItemChanged); - - return(eti); + eti -> setFollowParentRotations(dom_element.attribute("rotate") == "true"); + + m_texts << eti; + + connect(eti, &ElementTextItem::diagramTextChanged, this, &Element::textItemChanged); + + return(eti); + } + //The text haven't got a tagg, so we convert it to a dynamic text item + //and store it to m_converted_text_from_xml_description, instead of m_dynamic_text_list + //because these dynamic text need post treatement + else + { + DynamicElementTextItem *deti = new DynamicElementTextItem(this); + deti->setText(dom_element.attribute("text", "_")); + deti->setFontSize(dom_element.attribute("size", QString::number(9)).toInt()); + deti->setRotation(dom_element.attribute("rotation", QString::number(0)).toDouble()); + + + //the origin transformation point of PartDynamicTextField is the top left corner, no matter the font size + //The origin transformation point of ElementTextItem is the middle of left edge, and so by definition, change with the size of the font + //We need to use a QMatrix to find the pos of this text from the saved pos of text item + QMatrix matrix; + //First make the rotation + matrix.rotate(dom_element.attribute("rotation", "0").toDouble()); + QPointF pos = matrix.map(QPointF(0, -deti->boundingRect().height()/2)); + matrix.reset(); + //Second translate to the pos + QPointF p(dom_element.attribute("x", QString::number(0)).toDouble(), + dom_element.attribute("y", QString::number(0)).toDouble()); + matrix.translate(p.x(), p.y()); + deti->setPos(matrix.map(pos)); + m_converted_text_from_xml_description.insert(deti, p); + return true; + } + + return false; } /** @@ -791,7 +824,7 @@ Terminal *CustomElement::parseTerminal(QDomElement &e) { else return(nullptr); Terminal *new_terminal = new Terminal(terminalx, terminaly, terminalo, this); new_terminal -> setZValue(420); // valeur arbitraire pour maintenir les bornes au-dessus des champs de texte - list_terminals << new_terminal; + m_terminals << new_terminal; return(new_terminal); } @@ -1036,7 +1069,7 @@ ElementTextItem* CustomElement::setTaggedText(const QString &tagg, const QString * @param tagg */ ElementTextItem* CustomElement::taggedText(const QString &tagg) const { - foreach (ElementTextItem *eti, list_texts_) { + foreach (ElementTextItem *eti, m_texts) { if (eti -> tagg() == tagg) return eti; } return nullptr; diff --git a/sources/qetgraphicsitem/customelement.h b/sources/qetgraphicsitem/customelement.h index 30388b4cb..164f47d75 100644 --- a/sources/qetgraphicsitem/customelement.h +++ b/sources/qetgraphicsitem/customelement.h @@ -49,16 +49,17 @@ class CustomElement : public FixedElement ElementsLocation location_; QPicture drawing; QPicture low_zoom_drawing; - QList list_terminals; - QList list_texts_; + QList m_terminals; + QList m_texts; + QList m_dynamic_texts; bool forbid_antialiasing; - QList list_lines_; - QList list_rectangles_; - QList list_circles_; - QList *> list_polygons_; - QList *> list_arcs_; + QList m_lines; + QList m_rectangles; + QList m_circles; + QList *> m_polygons; + QList *> m_arcs; // methods public: @@ -87,7 +88,7 @@ class CustomElement : public FixedElement virtual bool parseArc(QDomElement &, QPainter &); virtual bool parsePolygon(QDomElement &, QPainter &); virtual bool parseText(QDomElement &, QPainter &); - virtual ElementTextItem *parseInput(QDomElement &); + virtual bool parseInput(QDomElement &); virtual DynamicElementTextItem *parseDynamicText(QDomElement &); virtual Terminal *parseTerminal(QDomElement &); diff --git a/sources/qetgraphicsitem/element.cpp b/sources/qetgraphicsitem/element.cpp index 7b4dca182..dc1f03f1f 100644 --- a/sources/qetgraphicsitem/element.cpp +++ b/sources/qetgraphicsitem/element.cpp @@ -448,20 +448,6 @@ bool Element::fromXml(QDomElement &e, QHash &table_id_adr, bool } } - //import text filed value - QList inputs = QET::findInDomElement(e, "inputs", "input"); - foreach(QGraphicsItem *qgi, childItems()) - { - if (ElementTextItem *eti = qgraphicsitem_cast(qgi)) - { - foreach(QDomElement input, inputs) - { - eti -> fromXml(input); - etiToElementLabels(eti); - } - } - } - //load uuid of connected elements QList uuid_list = QET::findInDomElement(e, "links_uuids", "link_uuid"); foreach (QDomElement qdo, uuid_list) tmp_uuids_link << qdo.attribute("uuid"); @@ -481,6 +467,122 @@ bool Element::fromXml(QDomElement &e, QHash &table_id_adr, bool else m_autoNum_seq.fromXml(e.firstChildElement("sequentialNumbers")); + //Position and selection. + //We directly call setPos from QGraphicsObject, because QetGraphicsItem will snap to grid + QGraphicsObject::setPos(e.attribute("x").toDouble(), e.attribute("y").toDouble()); + setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable); + + // orientation + bool conv_ok; + int read_ori = e.attribute("orientation").toInt(&conv_ok); + if (!conv_ok || read_ori < 0 || read_ori > 3) read_ori = 0; + if (handle_inputs_rotation) { + rotateBy(90*read_ori); + } else { + applyRotation(90*read_ori); + } + + //Befor load the dynamic text field, + //we remove the dynamic text field created from the description of this element, to avoid doublons. + for(DynamicElementTextItem *deti : m_dynamic_text_list) + delete deti; + m_dynamic_text_list.clear(); + + //************************// + //***Dynamic texts item***// + //************************// + for (QDomElement qde : QET::findInDomElement(e, "dynamic_texts", DynamicElementTextItem::xmlTaggName())) + { + DynamicElementTextItem *deti = new DynamicElementTextItem(this); + addDynamicTextItem(deti); + deti->fromXml(qde); + } + + + //************************// + //***Element texts item***// + //************************// + QList inputs = QET::findInDomElement(e, "inputs", "input"); + + //First case, we check for the text item converted to dynamic text item + const QList conv_deti_list = m_converted_text_from_xml_description.keys(); + const QList dom_inputs = inputs; + + for (DynamicElementTextItem *deti : conv_deti_list) + { + for(QDomElement dom_input : dom_inputs) + { + //we use the same method used in ElementTextItem::fromXml to compar and know if the input dom element is for one of the text stored. + //The comparaison is made from the text position : if the position of the text is the same as the position stored in 'input' dom element + //that mean this is the good text + if (qFuzzyCompare(qreal(dom_input.attribute("x").toDouble()), m_converted_text_from_xml_description.value(deti).x()) && + qFuzzyCompare(qreal(dom_input.attribute("y").toDouble()), m_converted_text_from_xml_description.value(deti).y())) + { + deti->setText(dom_input.attribute("text")); + + qreal rotation = deti->rotation(); + QPointF xml_pos = m_converted_text_from_xml_description.value(deti); + + if (dom_input.attribute("userrotation").toDouble()) + rotation = dom_input.attribute("userrotation").toDouble(); + + if (dom_input.hasAttribute("userx")) + xml_pos.setX(dom_input.attribute("userx").toDouble()); + if(dom_input.hasAttribute("usery")) + xml_pos.setY(dom_input.attribute("usery", "0").toDouble()); + + //the origin transformation point of PartDynamicTextField is the top left corner, no matter the font size + //The origin transformation point of PartTextField is the middle of left edge, and so by definition, change with the size of the font + //We need to use a QMatrix to find the pos of this text from the saved pos of text item + + deti->setPos(xml_pos); + deti->setRotation(rotation); + + QMatrix matrix; + //First make the rotation + matrix.rotate(rotation); + QPointF pos = matrix.map(QPointF(0, -deti->boundingRect().height()/2)); + matrix.reset(); + //Second translate to the pos + matrix.translate(xml_pos.x(), xml_pos.y()); + deti->setPos(matrix.map(pos)); + + //dom_input and deti matched we remove the dom_input from @inputs list, + //to avoid unnecessary checking made below + //we also move deti from the m_converted_text_from_xml_description to m_dynamic_text_list + inputs.removeAll(dom_input); + m_dynamic_text_list.append(deti); + m_converted_text_from_xml_description.remove(deti); + } + } + } + + //###Firts case : if this is the first time the user open the project since text item are converted to dynamic text, + //in the previous opening of the project, every texts field present in the element description was created. + //At save time, the values of each of them was save in the 'input' dom element. + //The loop upper is made for the first case, to import the values in 'input' to the new converted dynamic texts field. + //###Second case : this is not the first time the user open the project since text item are converted to dynamic text. + //That mean, in a previous opening of the project, the text item was already converted and save as a dynamic text field. + //So there isn't 'input' dom element in the project, and every dynamic text item present in m_converted_text_from_xml_description + //need to be deleted (because already exist in m_dynamic_text_list, from a previous save) + for (DynamicElementTextItem *deti : m_converted_text_from_xml_description.keys()) + delete deti; + m_converted_text_from_xml_description.clear(); + + //For the moment the text item with a tagg are not converted to dynamic text item + //so we must to check it + foreach(QGraphicsItem *qgi, childItems()) + { + if (ElementTextItem *eti = qgraphicsitem_cast(qgi)) + { + foreach(QDomElement input, inputs) + { + eti -> fromXml(input); + etiToElementLabels(eti); + } + } + } + //load informations m_element_informations.fromXml(e.firstChildElement("elementInformations"), "elementInformation"); /** @@ -517,35 +619,6 @@ bool Element::fromXml(QDomElement &e, QHash &table_id_adr, bool } } } - - //Position and selection. - //We directly call setPos from QGraphicsObject, because QetGraphicsItem will snap to grid - QGraphicsObject::setPos(e.attribute("x").toDouble(), e.attribute("y").toDouble()); - setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable); - - // orientation - bool conv_ok; - int read_ori = e.attribute("orientation").toInt(&conv_ok); - if (!conv_ok || read_ori < 0 || read_ori > 3) read_ori = 0; - if (handle_inputs_rotation) { - rotateBy(90*read_ori); - } else { - applyRotation(90*read_ori); - } - - //Befor load the dynamic text field, - //we remove the dynamic text field created from the description of this element, to avoid doublons. - for(DynamicElementTextItem *deti : m_dynamic_text_list) - delete deti; - m_dynamic_text_list.clear(); - - //Dynamic texts - for (QDomElement qde : QET::findInDomElement(e, "dynamic_texts", DynamicElementTextItem::xmlTaggName())) - { - DynamicElementTextItem *deti = new DynamicElementTextItem(this); - addDynamicTextItem(deti); - deti->fromXml(qde); - } return(true); } diff --git a/sources/qetgraphicsitem/element.h b/sources/qetgraphicsitem/element.h index b73bf4fea..57132138c 100644 --- a/sources/qetgraphicsitem/element.h +++ b/sources/qetgraphicsitem/element.h @@ -37,6 +37,8 @@ class DynamicElementTextItem; */ class Element : public QetGraphicsItem { + friend class DiagramEventAddElement; + Q_OBJECT // constructors, destructor @@ -215,6 +217,11 @@ class Element : public QetGraphicsItem void hoverEnterEvent ( QGraphicsSceneHoverEvent * ) override; void hoverLeaveEvent ( QGraphicsSceneHoverEvent * ) override; + protected: + // @m_converted_text_from_description, when a element is created from his description, the old element text item (tagged as 'input' in the xml) + // are converted to dynamic text field, the QPointF is the original position of the text item, because the origin transformation point of text item + // and dynamic text item are not the same, so we must to keep a track of this value, to be use in the function element::fromXml + QHash m_converted_text_from_xml_description; private: bool m_mouse_over; QString m_prefix; diff --git a/sources/qetgraphicsitem/ghostelement.cpp b/sources/qetgraphicsitem/ghostelement.cpp index 2ab44746c..1d44c0691 100644 --- a/sources/qetgraphicsitem/ghostelement.cpp +++ b/sources/qetgraphicsitem/ghostelement.cpp @@ -60,10 +60,7 @@ bool GhostElement::fromXml(QDomElement &e, QHash &table_id_adr, // instancie les champs de texte decrits dans l'element XML foreach(QDomElement qde, QET::findInDomElement(e, "inputs", "input")) { qde.setAttribute("size", 9); // arbitraire - if (ElementTextItem *new_input = CustomElement::parseInput(qde)) { - new_input -> fromXml(qde); - } - qde.removeAttribute("size"); + CustomElement::parseInput(qde); } /*