[qet] qet/qet: [5083] Diagram editor :

[ Thread Index | Date Index | More lists.tuxfamily.org/qet Archives ]


Revision: 5083
Author:   blacksun
Date:     2017-10-19 11:10:23 +0200 (Thu, 19 Oct 2017)
Log Message:
-----------
Diagram editor :
1° When user drag and drop an element with text item (tagg input in the xml), the text item are converted to a dynamic text item.
2° When open an existing project, every texts item of elements in the project are converted to dynamic text field.

Note that the changes described upper don't work for the texts which have a tagg (for the moment)

Modified Paths:
--------------
    trunk/sources/diagramevent/diagrameventaddelement.cpp
    trunk/sources/qetgraphicsitem/customelement.cpp
    trunk/sources/qetgraphicsitem/customelement.h
    trunk/sources/qetgraphicsitem/element.cpp
    trunk/sources/qetgraphicsitem/element.h
    trunk/sources/qetgraphicsitem/ghostelement.cpp

Modified: trunk/sources/diagramevent/diagrameventaddelement.cpp
===================================================================
--- trunk/sources/diagramevent/diagrameventaddelement.cpp	2017-10-14 06:27:03 UTC (rev 5082)
+++ trunk/sources/diagramevent/diagrameventaddelement.cpp	2017-10-19 09:10:23 UTC (rev 5083)
@@ -216,6 +216,11 @@
 	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 *>(element, m_diagram, m_element -> pos(), undo_object);

