[qet] qet/qet: [5141] Texts group item can be rotate.

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


Revision: 5141
Author:   blacksun
Date:     2017-12-05 21:51:54 +0100 (Tue, 05 Dec 2017)
Log Message:
-----------
Texts group item can be rotate.
The keybord shortcut for texts group alignment change. Now it's ctrl + arrow-left/up/right

Modified Paths:
--------------
    trunk/sources/diagram.cpp
    trunk/sources/diagram.h
    trunk/sources/diagramcommands.cpp
    trunk/sources/diagramcommands.h
    trunk/sources/diagramcontent.cpp
    trunk/sources/diagramcontent.h
    trunk/sources/diagramview.cpp
    trunk/sources/diagramview.h
    trunk/sources/elementsmover.cpp
    trunk/sources/elementsmover.h
    trunk/sources/qetdiagrameditor.cpp
    trunk/sources/qetgraphicsitem/elementtextitemgroup.cpp
    trunk/sources/qetgraphicsitem/elementtextitemgroup.h

Added Paths:
-----------
    trunk/sources/undocommand/rotateselectioncommand.cpp
    trunk/sources/undocommand/rotateselectioncommand.h
    trunk/sources/undocommand/rotatetextscommand.cpp
    trunk/sources/undocommand/rotatetextscommand.h

Modified: trunk/sources/diagram.cpp
===================================================================
--- trunk/sources/diagram.cpp	2017-12-05 12:31:47 UTC (rev 5140)
+++ trunk/sources/diagram.cpp	2017-12-05 20:51:54 UTC (rev 5141)
@@ -39,6 +39,8 @@
 #include "element.h"
 #include "diagramview.h"
 #include "dynamicelementtextitem.h"
+#include "elementtextitemgroup.h"
+#include "undocommand/addelementtextcommand.h"
 
 const int   Diagram::xGrid  = 10;
 const int   Diagram::yGrid  = 10;
@@ -291,10 +293,10 @@
  * Else move selected elements
  * @param e
  */