Modified: trunk/sources/qetgraphicsitem/customelement.cpp
===================================================================
--- trunk/sources/qetgraphicsitem/customelement.cpp	2017-10-14 06:27:03 UTC (rev 5082)
+++ trunk/sources/qetgraphicsitem/customelement.cpp	2017-10-19 09:10:23 UTC (rev 5083)
@@ -59,11 +59,11 @@
 	}
 
 		//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,55 +219,55 @@
 	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<Terminal *> CustomElement::terminals() const {
-	return(list_terminals);
+	return(m_terminals);
 }
 
 /// @return la liste des conducteurs rattaches a cet element
 QList<Conductor *> CustomElement::conductors() const {
 	QList<Conductor *> conductors;
-	foreach(Terminal *t, list_terminals) conductors << t -> conductors();
+	foreach(Terminal *t, m_terminals) conductors << t -> conductors();
 	return(conductors);
 }
 
 /// @return la liste des textes de cet element
 QList<ElementTextItem *> CustomElement::texts() const {
-	return(list_texts_);
+	return(m_texts);
 }
 
 /// @return the list of lines
 QList<QLineF *> CustomElement::lines() const {
-	return(list_lines_);
+	return(m_lines);
 }
 
 /// @return the list of rectangles
 QList<QRectF *> CustomElement::rectangles() const {
-	return(list_rectangles_);
+	return(m_rectangles);
 }
 
 /// @return the list of bounding rectangles for circles
 QList<QRectF *> CustomElement::circles() const {
-	return(list_circles_);
+	return(m_circles);
 }
 
 /// @return the list of bounding rectangles for circles
 QList<QVector<QPointF> *> CustomElement::polygons() const {
-	return(list_polygons_);
+	return(m_polygons);
 }
 
 /// @return the list of arcs
 QList<QVector<qreal> *> CustomElement::arcs() const {
-	return(list_arcs_);
+	return(m_arcs);
 }
 
 /**
@@ -274,7 +274,7 @@
 	@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 @@
 
 	//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 @@
 
 	//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 @@
 
 	// 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 @@
 	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 @@
 	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 @@
 
 	// Add to list of polygons.
 	QVector<QPointF> *poly = new QVector<QPointF>(points);
-	list_polygons_ << poly;
+	m_polygons << poly;
 
 	qp.restore();
 	return(true);
@@ -666,7 +666,7 @@
 	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 @@
 		- 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 @@
 	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 @@
  * @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;

Modified: trunk/sources/qetgraphicsitem/customelement.h
===================================================================
--- trunk/sources/qetgraphicsitem/customelement.h	2017-10-14 06:27:03 UTC (rev 5082)
+++ trunk/sources/qetgraphicsitem/customelement.h	2017-10-19 09:10:23 UTC (rev 5083)
@@ -49,16 +49,17 @@
 		ElementsLocation location_;
 		QPicture drawing;
 		QPicture low_zoom_drawing;
-		QList<Terminal *> list_terminals;
-		QList<ElementTextItem *> list_texts_;
+		QList<Terminal *> m_terminals;
+		QList<ElementTextItem *> m_texts;
+		QList<DynamicElementTextItem *> m_dynamic_texts;
 		bool forbid_antialiasing;
 
 
-		QList<QLineF *> list_lines_;
-		QList<QRectF *> list_rectangles_;
-		QList<QRectF *> list_circles_;
-		QList<QVector<QPointF> *> list_polygons_;
-		QList<QVector<qreal> *> list_arcs_;
+		QList<QLineF *> m_lines;
+		QList<QRectF *> m_rectangles;
+		QList<QRectF *> m_circles;
+		QList<QVector<QPointF> *> m_polygons;
+		QList<QVector<qreal> *> m_arcs;
 	
 	// methods
 	public:
@@ -87,7 +88,7 @@
 		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 &);
 		

Modified: trunk/sources/qetgraphicsitem/element.cpp
===================================================================
--- trunk/sources/qetgraphicsitem/element.cpp	2017-10-14 06:27:03 UTC (rev 5082)
+++ trunk/sources/qetgraphicsitem/element.cpp	2017-10-19 09:10:23 UTC (rev 5083)
@@ -448,20 +448,6 @@
 		}
 	}
 
-		//import text filed value
-	QList<QDomElement> inputs = QET::findInDomElement(e, "inputs", "input");
-	foreach(QGraphicsItem *qgi, childItems())
-	{
-		if (ElementTextItem *eti = qgraphicsitem_cast<ElementTextItem *>(qgi))
-		{
-			foreach(QDomElement input, inputs)
-			{
-				eti -> fromXml(input);
-				etiToElementLabels(eti);
-			}
-		}
-	}
-
 	//load uuid of connected elements
 	QList <QDomElement> uuid_list = QET::findInDomElement(e, "links_uuids", "link_uuid");
 	foreach (QDomElement qdo, uuid_list) tmp_uuids_link << qdo.attribute("uuid");
@@ -481,6 +467,122 @@
 	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<QDomElement> inputs = QET::findInDomElement(e, "inputs", "input");
+	
+		//First case, we check for the text item converted to dynamic text item
+	const QList <DynamicElementTextItem *> conv_deti_list = m_converted_text_from_xml_description.keys();
+	const QList <QDomElement> 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<ElementTextItem *>(qgi))
+		{
+			foreach(QDomElement input, inputs)
+			{
+				eti -> fromXml(input);
+				etiToElementLabels(eti);
+			}
+		}
+	}
+	
 		//load informations
 	m_element_informations.fromXml(e.firstChildElement("elementInformations"), "elementInformation");
 		/**
@@ -517,36 +619,7 @@
 			}
 		}
 	}
-
-	//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);
 }
 

Modified: trunk/sources/qetgraphicsitem/element.h
===================================================================
--- trunk/sources/qetgraphicsitem/element.h	2017-10-14 06:27:03 UTC (rev 5082)
+++ trunk/sources/qetgraphicsitem/element.h	2017-10-19 09:10:23 UTC (rev 5083)
@@ -37,6 +37,8 @@
 */
 class Element : public QetGraphicsItem
 {
+	friend class DiagramEventAddElement;
+	
 	Q_OBJECT
 	
 		// constructors, destructor
@@ -215,6 +217,11 @@
 		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 <DynamicElementTextItem *, QPointF> m_converted_text_from_xml_description;
 	private:
 		bool m_mouse_over;
 		QString m_prefix;

Modified: trunk/sources/qetgraphicsitem/ghostelement.cpp
===================================================================
--- trunk/sources/qetgraphicsitem/ghostelement.cpp	2017-10-14 06:27:03 UTC (rev 5082)
+++ trunk/sources/qetgraphicsitem/ghostelement.cpp	2017-10-19 09:10:23 UTC (rev 5083)
@@ -60,10 +60,7 @@
 	// 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);
 	}
 	
 	/*


Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/