-void Diagram::keyPressEvent(QKeyEvent *e)
+void Diagram::keyPressEvent(QKeyEvent *event)
 {
 	if (m_event_interface)
-		if(m_event_interface->keyPressEvent(e))
+		if(m_event_interface->keyPressEvent(event))
 		{
 			if(!m_event_interface->isRunning())
 			{
@@ -302,45 +304,77 @@
 			}
 			return;
 		}
-
-	bool transmit_event = true;
-	if (!isReadOnly()) {
+	
+	if (!isReadOnly())
+	{
 		QPointF movement;
 		qreal top_position = 0;
 		qreal left_position = 0;
-		QList<QGraphicsItem*> selected_elmts = this->selectedContent().items();
-		if (!this->selectedContent().items(DiagramContent::All).isEmpty()) {
-		switch(e -> key()) {
-			case Qt::Key_Left:
-				foreach (Element *item, selectedContent().m_elements) {
-					left_position = item->mapRectFromScene(item->boundingRect()).x();
-					if (left_position >= this->sceneRect().left() - item->boundingRect().width())
+		DiagramContent dc(this);
+		if (!dc.items(DiagramContent::All).isEmpty())
+		{
+				//Move item with the keyborb arrow
+			if(event->modifiers() == Qt::NoModifier)
+			{
+				switch(event->key())
+				{
+					case Qt::Key_Left:
+						for (Element *item : dc.m_elements)
+						{
+							left_position = item->mapRectFromScene(item->boundingRect()).x();
+							if (left_position >= this->sceneRect().left() - item->boundingRect().width())
+								return;
+						}
+						movement = QPointF(-xGrid, 0.0);
+						break;
+					case Qt::Key_Right:
+						movement = QPointF(+xGrid, 0.0);
+						break;
+					case Qt::Key_Up:
+						for(Element *item : dc.m_elements)
+						{
+							top_position = item->mapRectFromScene(item->boundingRect()).y();
+							if (top_position >= this->sceneRect().top() - item->boundingRect().height())
+								return;
+						}
+						movement = QPointF(0.0, -yGrid);
+						break;
+					case Qt::Key_Down:
+						movement = QPointF(0.0, +yGrid);
+						break;
+				}
+				
+				if (!movement.isNull() && !focusItem())
+				{
+					beginMoveElements();
+					continueMoveElements(movement);
+					event->accept();
 					return;
 				}
-				movement = QPointF(-xGrid, 0.0);
-				break;
-			case Qt::Key_Right: movement = QPointF(+xGrid, 0.0); break;
-			case Qt::Key_Up:
-				foreach (Element *item, selectedContent().m_elements) {
-					top_position = item->mapRectFromScene(item->boundingRect()).y();
-					if (top_position >= this->sceneRect().top() - item->boundingRect().height())
-						return;
+			}
+			else if(event->modifiers() == Qt::ControlModifier)
+			{
+				//Adjust the alignment of a texts group
+				if(selectedItems().size() == 1 && selectedItems().first()->type() == QGraphicsItemGroup::Type)
+				{
+					if(ElementTextItemGroup *etig = dynamic_cast<ElementTextItemGroup *>(selectedItems().first()))
+					{
+						if(event->key() == Qt::Key_Left &&  etig->alignment() != Qt::AlignLeft)
+							undoStack().push(new AlignmentTextsGroupCommand(etig, Qt::AlignLeft));
+						
+						else if (event->key() == Qt::Key_Up && etig->alignment() != Qt::AlignVCenter)
+							undoStack().push(new AlignmentTextsGroupCommand(etig, Qt::AlignVCenter));
+						
+						else if (event->key() == Qt::Key_Right && etig->alignment() != Qt::AlignRight)
+							undoStack().push(new AlignmentTextsGroupCommand(etig, Qt::AlignRight));
+					}
 				}
-				movement = QPointF(0.0, -yGrid);
-				break;
-			case Qt::Key_Down: movement = QPointF(0.0, +yGrid); break;
+			}
 		}
-		if (!movement.isNull() && !focusItem()) {
-			beginMoveElements();
-			continueMoveElements(movement);
-			e -> accept();
-			transmit_event = false;
-		}
+		
+		event->ignore();
+		QGraphicsScene::keyPressEvent(event);
 	}
-	if (transmit_event) {
-		QGraphicsScene::keyPressEvent(e);
-		}
-	}
 }
 
 /**
@@ -1659,25 +1693,6 @@
 	return(conductors_set);
 }
 
-/**
- * @brief Diagram::selectedTexts
- * @return A list of every selected texts (every kind of texts)
- */
-QSet<DiagramTextItem *> Diagram::selectedTexts() const
-{
-	QSet<DiagramTextItem *> selected_texts;
-	for(QGraphicsItem *qgi : selectedItems())
-	{
-		if (qgi->type() == ConductorTextItem::Type ||
-			qgi->type() == ElementTextItem::Type ||
-			qgi->type() == IndependentTextItem::Type ||
-			qgi->type() == DynamicElementTextItem::Type)
-				selected_texts << static_cast<DiagramTextItem *>(qgi);
-	}
-	
-	return(selected_texts);
-}
-
 /// @return true si le presse-papier semble contenir un schema
 bool Diagram::clipboardMayContainDiagram() {
 	QString clipboard_text = QApplication::clipboard() -> text().trimmed();
@@ -1761,62 +1776,6 @@
 }
 
 /**
- * @brief Diagram::selectedContent
- * @return the selected items, stored in a DiagramContent
- */
-DiagramContent Diagram::selectedContent()
-{
-	DiagramContent dc;
-
-		//Get the selected items
-	for (QGraphicsItem *item : selectedItems())
-	{
-		if (Element *elmt = qgraphicsitem_cast<Element *>(item))
-			dc.m_elements << elmt;
-		else if (IndependentTextItem *iti = qgraphicsitem_cast<IndependentTextItem *>(item))
-			dc.m_text_fields << iti;
-		else if (Conductor *c = qgraphicsitem_cast<Conductor *>(item))
-		{
-			// recupere les conducteurs selectionnes isoles (= non deplacables mais supprimables)
-			if (
-				!c -> terminal1 -> parentItem() -> isSelected() &&\
-				!c -> terminal2 -> parentItem() -> isSelected()
-			) {
-				dc.m_other_conductors << c;
-			}
-		}
-		else if (DiagramImageItem *dii = qgraphicsitem_cast<DiagramImageItem *>(item))
-			dc.m_images << dii;
-		else if (QetShapeItem *dsi = qgraphicsitem_cast<QetShapeItem *>(item))
-			dc.m_shapes << dsi;
-		else if (DynamicElementTextItem *deti = qgraphicsitem_cast<DynamicElementTextItem *>(item))
-			dc.m_element_texts << deti;
-	}
-	
-		//For each selected element, we determine if conductors must be moved or updated.
-	for(Element *elmt : dc.m_elements) {
-		for(Terminal *terminal : elmt -> terminals()) {
-			for(Conductor *conductor : terminal -> conductors()) {
-				Terminal *other_terminal;
-				if (conductor -> terminal1 == terminal) {
-					other_terminal = conductor -> terminal2;
-				} else {
-					other_terminal = conductor -> terminal1;
-				}
-				// si les deux elements du conducteur sont deplaces
-				if (dc.m_elements.contains(other_terminal -> parentElement())) {
-					dc.m_conductors_to_move << conductor;
-				} else {
-					dc.m_conductors_to_update << conductor;
-				}
-			}
-		}
-	}
-	
-	return(dc);
-}
-
-/**
  * @brief Diagram::canRotateSelection
  * @return True if a least one of selected items can be rotated
  */
@@ -1829,7 +1788,12 @@
 			qgi->type() == DiagramImageItem::Type ||
 			qgi->type() == ElementTextItem::Type ||
 			qgi->type() == Element::Type ||
-			qgi->type() == DynamicElementTextItem::Type) return true;
+			qgi->type() == DynamicElementTextItem::Type)
+			return true;
+		
+		if(qgi->type() == QGraphicsItemGroup::Type)
+			if(dynamic_cast<ElementTextItemGroup *>(qgi))
+				return true;
 	}
 	
 	return false;

Modified: trunk/sources/diagram.h
===================================================================
--- trunk/sources/diagram.h	2017-12-05 12:31:47 UTC (rev 5140)
+++ trunk/sources/diagram.h	2017-12-05 20:51:54 UTC (rev 5141)
@@ -121,7 +121,7 @@
 		void mouseMoveEvent        (QGraphicsSceneMouseEvent *event) override;
 		void mouseReleaseEvent     (QGraphicsSceneMouseEvent *event) override;
 		void wheelEvent            (QGraphicsSceneWheelEvent *event) override;
-		void keyPressEvent   (QKeyEvent *) override;
+		void keyPressEvent   (QKeyEvent *event) override;
 		void keyReleaseEvent (QKeyEvent *) override;
 	
 	public:
@@ -187,10 +187,8 @@
 		QList<CustomElement *> customElements() const;
 		QList<Element *> elements() const;
 		QList<Conductor *> conductors() const;
-		QSet<DiagramTextItem *> selectedTexts() const;
 		QSet<Conductor *> selectedConductors() const;
 		DiagramContent content() const;
-		DiagramContent selectedContent();
 		bool canRotateSelection() const;
 		int  beginMoveElements(QGraphicsItem * = nullptr);
 		void continueMoveElements(const QPointF &);

Modified: trunk/sources/diagramcommands.cpp
===================================================================
--- trunk/sources/diagramcommands.cpp	2017-12-05 12:31:47 UTC (rev 5140)
+++ trunk/sources/diagramcommands.cpp	2017-12-05 20:51:54 UTC (rev 5141)
@@ -26,6 +26,7 @@
 #include "diagram.h"
 #include "qetgraphicsitem/diagramtextitem.h"
 #include "qetgraphicsitem/diagramimageitem.h"
+#include "elementtextitemgroup.h"
 #include <QPropertyAnimation>
 
 QString itemText(const QetGraphicsItem *item) {
@@ -266,32 +267,36 @@
  * Move item and conductor to @actual_movement
  * @param actual_movement movement to be applied
  */
-void MoveElementsCommand::move(const QPointF &actual_movement) {
+void MoveElementsCommand::move(const QPointF &actual_movement)
+{
 	typedef DiagramContent dc;
 
-	//Move every movable item, except conductor
-	foreach (QGraphicsItem *qgi, content_to_move.items(dc::Elements | dc::TextFields | dc::Images | dc::Shapes)) {
-		//If curent item have parent, and parent item is in content_to_move
-		//we don't apply movement to this item, because this item will be moved by is parent.
-		if (qgi->parentItem()) {
+		//Move every movable items, except conductor
+	for (QGraphicsItem *qgi : content_to_move.items(dc::Elements | dc::TextFields | dc::Images | dc::Shapes | dc::TextGroup))
+	{
+			//If curent item have parent, and parent item is in content_to_move
+			//we don't apply movement to this item, because this item will be moved by is parent.
+		if (qgi->parentItem())
 			if (content_to_move.items().contains(qgi->parentItem()))
 					continue;
-		}
-		if(qgi->toGraphicsObject()) {
+		
+		if(qgi->toGraphicsObject())
 			setupAnimation(qgi->toGraphicsObject(), "pos", qgi->pos(), qgi->pos() + actual_movement);
+		else if(qgi->type() == QGraphicsItemGroup::Type) //ElementTextItemGroup is a QObject but not a QGraphicsObject
+		{
+			if(ElementTextItemGroup *etig = dynamic_cast<ElementTextItemGroup *>(qgi))
+				setupAnimation(etig, "pos", etig->pos(), etig->pos() + actual_movement);
 		}
 		else qgi -> setPos(qgi->pos() + actual_movement);
 	}
 	
-	// Move some conductors
-	foreach(Conductor *conductor, content_to_move.m_conductors_to_move) {
+		// Move some conductors
+	for (Conductor *conductor : content_to_move.m_conductors_to_move)
 		setupAnimation(conductor, "pos", conductor->pos(), conductor->pos() + actual_movement);
-	}
 	
-	// Recalcul the path of other conductor
-	foreach(Conductor *conductor, content_to_move.m_conductors_to_update) {
+		// Recalcul the path of other conductor
+	for (Conductor *conductor : content_to_move.m_conductors_to_update)
 		setupAnimation(conductor, "animPath", 1, 1);
-	}
 }
 
 /**
@@ -442,137 +447,6 @@
 
 /**
 	Constructeur
-	@param elements Elements a pivoter associes a leur orientation d'origine
-	@param texts Textes a pivoter
-	@param parent QUndoCommand parent
-*/
-RotateElementsCommand::RotateElementsCommand(const QList<Element *> &elements, const QList<DiagramTextItem *> &texts, const QList<DiagramImageItem *> &images, QUndoCommand *parent) :
-	QUndoCommand(parent),
-	elements_to_rotate(elements),
-	texts_to_rotate(texts),
-	images_to_rotate(images),
-	applied_rotation_angle_(90.0)
-{
-	if(elements_to_rotate.size()) diagram = elements_to_rotate.first()->diagram();
-	else if (texts_to_rotate.size()) diagram = texts_to_rotate.first()->diagram();
-	else if (images_to_rotate.size()) diagram = images_to_rotate.first()->diagram();
-
-	setText(
-		QString(
-			QObject::tr(
-				"pivoter %1",
-				"undo caption - %1 is a sentence listing the rotated content"
-			)
-		).arg(QET::ElementsAndConductorsSentence(elements.count(), 0, texts.count(), images.count()))
-	);
-}
-
-/// Destructeur
-RotateElementsCommand::~RotateElementsCommand() {
-}
-
-/// defait le pivotement
-void RotateElementsCommand::undo() {
-	diagram -> showMe();
-	foreach(Element *e, elements_to_rotate) {
-		e -> rotateBy(-applied_rotation_angle_);
-	}
-	foreach(DiagramTextItem *dti, texts_to_rotate) {
-		//ConductorTextItem have a default rotation angle, we apply a specific treatment
-		if (ConductorTextItem *cti = qgraphicsitem_cast<ConductorTextItem *>(dti)) {
-			cti -> forceRotateByUser(previous_rotate_by_user_[cti]);
-			(cti -> wasRotateByUser()) ? cti -> rotateBy(-applied_rotation_angle_) :
-										 cti -> parentConductor() -> calculateTextItemPosition();
-		}
-		else {dti -> rotateBy(-applied_rotation_angle_);}
-	}
-	foreach(DiagramImageItem *dii, images_to_rotate) dii -> rotateBy(-applied_rotation_angle_);
-}
-
-/// refait le pivotement
-void RotateElementsCommand::redo() {
-	diagram -> showMe();
-	foreach(Element *e, elements_to_rotate) {
-		e -> rotateBy(applied_rotation_angle_);
-	}
-	foreach(DiagramTextItem *dti, texts_to_rotate) {
-		//we grab the previous rotation by user of each ConductorTextItem
-		if (ConductorTextItem *cti = qgraphicsitem_cast<ConductorTextItem *>(dti)) {
-			previous_rotate_by_user_.insert(cti, cti -> wasRotateByUser());
-			cti -> forceRotateByUser(true);
-		}
-		dti -> rotateBy(applied_rotation_angle_);
-	}
-	foreach(DiagramImageItem *dii, images_to_rotate) dii -> rotateBy(applied_rotation_angle_);
-}
-
-/**
-	Constructeur
-	@param texts Liste des textes impactes par l'action. L'objet retiendra leur angle de rotation au moment de sa construction.
-	@param applied_rotation Nouvel angle de rotation, a appliquer au textes concernes
-	@param parent QUndoCommand parent
-*/
-RotateTextsCommand::RotateTextsCommand(const QList<DiagramTextItem *> &texts, double applied_rotation, QUndoCommand *parent) :
-	QUndoCommand(parent),
-	m_applied_rotation_angle(applied_rotation),
-	m_diagram(texts.first()->diagram())
-{
-	foreach(DiagramTextItem *text, texts) {
-		m_texts_to_rotate.insert(text, text -> rotationAngle());
-	}
-	defineCommandName();
-}
-
-/**
-	Destructeur
-*/
-RotateTextsCommand::~RotateTextsCommand() {
-}
-
-/**
-	Annule la rotation des textes
-*/
-void RotateTextsCommand::undo() {
-	m_diagram -> showMe();
-	foreach(DiagramTextItem *text, m_texts_to_rotate.keys()) {
-		if (ConductorTextItem *cti = qgraphicsitem_cast<ConductorTextItem *>(text))
-			cti -> forceRotateByUser(m_previous_rotate_by_user[cti]);
-		text -> setRotationAngle(m_texts_to_rotate[text]);
-	}
-}
-
-/**
-	Applique l'angle de rotation aux textes
-*/
-void RotateTextsCommand::redo() {
-	m_diagram -> showMe();
-	foreach(DiagramTextItem *text, m_texts_to_rotate.keys()) {
-		if (ConductorTextItem *cti = qgraphicsitem_cast<ConductorTextItem *>(text)) {
-			//we grab the previous rotation by user of each ConductorTextItem
-			m_previous_rotate_by_user.insert(cti, cti -> wasRotateByUser());
-			cti -> forceRotateByUser(true);
-		}
-		text -> setRotationAngle(m_applied_rotation_angle);
-	}
-}
-
-/**
-	Definit le nom de la commande d'annulation
-*/
-void RotateTextsCommand::defineCommandName() {
-	setText(
-		QString(
-			QObject::tr(
-				"orienter %1 à %2°",
-				"undo caption - %1 looks like '42 texts', %2 is a rotation angle"
-			)
-		).arg(QET::ElementsAndConductorsSentence(0, 0, m_texts_to_rotate.count()))
-		.arg(m_applied_rotation_angle)
-	);
-}
-
-/**
-	Constructeur
 	@param c Conducteur modifie
 	@param old_p ancien profil du conducteur
 	@param new_p nouveau profil du conducteur

Modified: trunk/sources/diagramcommands.h
===================================================================
--- trunk/sources/diagramcommands.h	2017-12-05 12:31:47 UTC (rev 5140)
+++ trunk/sources/diagramcommands.h	2017-12-05 20:51:54 UTC (rev 5141)
@@ -216,69 +216,6 @@
 };
 
 /**
-	This command rotates several elements or text items by a particular angle.
-*/
-class RotateElementsCommand : public QUndoCommand {
-	// constructors, destructor
-	public:
-	RotateElementsCommand(const QList<Element *> &elements, const QList<DiagramTextItem *> &, const QList<DiagramImageItem *> &, QUndoCommand * = nullptr);
-	~RotateElementsCommand() override;
-	private:
-	RotateElementsCommand(const RotateElementsCommand &);
-	
-	// methods
-	public:
-	void undo() override;
-	void redo() override;
-	
-	// attributes
-	private:
-	/// hold rotated elements along with their former orientation
-	QList<Element *> elements_to_rotate;
-	/// text items to be rotated
-	QList<DiagramTextItem *> texts_to_rotate;
-	/// images item to be rotated
-	QList<DiagramImageItem *> images_to_rotate;
-	/// angle of rotation to be applied to text items
-	qreal applied_rotation_angle_;
-	/// previous state of each conductor text item
-	QHash<ConductorTextItem *, bool> previous_rotate_by_user_;
-	Diagram *diagram;
-};
-
-/**
-	This command directs several text items to a same particular angle of
-	rotation.
-*/
-class RotateTextsCommand : public QUndoCommand
-{
-	// constructors, destructor
-	public:
-		RotateTextsCommand(const QList<DiagramTextItem *> &, double, QUndoCommand * = nullptr);
-		~RotateTextsCommand() override;
-	private:
-		RotateTextsCommand(const RotateTextsCommand &);
-	
-	// methods
-	public:
-		void undo() override;
-		void redo() override;
-	
-	private:
-		void defineCommandName();
-	
-	// attributes
-	private:
-		/// hold rotated text items along with their former angle of rotation
-		QHash<DiagramTextItem *, double> m_texts_to_rotate;
-		/// angle of rotation of all text items after the command
-		double m_applied_rotation_angle;
-		/// previous state of each conductor text item
-		QHash<ConductorTextItem *, bool> m_previous_rotate_by_user;
-		Diagram *m_diagram;
-};
-
-/**
 	This command changes a particular conductor.
 */
 class ChangeConductorCommand : public QUndoCommand {

Modified: trunk/sources/diagramcontent.cpp
===================================================================
--- trunk/sources/diagramcontent.cpp	2017-12-05 12:31:47 UTC (rev 5140)
+++ trunk/sources/diagramcontent.cpp	2017-12-05 20:51:54 UTC (rev 5141)
@@ -24,6 +24,10 @@
 #include "elementtextitem.h"
 #include "qetshapeitem.h"
 #include "dynamicelementtextitem.h"
+#include "elementtextitemgroup.h"
+#include "diagram.h"
+#include "terminal.h"
+#include "conductortextitem.h"
 
 /**
  * @brief DiagramContent::DiagramContent
@@ -32,6 +36,63 @@
 
 /**
  * @brief DiagramContent::DiagramContent
+ * Constructor
+ * @param diagram : Construct a diagramContent and fill it with the selected item of @diagram
+ */
+DiagramContent::DiagramContent(Diagram *diagram) :
+	m_selected_items(diagram->selectedItems())
+{
+		//Get the selected items
+	for (QGraphicsItem *item : m_selected_items)
+	{
+		if (Element *elmt = qgraphicsitem_cast<Element *>(item))
+			m_elements << elmt;
+		else if (IndependentTextItem *iti = qgraphicsitem_cast<IndependentTextItem *>(item))
+			m_text_fields << iti;
+		else if (Conductor *c = qgraphicsitem_cast<Conductor *>(item))
+		{
+				//Get the isolated selected conductor (= not movable, but deletable)
+			if (!c->terminal1->parentItem()->isSelected() &&\
+				!c->terminal2->parentItem()->isSelected()) {
+				m_other_conductors << c;
+			}
+		}
+		else if (DiagramImageItem *dii = qgraphicsitem_cast<DiagramImageItem *>(item))
+			m_images << dii;
+		else if (QetShapeItem *dsi = qgraphicsitem_cast<QetShapeItem *>(item))
+			m_shapes << dsi;
+		else if (DynamicElementTextItem *deti = qgraphicsitem_cast<DynamicElementTextItem *>(item))
+			m_element_texts << deti;
+		else if (QGraphicsItemGroup *group = qgraphicsitem_cast<QGraphicsItemGroup *>(item))
+			if(ElementTextItemGroup *etig = dynamic_cast<ElementTextItemGroup *>(group))
+				m_texts_groups << etig;
+	}
+	
+		//For each selected element, we determine if conductors must be moved or updated.
+	for(Element *elmt : m_elements)
+	{
+		for(Terminal *terminal : elmt->terminals())
+		{
+			for(Conductor *conductor : terminal->conductors())
+			{
+				Terminal *other_terminal;
+				if (conductor->terminal1 == terminal)
+					other_terminal = conductor->terminal2;
+				else
+					other_terminal = conductor->terminal1;
+
+					//If the two elements of conductor are movable
+				if (m_elements.contains(other_terminal -> parentElement()))
+					m_conductors_to_move << conductor;
+				else
+					m_conductors_to_update << conductor;
+			}
+		}
+	}
+}
+
+/**
+ * @brief DiagramContent::DiagramContent
  * Copy constructor
  * @param other
  */
@@ -43,7 +104,9 @@
 	m_conductors_to_update(other.m_conductors_to_update),
 	m_conductors_to_move(other.m_conductors_to_move),
 	m_other_conductors(other.m_other_conductors),
-	m_element_texts(other.m_element_texts)
+	m_element_texts(other.m_element_texts),
+	m_texts_groups(other.m_texts_groups),
+	m_selected_items(other.m_selected_items)
 {}
 
 /**
@@ -51,7 +114,48 @@
  */
 DiagramContent::~DiagramContent() {}
 
+
 /**
+ * @brief DiagramContent::selectedTexts
+ * @return a list of every selected texts (every kind of texts)
+ * Note that the returned list of texts, correspond to the selected texts
+ * at the moment of the creation of this DiagramContent,
+ * with the constructor :  DiagramContent::DiagramContent(Diagram *diagram)
+ */
+QList<DiagramTextItem *> DiagramContent::selectedTexts() const
+{
+	QList<DiagramTextItem *> selected_texts;
+	for(QGraphicsItem *qgi : m_selected_items)
+	{
+		if (qgi->type() == ConductorTextItem::Type ||
+			qgi->type() == ElementTextItem::Type ||
+			qgi->type() == IndependentTextItem::Type ||
+			qgi->type() == DynamicElementTextItem::Type)
+				selected_texts << static_cast<DiagramTextItem *>(qgi);
+	}
+	return(selected_texts);
+}
+
+/**
+ * @brief DiagramContent::selectedTextsGroup
+ * @return a list of selected texts group
+ * Note that the returned list of texts group, correspond to the selected texts group
+ * at the moment of the creation of this DiagramContent,
+ * with the constructor :  DiagramContent::DiagramContent(Diagram *diagram)
+ */
+QList<ElementTextItemGroup *> DiagramContent::selectedTextsGroup() const
+{
+	QList<ElementTextItemGroup *> groups;
+	
+	for(QGraphicsItem *qgi : m_selected_items)
+		if(qgi->type() == QGraphicsItemGroup::Type)
+			if(ElementTextItemGroup *grp = dynamic_cast<ElementTextItemGroup *>(qgi))
+				groups << grp;
+	
+	return groups;
+}
+
+/**
  * @brief DiagramContent::conductors
  * @param filter
  * @return Every conductors according to the filter
@@ -84,6 +188,8 @@
 	m_conductors_to_move.clear();
 	m_other_conductors.clear();
 	m_element_texts.clear();
+	m_texts_groups.clear();
+	m_selected_items.clear();
 }
 
 /**
@@ -138,6 +244,7 @@
 	if (filter & Images)            for(QGraphicsItem *qgi : m_images)        items_list << qgi;
 	if (filter & Shapes)            for(QGraphicsItem *qgi : m_shapes)        items_list << qgi;
 	if (filter & ElementTextFields) for(QGraphicsItem *qgi : m_element_texts) items_list << qgi;
+	if (filter & TextGroup)			for(QGraphicsItem *qgi : m_texts_groups)   items_list << qgi;
 
 	if (filter & SelectedOnly) {
 		for(QGraphicsItem *qgi : items_list) {
@@ -163,7 +270,8 @@
 		if (filter & ConductorsToMove)   for(Conductor *conductor : m_conductors_to_move)     { if (conductor -> isSelected()) ++ count; }
 		if (filter & ConductorsToUpdate) for(Conductor *conductor : m_conductors_to_update)   { if (conductor -> isSelected()) ++ count; }
 		if (filter & OtherConductors)    for(Conductor *conductor : m_other_conductors)       { if (conductor -> isSelected()) ++ count; }
-		if (filter & ElementTextFields)   for(DynamicElementTextItem *deti : m_element_texts) { if (deti      -> isSelected()) ++ count; }
+		if (filter & ElementTextFields)  for(DynamicElementTextItem *deti : m_element_texts)  { if (deti      -> isSelected()) ++ count; }
+		if (filter & TextGroup)          for(ElementTextItemGroup *etig : m_texts_groups)      { if (etig      -> isSelected()) ++ count; }
 	}
 	else {
 		if (filter & Elements)           count += m_elements.count();
@@ -174,6 +282,7 @@
 		if (filter & ConductorsToUpdate) count += m_conductors_to_update.count();
 		if (filter & OtherConductors)    count += m_other_conductors.count();
 		if (filter & ElementTextFields)  count += m_element_texts.count();
+		if (filter & TextGroup)			 count += m_texts_groups.count();
 	}
 	return(count);
 }

Modified: trunk/sources/diagramcontent.h
===================================================================
--- trunk/sources/diagramcontent.h	2017-12-05 12:31:47 UTC (rev 5140)
+++ trunk/sources/diagramcontent.h	2017-12-05 20:51:54 UTC (rev 5141)
@@ -28,6 +28,9 @@
 class ElementTextItem;
 class QetShapeItem;
 class DynamicElementTextItem;
+class ElementTextItemGroup;
+class Diagram;
+class DiagramTextItem;
 
 /**
 	This class provides a container that makes the transmission of diagram content
@@ -42,6 +45,7 @@
 {
 	public:
 		DiagramContent();
+		DiagramContent(Diagram *diagram);
 		DiagramContent(const DiagramContent &);
 		~DiagramContent();
 		
@@ -56,8 +60,9 @@
 			OtherConductors = 64,
 			AnyConductor = 112,
 			Shapes = 128,
-			All = 255,
-			SelectedOnly = 256
+			TextGroup = 256,
+			All = 511,
+			SelectedOnly = 512
 		};
 		
 		QSet<Element *> m_elements;
@@ -68,7 +73,11 @@
 		QSet<Conductor *> m_conductors_to_move;
 		QSet<Conductor *> m_other_conductors;
 		QSet<DynamicElementTextItem *> m_element_texts;
+		QSet<ElementTextItemGroup *> m_texts_groups;
+		QList<QGraphicsItem *> m_selected_items;
 		
+		QList<DiagramTextItem *> selectedTexts() const;
+		QList<ElementTextItemGroup *> selectedTextsGroup() const;
 		QList<Conductor *> conductors(int = AnyConductor) const;
 		QList<QGraphicsItem *> items(int = All) const;
 		QString sentence(int = All) const;

Modified: trunk/sources/diagramview.cpp
===================================================================
--- trunk/sources/diagramview.cpp	2017-12-05 12:31:47 UTC (rev 5140)
+++ trunk/sources/diagramview.cpp	2017-12-05 20:51:54 UTC (rev 5141)
@@ -28,7 +28,6 @@
 #include "qetgraphicsitem/independenttextitem.h"
 #include "qetgraphicsitem/diagramimageitem.h"
 #include "templatelocation.h"
-#include "qetapp.h"
 #include "qetproject.h"
 #include "projectview.h"
 #include "integrationmovetemplateshandler.h"
@@ -35,7 +34,6 @@
 #include "qetdiagrameditor.h"
 #include "qeticons.h"
 #include "qetmessagebox.h"
-#include "qtextorientationspinboxwidget.h"
 #include <QGraphicsObject>
 #include <QGraphicsPixmapItem>
 #include <QGraphicsSceneMouseEvent>
@@ -136,7 +134,7 @@
 {
 	if (m_diagram -> isReadOnly())
 		return;
-	DiagramContent removed_content = m_diagram->selectedContent();
+	DiagramContent removed_content = DiagramContent(m_diagram);
 	m_diagram->clearSelection();
 	m_diagram->undoStack().push(new DeleteQGraphicsItemCommand(m_diagram, removed_content));
 	adjustSceneRect();
@@ -143,105 +141,6 @@
 }
 
 /**
- * @brief DiagramView::rotateSelection
- * Rotate the selected items
- */
-void DiagramView::rotateSelection()
-{
-	if (m_diagram->isReadOnly())
-		return;
-
-	QList<Element *> elements_to_rotate;
-	QList<DiagramTextItem *> texts_to_rotate;
-	QList<DiagramImageItem *> images_to_rotate;
-	
-	for (QGraphicsItem *item : m_diagram->selectedItems())
-	{
-		if (Element *e = qgraphicsitem_cast<Element *>(item))
-			elements_to_rotate << e;
-		else if (ConductorTextItem *cti = qgraphicsitem_cast<ConductorTextItem *>(item))
-			texts_to_rotate << cti;
-		else if (IndependentTextItem *iti = qgraphicsitem_cast<IndependentTextItem *>(item))
-			texts_to_rotate << iti;
-		else if (ElementTextItem *eti = qgraphicsitem_cast<ElementTextItem *>(item))
-		{
-				//We rotate element text item only if is parent element is not selected
-			if (eti->parentItem() && !eti->parentItem()->isSelected())
-				texts_to_rotate << eti;
-		}
-		else if (DynamicElementTextItem *deti = qgraphicsitem_cast<DynamicElementTextItem *>(item))
-		{
-				//We rotate dynamic element text item only if is parent element is not selected
-			if (deti->parentItem() && !deti->parentItem()->isSelected())
-				texts_to_rotate << deti;
-		}
-		else if (DiagramImageItem *dii = qgraphicsitem_cast<DiagramImageItem *>(item))
-			images_to_rotate << dii;
-	}
-
-		//Do the rotation
-	if (elements_to_rotate.isEmpty() && texts_to_rotate.isEmpty() && images_to_rotate.isEmpty())
-		return;
-	m_diagram->undoStack().push(new RotateElementsCommand(elements_to_rotate, texts_to_rotate, images_to_rotate));
-}
-
-/**
- * @brief DiagramView::rotateTexts
- * Open a dialog to set the rotation angle, and apply it to the selected texts.
- */
-void DiagramView::rotateTexts()
-{
-	if (m_diagram->isReadOnly())
-		return;
-
-		//Get the texts fields
-	QList<DiagramTextItem *> texts_to_rotate;
-	for (QGraphicsItem *item : m_diagram->selectedItems())
-	{
-		if (ConductorTextItem *cti = qgraphicsitem_cast<ConductorTextItem *>(item))
-			texts_to_rotate << cti;
-		else if (IndependentTextItem *iti = qgraphicsitem_cast<IndependentTextItem *>(item))
-			texts_to_rotate << iti;
-		else if (ElementTextItem *eti = qgraphicsitem_cast<ElementTextItem *>(item))
-			texts_to_rotate << eti;
-		else if (DynamicElementTextItem *deti = qgraphicsitem_cast<DynamicElementTextItem *>(item))
-			texts_to_rotate << deti;
-	}
-	
-	if (texts_to_rotate.isEmpty())
-		return;
-
-		//Open the dialog
-	QDialog ori_text_dialog(diagramEditor());
-	ori_text_dialog.setSizeGripEnabled(false);
-#ifdef Q_OS_MAC
-	ori_text_dialog.setWindowFlags(Qt::Sheet);
-#endif
-	ori_text_dialog.setWindowTitle(tr("Orienter les textes sélectionnés", "window title"));
-
-
-	QTextOrientationSpinBoxWidget *ori_widget = QETApp::createTextOrientationSpinBoxWidget();
-	ori_widget -> setParent(&ori_text_dialog);
-	if (texts_to_rotate.count() == 1) {
-		ori_widget -> setOrientation(texts_to_rotate.at(0) -> rotationAngle());
-	}
-	ori_widget -> spinBox() -> selectAll();
-
-	QDialogButtonBox buttons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
-	connect(&buttons, SIGNAL(accepted()), &ori_text_dialog, SLOT(accept()));
-	connect(&buttons, SIGNAL(rejected()), &ori_text_dialog, SLOT(reject()));
-	
-	QVBoxLayout layout_v(&ori_text_dialog);
-	layout_v.setSizeConstraint(QLayout::SetFixedSize);
-	layout_v.addWidget(ori_widget);
-	layout_v.addStretch();
-	layout_v.addWidget(&buttons);
-
-	if (ori_text_dialog.exec() == QDialog::Accepted)
-		m_diagram -> undoStack().push(new RotateTextsCommand(texts_to_rotate, ori_widget -> orientation()));
-}
-
-/**
 	Accepte ou refuse le drag'n drop en fonction du type de donnees entrant
 	@param e le QDragEnterEvent correspondant au drag'n drop tente
 */
@@ -258,14 +157,6 @@
 }
 
 /**
-	Gere les dragleave
-	@param e le QDragEnterEvent correspondant au drag'n drop sortant
-*/
-void DiagramView::dragLeaveEvent(QDragLeaveEvent *e) {
-	Q_UNUSED(e);
-}
-
-/**
 	Accepte ou refuse le drag'n drop en fonction du type de donnees entrant
 	@param e le QDragMoveEvent correspondant au drag'n drop tente
 */
@@ -451,7 +342,7 @@
 */
 void DiagramView::cut() {
 	copy();
-	DiagramContent cut_content = m_diagram -> selectedContent();
+	DiagramContent cut_content(m_diagram);
 	m_diagram -> clearSelection();
 	m_diagram -> undoStack().push(new CutDiagramCommand(m_diagram, cut_content));
 }
@@ -651,6 +542,7 @@
 		return;
 	
 	ProjectView *current_project = this->diagramEditor()->acessCurrentProject();
+	DiagramContent dc(m_diagram);
 	switch(e -> key())
 	{
 		case Qt::Key_PageUp:
@@ -702,22 +594,22 @@
 		}
 			break;
 		case Qt::Key_Up: {
-			if(!(m_diagram->selectedContent().items(DiagramContent::All).isEmpty()))
+			if(!(dc.items(DiagramContent::All).isEmpty()))
 				scrollOnMovement(e);
 		}
 			break;
 		case Qt::Key_Down: {
-			if(!(m_diagram->selectedContent().items(DiagramContent::All).isEmpty()))
+			if(!(dc.items(DiagramContent::All).isEmpty()))
 				scrollOnMovement(e);
 		}
 			break;
 		case Qt::Key_Left: {
-			if(!(m_diagram->selectedContent().items(DiagramContent::All).isEmpty()))
+			if(!(dc.items(DiagramContent::All).isEmpty()))
 				scrollOnMovement(e);
 		}
 			break;
 		case Qt::Key_Right: {
-			if(!(m_diagram->selectedContent().items(DiagramContent::All).isEmpty()))
+			if(!(dc.items(DiagramContent::All).isEmpty()))
 				scrollOnMovement(e);
 		}
 			break;
@@ -743,8 +635,9 @@
 	and horizontal bar. If element is moved to the right side of the editor
 	or below the editor SceneRect is expanded
 */
-void DiagramView::scrollOnMovement(QKeyEvent *e){
-			QList<QGraphicsItem *> selected_elmts = m_diagram->selectedContent().items(DiagramContent::All);
+void DiagramView::scrollOnMovement(QKeyEvent *e)
+{
+			QList<QGraphicsItem *> selected_elmts = DiagramContent(m_diagram).items(DiagramContent::All);
 			QRectF viewed_scene = viewedSceneRect();
 			foreach (QGraphicsItem *qgi, selected_elmts){
 				if (qgraphicsitem_cast<Conductor *>(qgi)) continue;
@@ -823,13 +716,6 @@
 }
 
 /**
-	@return true s'il y a des items selectionnes sur le schema, false sinon
-*/
-bool DiagramView::hasSelectedItems() {
-	return(m_diagram -> selectedItems().size() > 0);
-}
-
-/**
 	@return true s'il y a des items selectionnes sur le schema et que ceux-ci
 	peuvent etre copies dans le presse-papier, false sinon
 */
@@ -1011,11 +897,13 @@
 }
 
 /**
-	Edite les proprietes des objets selectionnes
-*/
-void DiagramView::editSelectionProperties() {
-	// get selection
-	DiagramContent selection = m_diagram -> selectedContent();
+ * @brief DiagramView::editSelectionProperties
+ * Edit the properties of the selected items
+ */
+void DiagramView::editSelectionProperties()
+{
+		// get selection
+	DiagramContent selection(m_diagram);
 
 	// if selection contains nothing return
 	int selected_items_count = selection.count(DiagramContent::All | DiagramContent::SelectedOnly);
@@ -1048,13 +936,15 @@
 }
 
 /**
-	Edit the color of the selected conductor; does nothing if multiple conductors are selected
-*/
-void DiagramView::editSelectedConductorColor() {
-	// retrieve selected content
-	DiagramContent selection = m_diagram -> selectedContent();
+ * @brief DiagramView::editSelectedConductorColor
+ * Edit the color of the selected conductor; does nothing if multiple conductors are selected
+ */
+void DiagramView::editSelectedConductorColor()
+{
+		//retrieve selected content
+	DiagramContent selection(m_diagram);
 
-	// we'll focus on the selected conductor (we do not handle multiple conductors edition)
+		// we'll focus on the selected conductor (we do not handle multiple conductors edition)
 	QList<Conductor *> selected_conductors = selection.conductors(DiagramContent::AnyConductor | DiagramContent::SelectedOnly);
 	if (selected_conductors.count() == 1) {
 		editConductorColor(selected_conductors.at(0));

Modified: trunk/sources/diagramview.h
===================================================================
--- trunk/sources/diagramview.h	2017-12-05 12:31:47 UTC (rev 5140)
+++ trunk/sources/diagramview.h	2017-12-05 20:51:54 UTC (rev 5141)
@@ -49,10 +49,10 @@
 	
 		// attributes
 
-		Diagram          *m_diagram;
+		Diagram          *m_diagram = nullptr;
 		DVEventInterface *m_event_interface = nullptr;
-		QMenu            *m_context_menu;
-		QAction          *m_paste_here;
+		QMenu            *m_context_menu = nullptr;
+		QAction          *m_paste_here = nullptr;
 		QPoint            m_paste_here_pos;
 		QPointF           m_rubber_band_origin;
 		bool              m_fresh_focus_in,
@@ -64,10 +64,8 @@
 		void removeColumn();
 		void addRow();
 		void removeRow();
-		/// @return the diagram rendered by this view
 		Diagram *diagram() { return(m_diagram); }
 		QETDiagramEditor *diagramEditor() const;
-		bool hasSelectedItems();
 		bool hasCopiableItems();
 		bool hasTextItems();
 		bool hasDeletableItems();
@@ -92,7 +90,6 @@
 		void mouseMoveEvent(QMouseEvent *) override;
 		void mouseReleaseEvent(QMouseEvent *) override;
 		void dragEnterEvent(QDragEnterEvent *) override;
-		void dragLeaveEvent(QDragLeaveEvent *) override;
 		void dragMoveEvent(QDragMoveEvent *) override;
 		void dropEvent(QDropEvent *) override;
 		void handleElementDrop(QDropEvent *);
@@ -123,8 +120,6 @@
 		void selectAll();
 		void selectInvert();
 		void deleteSelection();
-		void rotateSelection();
-		void rotateTexts();
 		void setVisualisationMode();
 		void setSelectionMode();
 		void zoom(const qreal zoom_factor);

Modified: trunk/sources/elementsmover.cpp
===================================================================
--- trunk/sources/elementsmover.cpp	2017-12-05 12:31:47 UTC (rev 5140)
+++ trunk/sources/elementsmover.cpp	2017-12-05 20:51:54 UTC (rev 5141)
@@ -33,8 +33,8 @@
 	movement_running_(false),
 	current_movement_(),
 	diagram_(nullptr),
-	movement_driver_(nullptr),
-	moved_content_()
+	m_movement_driver(nullptr),
+	m_moved_content()
 {
 	
 }
@@ -70,21 +70,21 @@
 	diagram_ = diagram;
 	
 	// Take count of driver item
-	movement_driver_ = driver_item;
+	m_movement_driver = driver_item;
 	
 	// At the beginning of movement, move is NULL
 	current_movement_ = QPointF(0.0, 0.0);
 	
-	moved_content_ = diagram -> selectedContent();
-	moved_content_.removeNonMovableItems();
+	m_moved_content = DiagramContent(diagram);
+	m_moved_content.removeNonMovableItems();
 
-	if (!moved_content_.count()) return(-1);
+	if (!m_moved_content.count()) return(-1);
 	
 	/* At this point, we've got all info to manage movement.
 	 * There is now a move in progress */
 	movement_running_ = true;
 	
-	return(moved_content_.count());
+	return(m_moved_content.count());
 }
 
 /**
@@ -99,18 +99,20 @@
 
 	//Move every movable item, except conductor
 	typedef DiagramContent dc;
-	foreach (QGraphicsItem *qgi, moved_content_.items(dc::Elements | dc::TextFields | dc::Images | dc::Shapes)) {
-		if (qgi == movement_driver_) continue;
+	for (QGraphicsItem *qgi : m_moved_content.items(dc::Elements | dc::TextFields | dc::Images | dc::Shapes | dc::TextGroup))
+	{
+		if (qgi == m_movement_driver)
+			continue;
 		qgi -> setPos(qgi->pos() + movement);
 	}
 	
 	// Move some conductors
-	foreach(Conductor *conductor, moved_content_.m_conductors_to_move) {
+	foreach(Conductor *conductor, m_moved_content.m_conductors_to_move) {
 		conductor -> setPos(conductor -> pos() + movement);
 	}
 	
 	// Recalcul the path of other conductors
-	foreach(Conductor *conductor, moved_content_.m_conductors_to_update) {
+	foreach(Conductor *conductor, m_moved_content.m_conductors_to_update) {
 		conductor -> updatePath();
 	}
 }
@@ -131,7 +133,7 @@
 
 		//Create undo move if there is a movement
 	if (!current_movement_.isNull()) {
-		QUndoCommand *quc = new MoveElementsCommand(diagram_, moved_content_, current_movement_, undo_object);
+		QUndoCommand *quc = new MoveElementsCommand(diagram_, m_moved_content, current_movement_, undo_object);
 		undo_object->setText(quc->text());
 	}
 
@@ -138,11 +140,11 @@
 		//There is only one element moved, and project authorize auto conductor,
 		//we try auto connection of conductor;
 	typedef DiagramContent dc;
-	if (moved_content_.items(dc::TextFields | dc::Images | dc::Shapes).size() == 0 &&
-		moved_content_.items(dc::Elements).size() == 1 &&
+	if (m_moved_content.items(dc::TextFields | dc::Images | dc::Shapes).size() == 0 &&
+		m_moved_content.items(dc::Elements).size() == 1 &&
 		diagram_ -> project() -> autoConductor())
 	{
-		Element *elmt = moved_content_.m_elements.toList().first();
+		Element *elmt = m_moved_content.m_elements.toList().first();
 
 		int acc = elmt->AlignedFreeTerminals().size();
 

Modified: trunk/sources/elementsmover.h
===================================================================
--- trunk/sources/elementsmover.h	2017-12-05 12:31:47 UTC (rev 5140)
+++ trunk/sources/elementsmover.h	2017-12-05 20:51:54 UTC (rev 5141)
@@ -55,7 +55,7 @@
 	bool movement_running_;
 	QPointF current_movement_;
 	Diagram *diagram_;
-	QGraphicsItem *movement_driver_;
-	DiagramContent moved_content_;
+	QGraphicsItem *m_movement_driver;
+	DiagramContent m_moved_content;
 };
 #endif

Modified: trunk/sources/qetdiagrameditor.cpp
===================================================================
--- trunk/sources/qetdiagrameditor.cpp	2017-12-05 12:31:47 UTC (rev 5140)
+++ trunk/sources/qetdiagrameditor.cpp	2017-12-05 20:51:54 UTC (rev 5141)
@@ -45,6 +45,8 @@
 #include "dynamicelementtextitem.h"
 #include "conductortextitem.h"
 #include "elementtextitem.h"
+#include "undocommand/rotateselectioncommand.h"
+#include "rotatetextscommand.h"
 
 #include <QMessageBox>
 #include <QStandardPaths>
@@ -1038,12 +1040,15 @@
 	  * no element is selected
 	  * more than one element is selected
 */
-Element *QETDiagramEditor::currentElement() const {
+Element *QETDiagramEditor::currentElement() const
+{
 	DiagramView *dv = currentDiagram();
-	if (!dv) return(nullptr);
+	if (!dv)
+		return(nullptr);
 	
-	QList<Element *> selected_elements = dv -> diagram() -> selectedContent().m_elements.toList();
-	if (selected_elements.count() != 1) return(nullptr);
+	QList<Element *> selected_elements = DiagramContent(dv->diagram()).m_elements.toList();
+	if (selected_elements.count() != 1)
+		return(nullptr);
 	
 	return(selected_elements.first());
 }
@@ -1262,9 +1267,17 @@
 	if (value == "delete_selection")
 		dv->deleteSelection();
 	else if (value == "rotate_selection")
-		dv->rotateSelection();
+	{
+		Diagram *d = dv->diagram();
+		RotateSelectionCommand *c = new RotateSelectionCommand(d);
+		if(c->isValid())
+			d->undoStack().push(c);
+	}
 	else if (value == "rotate_selected_text")
-		dv->rotateTexts();
+	{
+		Diagram *d = dv->diagram();
+		d->undoStack().push(new RotateTextsCommand(d));
+	}
 	else if (value == "find_selected_element" && currentCustomElement())
 		findElementInPanel(currentCustomElement()->location());
 	else if (value == "edit_selected_element")
@@ -1400,6 +1413,7 @@
 	}
 	
 	Diagram *diagram_ = dv->diagram();
+	DiagramContent dc(diagram_);
 	bool ro = diagram_->isReadOnly();
 	
 
@@ -1408,7 +1422,7 @@
 	m_conductor_reset->setEnabled(!ro && selected_conductors_count);
 	
 		// number of selected elements
-	int selected_elements_count = diagram_->selectedContent().count(DiagramContent::Elements);
+	int selected_elements_count = dc.count(DiagramContent::Elements);
 	m_find_element->setEnabled(selected_elements_count == 1);
 	
 		//Action that need items (elements, conductors, texts...) selected, to be enabled
@@ -1419,17 +1433,19 @@
 	m_delete_selection -> setEnabled(!ro && deletable_items);
 	m_rotate_selection -> setEnabled(!ro && diagram_->canRotateSelection());
 
-		//Action that need selected texts
-	int selected_texts = diagram_->selectedTexts().count();
-	int selected_conductor_texts   = 0; for(DiagramTextItem *dti : diagram_->selectedTexts()) {if(dti->type() == ConductorTextItem::Type) selected_conductor_texts++;}
-	int selected_element_texts     = 0; for(DiagramTextItem *dti : diagram_->selectedTexts()) {if(dti->type() == ElementTextItem::Type) selected_element_texts++;}
-	int selected_dynamic_elmt_text = 0; for(DiagramTextItem *dti : diagram_->selectedTexts()) {if(dti->type() == DynamicElementTextItem::Type) selected_dynamic_elmt_text++;}
-	m_rotate_texts -> setEnabled(!ro && selected_texts);
+		//Action that need selected texts or texts group
+	QList<DiagramTextItem *> texts = DiagramContent(diagram_).selectedTexts();
+	QList<ElementTextItemGroup *> groups = DiagramContent(diagram_).selectedTextsGroup();
+	int selected_texts = texts.count();
+	int selected_conductor_texts   = 0; for(DiagramTextItem *dti : texts) {if(dti->type() == ConductorTextItem::Type) selected_conductor_texts++;}
+	int selected_element_texts     = 0; for(DiagramTextItem *dti : texts) {if(dti->type() == ElementTextItem::Type) selected_element_texts++;}
+	int selected_dynamic_elmt_text = 0; for(DiagramTextItem *dti : texts) {if(dti->type() == DynamicElementTextItem::Type) selected_dynamic_elmt_text++;}
+	m_rotate_texts->setEnabled(!ro && (selected_texts || groups.size()));
 
 		// actions need only one editable item
-	int selected_image = diagram_-> selectedContent().count(DiagramContent::Images);
+	int selected_image = dc.count(DiagramContent::Images);
 
-	int selected_shape = diagram_-> selectedContent().count(DiagramContent::Shapes);
+	int selected_shape = dc.count(DiagramContent::Shapes);
 	int selected_editable = selected_elements_count +
 							(selected_texts - selected_conductor_texts - selected_element_texts - selected_dynamic_elmt_text) +
 							selected_image +

Modified: trunk/sources/qetgraphicsitem/elementtextitemgroup.cpp
===================================================================
--- trunk/sources/qetgraphicsitem/elementtextitemgroup.cpp	2017-12-05 12:31:47 UTC (rev 5140)
+++ trunk/sources/qetgraphicsitem/elementtextitemgroup.cpp	2017-12-05 20:51:54 UTC (rev 5141)
@@ -20,6 +20,7 @@
 #include "element.h"
 #include "diagram.h"
 #include "addelementtextcommand.h"
+#include "QPropertyUndoCommand/qpropertyundocommand.h"
 
 #include <QPainter>
 #include <QGraphicsSceneMouseEvent>
@@ -37,7 +38,7 @@
 	QGraphicsItemGroup(parent),
 	m_name(name)
 {
-	setFlags(QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsFocusable);
+	setFlags(QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsMovable);
 }
 
 ElementTextItemGroup::~ElementTextItemGroup()
@@ -127,7 +128,6 @@
 				item->setPos(ref.x(), ref.y()+y_offset);
 				y_offset+=item->boundingRect().height();
 			}
-			return;
 		}
 		else if(m_alignment == Qt::AlignVCenter)
 		{
@@ -139,9 +139,7 @@
 				item->setPos(ref.x() - item->boundingRect().width()/2,
 							 ref.y() + y_offset);
 				y_offset+=item->boundingRect().height();
-			}
-			return;
-				
+			}	
 		}
 		else if (m_alignment == Qt::AlignRight)
 		{
@@ -154,8 +152,9 @@
 							 ref.y() + y_offset);
 				y_offset+=item->boundingRect().height();
 			}
-			return;
 		}
+		
+		setTransformOriginPoint(boundingRect().topLeft());
 	}
 }
 
@@ -381,26 +380,30 @@
  */
 void ElementTextItemGroup::keyPressEvent(QKeyEvent *event)
 {	
-	if(event->key() == Qt::Key_A && m_alignment	!= Qt::AlignLeft)
+ 	if(event->modifiers() == Qt::ControlModifier)
 	{
-		if(diagram())
-			diagram()->undoStack().push(new AlignmentTextsGroupCommand(this, Qt::AlignLeft));
-		else
-			setAlignment(Qt::AlignLeft);
+		if(event->key() == Qt::Key_Left && m_alignment	!= Qt::AlignLeft)
+		{
+			if(diagram())
+				diagram()->undoStack().push(new AlignmentTextsGroupCommand(this, Qt::AlignLeft));
+			else
+				setAlignment(Qt::AlignLeft);
+		}
+		else if (event->key() == Qt::Key_Up && m_alignment	!= Qt::AlignVCenter)
+		{
+			if(diagram())
+				diagram()->undoStack().push(new AlignmentTextsGroupCommand(this, Qt::AlignVCenter));
+			else
+				setAlignment(Qt::AlignVCenter);
+		}
+		else if (event->key() == Qt::Key_Right && m_alignment	!= Qt::AlignRight)
+		{
+			if(diagram())
+				diagram()->undoStack().push(new AlignmentTextsGroupCommand(this, Qt::AlignRight));
+			else
+				setAlignment(Qt::AlignRight);
+		}
 	}
-	else if (event->key() == Qt::Key_Z && m_alignment	!= Qt::AlignVCenter)
-	{
-		if(diagram())
-			diagram()->undoStack().push(new AlignmentTextsGroupCommand(this, Qt::AlignVCenter));
-		else
-			setAlignment(Qt::AlignVCenter);
-	}
-	else if (event->key() == Qt::Key_E && m_alignment	!= Qt::AlignRight)
-	{
-		if(diagram())
-			diagram()->undoStack().push(new AlignmentTextsGroupCommand(this, Qt::AlignRight));
-		else
-			setAlignment(Qt::AlignRight);
-	}
+	event->ignore();
 }
 

Modified: trunk/sources/qetgraphicsitem/elementtextitemgroup.h
===================================================================
--- trunk/sources/qetgraphicsitem/elementtextitemgroup.h	2017-12-05 12:31:47 UTC (rev 5140)
+++ trunk/sources/qetgraphicsitem/elementtextitemgroup.h	2017-12-05 20:51:54 UTC (rev 5141)
@@ -36,6 +36,7 @@
 	Q_OBJECT
 	
 	Q_PROPERTY(QPointF pos READ pos WRITE setPos)
+	Q_PROPERTY(qreal rotation READ rotation WRITE setRotation)
 	
 	public:
 		ElementTextItemGroup(const QString &name, Element *parent);

Added: trunk/sources/undocommand/rotateselectioncommand.cpp
===================================================================
--- trunk/sources/undocommand/rotateselectioncommand.cpp	                        (rev 0)
+++ trunk/sources/undocommand/rotateselectioncommand.cpp	2017-12-05 20:51:54 UTC (rev 5141)
@@ -0,0 +1,154 @@
+/*
+	Copyright 2006-2017 The QElectroTech Team
+	This file is part of QElectroTech.
+	
+	QElectroTech is free software: you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation, either version 2 of the License, or
+	(at your option) any later version.
+	
+	QElectroTech is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+	
+	You should have received a copy of the GNU General Public License
+	along with QElectroTech.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "rotateselectioncommand.h"
+#include "element.h"
+#include "conductortextitem.h"
+#include "independenttextitem.h"
+#include "elementtextitem.h"
+#include "dynamicelementtextitem.h"
+#include "elementtextitemgroup.h"
+#include "diagramimageitem.h"
+#include "diagram.h"
+#include "conductor.h"
+
+#include <QGraphicsItem>
+
+RotateSelectionCommand::RotateSelectionCommand(Diagram *diagram, qreal angle, QUndoCommand *parent) :
+QUndoCommand(parent),
+m_diagram(diagram),
+m_angle(angle)
+{
+	setText(QObject::tr("Pivoter la selection"));
+	
+	if(!m_diagram->isReadOnly())
+	{
+		for (QGraphicsItem *item : m_diagram->selectedItems())
+		{
+			switch (item->type())
+			{
+				case Element::Type:
+					m_element << static_cast<Element *>(item);
+					break;
+				case ConductorTextItem::Type:
+					m_text << static_cast<DiagramTextItem *>(item);
+					break;
+				case IndependentTextItem::Type:
+					m_text << static_cast<DiagramTextItem *>(item);
+					break;
+				case ElementTextItem::Type:
+					if(item->parentItem() && !item->parentItem()->isSelected())
+						m_text << static_cast<DiagramTextItem *>(item);
+					break;
+				case DynamicElementTextItem::Type:
+					if(item->parentItem() && !item->parentItem()->isSelected())
+						m_text << static_cast<DiagramTextItem *>(item);
+					break;
+				case QGraphicsItemGroup::Type:
+					if(ElementTextItemGroup *grp = dynamic_cast<ElementTextItemGroup *>(item))
+						if(grp->parentElement() && !grp->parentElement()->isSelected())
+							m_group << grp;
+					break;
+				case DiagramImageItem::Type:
+					m_image << static_cast<DiagramImageItem *>(item);
+					break;
+				default:
+					break;
+			}
+		}
+	}
+}
+
+/**
+ * @brief RotateSelectionCommand::undo
+ */
+void RotateSelectionCommand::undo()
+{
+	m_diagram->showMe();
+	
+	for(QPointer<Element> elmt : m_element)
+		if(elmt)
+			elmt.data()->rotateBy(-m_angle);
+	for(QPointer<DiagramTextItem> text : m_text)
+	{
+		if(text)
+		{
+			if(text.data()->type() == ConductorTextItem::Type)
+			{
+				ConductorTextItem *cti = static_cast<ConductorTextItem *>(text.data());
+				cti->forceRotateByUser(m_rotate_by_user.value(text.data()));
+				if(cti->wasRotateByUser())
+					cti->rotateBy(-m_angle);
+				else
+					cti->parentConductor()->calculateTextItemPosition();
+			}
+			else
+				text.data()->rotateBy(-m_angle);
+		}
+	}
+	for(QPointer<DiagramImageItem> image : m_image)
+		if(image)
+			image.data()->rotateBy(-m_angle);
+	for(QPointer<ElementTextItemGroup> group : m_group)
+		if(group)
+			group.data()->setRotation(group.data()->rotation() - m_angle);
+}
+
+/**
+ * @brief RotateSelectionCommand::redo
+ */
+void RotateSelectionCommand::redo()
+{
+	m_diagram->showMe();
+	
+	for(QPointer<Element> elmt : m_element)
+		if(elmt)
+			elmt.data()->rotateBy(m_angle);
+	for(QPointer<DiagramTextItem> text : m_text)
+	{
+		if(text)
+		{
+			if(text.data()->type() == ConductorTextItem::Type)
+			{
+				ConductorTextItem *cti = static_cast<ConductorTextItem *>(text.data());
+				m_rotate_by_user.insert(text.data(), cti->wasRotateByUser());
+				cti->forceRotateByUser(true);
+			}
+			text.data()->rotateBy(m_angle);
+		}
+	}
+	for(QPointer<DiagramImageItem> image : m_image)
+		if(image)
+			image.data()->rotateBy(m_angle);
+	for(QPointer<ElementTextItemGroup> group : m_group)
+		if(group)
+			group.data()->setRotation(group.data()->rotation() + m_angle);
+}
+
+/**
+ * @brief RotateSelectionCommand::isValid
+ * @return true if this command rotate a least one item.
+ */
+bool RotateSelectionCommand::isValid()
+{
+	if(m_element.size()) return true;
+	if(m_image.size())   return true;
+	if(m_group.size())   return true;
+	if(m_text.size())    return true;
+	
+	return false;
+}

Added: trunk/sources/undocommand/rotateselectioncommand.h
===================================================================
--- trunk/sources/undocommand/rotateselectioncommand.h	                        (rev 0)
+++ trunk/sources/undocommand/rotateselectioncommand.h	2017-12-05 20:51:54 UTC (rev 5141)
@@ -0,0 +1,56 @@
+/*
+	Copyright 2006-2017 The QElectroTech Team
+	This file is part of QElectroTech.
+	
+	QElectroTech is free software: you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation, either version 2 of the License, or
+	(at your option) any later version.
+	
+	QElectroTech is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+	
+	You should have received a copy of the GNU General Public License
+	along with QElectroTech.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef ROTATESELECTIONCOMMAND_H
+#define ROTATESELECTIONCOMMAND_H
+
+#include <QUndoCommand>
+#include <QPointer>
+
+class Diagram;
+class Element;
+class QGraphicsObject;
+class ElementTextItemGroup;
+class DiagramTextItem;
+class DiagramImageItem;
+
+/**
+ * @brief The RotateSelectionCommand class
+ * Rotate the selected items in the given diagram
+ */
+class RotateSelectionCommand : public QUndoCommand
+{
+	public:
+		RotateSelectionCommand(Diagram *diagram, qreal angle=90, QUndoCommand *parent=nullptr);
+		void undo() override;
+		void redo() override;
+		
+		bool isValid();
+	
+	private:
+		Diagram *m_diagram =nullptr;
+		qreal m_angle;
+		
+		QList<QPointer<Element>> m_element;
+		QList<QPointer<DiagramImageItem>> m_image;
+		QList<QPointer<ElementTextItemGroup>> m_group;
+		QList<QPointer<DiagramTextItem>> m_text;
+		QHash<DiagramTextItem *, bool> m_rotate_by_user;
+		
+};
+
+#endif // ROTATESELECTIONCOMMAND_H

Added: trunk/sources/undocommand/rotatetextscommand.cpp
===================================================================
--- trunk/sources/undocommand/rotatetextscommand.cpp	                        (rev 0)
+++ trunk/sources/undocommand/rotatetextscommand.cpp	2017-12-05 20:51:54 UTC (rev 5141)
@@ -0,0 +1,152 @@
+/*
+	Copyright 2006-2017 The QElectroTech Team
+	This file is part of QElectroTech.
+
+	QElectroTech is free software: you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation, either version 2 of the License, or
+	(at your option) any later version.
+
+	QElectroTech is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with QElectroTech.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "rotatetextscommand.h"
+#include "diagramcontent.h"
+#include "diagram.h"
+#include "diagramtextitem.h"
+#include "elementtextitemgroup.h"
+#include "conductortextitem.h"
+#include "qetapp.h"
+#include "qtextorientationspinboxwidget.h"
+
+/**
+ * @brief RotateTextsCommand::RotateTextsCommand
+ * @param diagram : Apply the rotation to the selected texts and group of texts
+ * of diagram at construction time. 
+ * @param parent : undo parent
+ */
+RotateTextsCommand::RotateTextsCommand(Diagram *diagram, QUndoCommand *parent) :
+QUndoCommand(parent),
+m_diagram(diagram)
+{
+	DiagramContent dc(m_diagram);
+	QList <DiagramTextItem *> texts_list;
+	QList <ElementTextItemGroup *> groups_list;
+	
+	for(DiagramTextItem *dti : dc.selectedTexts())
+	{
+		texts_list << dti;
+		if(dti->type() == ConductorTextItem::Type)
+		{
+			ConductorTextItem *cti = static_cast<ConductorTextItem *>(dti);
+			m_cond_texts.insert(cti, cti->wasRotateByUser());
+		}
+	}
+	for(ElementTextItemGroup *etig : dc.selectedTextsGroup())
+		groups_list << etig;
+	
+	if(texts_list.count() || groups_list.count())
+	{
+		openDialog();
+		
+		QString text;
+		if(texts_list.count())
+			text.append(QObject::tr("Pivoter %1 textes").arg(texts_list.count()));
+		if(groups_list.count())
+		{
+			if(text.isEmpty())
+				text.append(QObject::tr("Pivoter"));
+			else
+				text.append(QObject::tr(" et"));
+			
+			text.append(QObject::tr(" %1 groupes de textes").arg(groups_list.count()));
+		}
+		if(!text.isNull())
+			setText(text);
+		
+		for(DiagramTextItem *dti : texts_list)
+			setupAnimation(dti, "rotation", dti->rotation(), m_rotation);
+		for(ElementTextItemGroup *grp : groups_list)
+			setupAnimation(grp, "rotation", grp->rotation(), m_rotation);
+	}
+#if QT_VERSION >= 0x050900
+	else
+		setObsolete(true);
+#endif
+	
+}
+
+void RotateTextsCommand::undo()
+{
+	if(m_diagram)
+		m_diagram.data()->showMe();
+	
+	m_anim_group->setDirection(QAnimationGroup::Backward);
+	m_anim_group->start();
+	
+	for(ConductorTextItem *cti : m_cond_texts.keys())
+		cti->forceMovedByUser(m_cond_texts.value(cti));
+}
+
+void RotateTextsCommand::redo()
+{
+	if(m_diagram)
+		m_diagram.data()->showMe();
+	
+	m_anim_group->setDirection(QAnimationGroup::Forward);
+	m_anim_group->start();
+	
+	for(ConductorTextItem *cti : m_cond_texts.keys())
+		cti->forceMovedByUser(true);
+}
+
+void RotateTextsCommand::openDialog()
+{
+		//Open the dialog
+	QDialog ori_text_dialog;
+	ori_text_dialog.setSizeGripEnabled(false);
+#ifdef Q_OS_MAC
+	ori_text_dialog.setWindowFlags(Qt::Sheet);
+#endif
+	ori_text_dialog.setWindowTitle(QObject::tr("Orienter les textes sélectionnés", "window title"));
+	
+	
+	QTextOrientationSpinBoxWidget *ori_widget = QETApp::createTextOrientationSpinBoxWidget();
+	ori_widget->setParent(&ori_text_dialog);
+	ori_widget->spinBox()->selectAll();
+	
+	QDialogButtonBox buttons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
+	QObject::connect(&buttons, SIGNAL(accepted()), &ori_text_dialog, SLOT(accept()));
+	QObject::connect(&buttons, SIGNAL(rejected()), &ori_text_dialog, SLOT(reject()));
+	
+	QVBoxLayout layout_v(&ori_text_dialog);
+	layout_v.setSizeConstraint(QLayout::SetFixedSize);
+	layout_v.addWidget(ori_widget);
+	layout_v.addStretch();
+	layout_v.addWidget(&buttons);
+	
+	if (ori_text_dialog.exec() == QDialog::Accepted)
+		m_rotation = ori_widget->orientation();
+#if QT_VERSION >= 0x050900
+	else
+		setObsolete(true);
+#endif
+}
+
+void RotateTextsCommand::setupAnimation(QObject *target, const QByteArray &propertyName, const QVariant start, const QVariant end)
+{
+	if(m_anim_group == nullptr)
+		m_anim_group = new QParallelAnimationGroup();
+	
+	QPropertyAnimation *animation = new QPropertyAnimation(target, propertyName);
+	animation->setDuration(300);
+	animation->setStartValue(start);
+	animation->setEndValue(end);
+	animation->setEasingCurve(QEasingCurve::OutQuad);
+	m_anim_group->addAnimation(animation);
+}

Added: trunk/sources/undocommand/rotatetextscommand.h
===================================================================
--- trunk/sources/undocommand/rotatetextscommand.h	                        (rev 0)
+++ trunk/sources/undocommand/rotatetextscommand.h	2017-12-05 20:51:54 UTC (rev 5141)
@@ -0,0 +1,52 @@
+/*
+	Copyright 2006-2017 The QElectroTech Team
+	This file is part of QElectroTech.
+
+	QElectroTech is free software: you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation, either version 2 of the License, or
+	(at your option) any later version.
+
+	QElectroTech is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with QElectroTech.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef ROTATETEXTSCOMMAND_H
+#define ROTATETEXTSCOMMAND_H
+
+#include <QUndoCommand>
+#include <QPointer>
+
+class ConductorTextItem;
+class Diagram;
+class QParallelAnimationGroup;
+
+/**
+ * @brief The RotateTextsCommand class
+ * Open a dialog for edit the rotation of the current selected texts and texts group in diagram.
+ * Just instantiate this undo command and push it in a QUndoStack.
+ */
+class RotateTextsCommand : public QUndoCommand
+{
+	public:
+		RotateTextsCommand(Diagram *diagram, QUndoCommand *parent=nullptr);
+		
+		void undo() override;
+		void redo() override;
+		
+	private:
+		void openDialog();
+		void setupAnimation(QObject *target, const QByteArray &propertyName, const QVariant start, const QVariant end);
+		
+	private:
+		QPointer<Diagram> m_diagram;
+		QHash<ConductorTextItem *, bool> m_cond_texts;
+		qreal m_rotation=0;
+		QParallelAnimationGroup *m_anim_group = nullptr;
+};
+
+#endif // ROTATETEXTSCOMMAND_H


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