diff --git a/sources/diagram.cpp b/sources/diagram.cpp index 357f1f49e..cf0e8a12c 100644 --- a/sources/diagram.cpp +++ b/sources/diagram.cpp @@ -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 @@ void Diagram::wheelEvent(QGraphicsSceneWheelEvent *event) * 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,44 +304,76 @@ void Diagram::keyPressEvent(QKeyEvent *e) } return; } - - bool transmit_event = true; - if (!isReadOnly()) { + + if (!isReadOnly()) + { QPointF movement; qreal top_position = 0; qreal left_position = 0; - QList 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(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; - } - } - if (transmit_event) { - QGraphicsScene::keyPressEvent(e); + } } + + event->ignore(); + QGraphicsScene::keyPressEvent(event); } } @@ -1659,25 +1693,6 @@ QSet Diagram::selectedConductors() const { return(conductors_set); } -/** - * @brief Diagram::selectedTexts - * @return A list of every selected texts (every kind of texts) - */ -QSet Diagram::selectedTexts() const -{ - QSet 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(qgi); - } - - return(selected_texts); -} - /// @return true si le presse-papier semble contenir un schema bool Diagram::clipboardMayContainDiagram() { QString clipboard_text = QApplication::clipboard() -> text().trimmed(); @@ -1760,62 +1775,6 @@ DiagramContent Diagram::content() const { return(dc); } -/** - * @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(item)) - dc.m_elements << elmt; - else if (IndependentTextItem *iti = qgraphicsitem_cast(item)) - dc.m_text_fields << iti; - else if (Conductor *c = qgraphicsitem_cast(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(item)) - dc.m_images << dii; - else if (QetShapeItem *dsi = qgraphicsitem_cast(item)) - dc.m_shapes << dsi; - else if (DynamicElementTextItem *deti = qgraphicsitem_cast(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 @@ bool Diagram::canRotateSelection() const 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(qgi)) + return true; } return false; diff --git a/sources/diagram.h b/sources/diagram.h index 3a8d69de7..44151a677 100644 --- a/sources/diagram.h +++ b/sources/diagram.h @@ -121,7 +121,7 @@ class Diagram : public QGraphicsScene 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 @@ class Diagram : public QGraphicsScene QList customElements() const; QList elements() const; QList conductors() const; - QSet selectedTexts() const; QSet selectedConductors() const; DiagramContent content() const; - DiagramContent selectedContent(); bool canRotateSelection() const; int beginMoveElements(QGraphicsItem * = nullptr); void continueMoveElements(const QPointF &); diff --git a/sources/diagramcommands.cpp b/sources/diagramcommands.cpp index 710748178..7fc15aca0 100644 --- a/sources/diagramcommands.cpp +++ b/sources/diagramcommands.cpp @@ -26,6 +26,7 @@ #include "diagram.h" #include "qetgraphicsitem/diagramtextitem.h" #include "qetgraphicsitem/diagramimageitem.h" +#include "elementtextitemgroup.h" #include QString itemText(const QetGraphicsItem *item) { @@ -266,32 +267,36 @@ void MoveElementsCommand::redo() { * 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(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); - } } /** @@ -440,137 +445,6 @@ void ChangeDiagramTextCommand::redo() { } } -/** - 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 &elements, const QList &texts, const QList &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(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(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 &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(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(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 diff --git a/sources/diagramcommands.h b/sources/diagramcommands.h index 64dfb9768..f4424d78d 100644 --- a/sources/diagramcommands.h +++ b/sources/diagramcommands.h @@ -215,69 +215,6 @@ class ChangeDiagramTextCommand : public QUndoCommand { Diagram *diagram; }; -/** - This command rotates several elements or text items by a particular angle. -*/ -class RotateElementsCommand : public QUndoCommand { - // constructors, destructor - public: - RotateElementsCommand(const QList &elements, const QList &, const QList &, 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 elements_to_rotate; - /// text items to be rotated - QList texts_to_rotate; - /// images item to be rotated - QList images_to_rotate; - /// angle of rotation to be applied to text items - qreal applied_rotation_angle_; - /// previous state of each conductor text item - QHash 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 &, 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 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 m_previous_rotate_by_user; - Diagram *m_diagram; -}; - /** This command changes a particular conductor. */ diff --git a/sources/diagramcontent.cpp b/sources/diagramcontent.cpp index 6eff994ce..607350a80 100644 --- a/sources/diagramcontent.cpp +++ b/sources/diagramcontent.cpp @@ -24,12 +24,73 @@ #include "elementtextitem.h" #include "qetshapeitem.h" #include "dynamicelementtextitem.h" +#include "elementtextitemgroup.h" +#include "diagram.h" +#include "terminal.h" +#include "conductortextitem.h" /** * @brief DiagramContent::DiagramContent */ DiagramContent::DiagramContent() {} +/** + * @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(item)) + m_elements << elmt; + else if (IndependentTextItem *iti = qgraphicsitem_cast(item)) + m_text_fields << iti; + else if (Conductor *c = qgraphicsitem_cast(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(item)) + m_images << dii; + else if (QetShapeItem *dsi = qgraphicsitem_cast(item)) + m_shapes << dsi; + else if (DynamicElementTextItem *deti = qgraphicsitem_cast(item)) + m_element_texts << deti; + else if (QGraphicsItemGroup *group = qgraphicsitem_cast(item)) + if(ElementTextItemGroup *etig = dynamic_cast(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 @@ -43,7 +104,9 @@ DiagramContent::DiagramContent(const DiagramContent &other) : 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,6 +114,47 @@ DiagramContent::DiagramContent(const DiagramContent &other) : */ 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 DiagramContent::selectedTexts() const +{ + QList 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(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 DiagramContent::selectedTextsGroup() const +{ + QList groups; + + for(QGraphicsItem *qgi : m_selected_items) + if(qgi->type() == QGraphicsItemGroup::Type) + if(ElementTextItemGroup *grp = dynamic_cast(qgi)) + groups << grp; + + return groups; +} + /** * @brief DiagramContent::conductors * @param filter @@ -84,6 +188,8 @@ void DiagramContent::clear() 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 @@ QList DiagramContent::items(int filter) const 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 @@ int DiagramContent::count(int filter) const 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 @@ int DiagramContent::count(int filter) const 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); } diff --git a/sources/diagramcontent.h b/sources/diagramcontent.h index 60f4d5e9d..df3dc9cf6 100644 --- a/sources/diagramcontent.h +++ b/sources/diagramcontent.h @@ -28,6 +28,9 @@ class DiagramImageItem; 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 @@ class DiagramContent { public: DiagramContent(); + DiagramContent(Diagram *diagram); DiagramContent(const DiagramContent &); ~DiagramContent(); @@ -56,8 +60,9 @@ class DiagramContent OtherConductors = 64, AnyConductor = 112, Shapes = 128, - All = 255, - SelectedOnly = 256 + TextGroup = 256, + All = 511, + SelectedOnly = 512 }; QSet m_elements; @@ -68,7 +73,11 @@ class DiagramContent QSet m_conductors_to_move; QSet m_other_conductors; QSet m_element_texts; + QSet m_texts_groups; + QList m_selected_items; + QList selectedTexts() const; + QList selectedTextsGroup() const; QList conductors(int = AnyConductor) const; QList items(int = All) const; QString sentence(int = All) const; diff --git a/sources/diagramview.cpp b/sources/diagramview.cpp index 672a053c5..f06b185a1 100644 --- a/sources/diagramview.cpp +++ b/sources/diagramview.cpp @@ -28,14 +28,12 @@ #include "qetgraphicsitem/independenttextitem.h" #include "qetgraphicsitem/diagramimageitem.h" #include "templatelocation.h" -#include "qetapp.h" #include "qetproject.h" #include "projectview.h" #include "integrationmovetemplateshandler.h" #include "qetdiagrameditor.h" #include "qeticons.h" #include "qetmessagebox.h" -#include "qtextorientationspinboxwidget.h" #include #include #include @@ -136,111 +134,12 @@ void DiagramView::deleteSelection() { 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(); } -/** - * @brief DiagramView::rotateSelection - * Rotate the selected items - */ -void DiagramView::rotateSelection() -{ - if (m_diagram->isReadOnly()) - return; - - QList elements_to_rotate; - QList texts_to_rotate; - QList images_to_rotate; - - for (QGraphicsItem *item : m_diagram->selectedItems()) - { - if (Element *e = qgraphicsitem_cast(item)) - elements_to_rotate << e; - else if (ConductorTextItem *cti = qgraphicsitem_cast(item)) - texts_to_rotate << cti; - else if (IndependentTextItem *iti = qgraphicsitem_cast(item)) - texts_to_rotate << iti; - else if (ElementTextItem *eti = qgraphicsitem_cast(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(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(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 texts_to_rotate; - for (QGraphicsItem *item : m_diagram->selectedItems()) - { - if (ConductorTextItem *cti = qgraphicsitem_cast(item)) - texts_to_rotate << cti; - else if (IndependentTextItem *iti = qgraphicsitem_cast(item)) - texts_to_rotate << iti; - else if (ElementTextItem *eti = qgraphicsitem_cast(item)) - texts_to_rotate << eti; - else if (DynamicElementTextItem *deti = qgraphicsitem_cast(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 @@ -257,14 +156,6 @@ void DiagramView::dragEnterEvent(QDragEnterEvent *e) { } } -/** - 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::zoomReset() { */ 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 @@ void DiagramView::keyPressEvent(QKeyEvent *e) return; ProjectView *current_project = this->diagramEditor()->acessCurrentProject(); + DiagramContent dc(m_diagram); switch(e -> key()) { case Qt::Key_PageUp: @@ -702,22 +594,22 @@ void DiagramView::keyPressEvent(QKeyEvent *e) } 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 @@ void DiagramView::keyReleaseEvent(QKeyEvent *e) { 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 selected_elmts = m_diagram->selectedContent().items(DiagramContent::All); +void DiagramView::scrollOnMovement(QKeyEvent *e) +{ + QList selected_elmts = DiagramContent(m_diagram).items(DiagramContent::All); QRectF viewed_scene = viewedSceneRect(); foreach (QGraphicsItem *qgi, selected_elmts){ if (qgraphicsitem_cast(qgi)) continue; @@ -822,13 +715,6 @@ void DiagramView::editDiagramProperties() { DiagramPropertiesDialog::diagramPropertiesDialog(m_diagram, diagramEditor()); } -/** - @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 @@ void DiagramView::applyReadOnly() { } /** - 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 @@ void DiagramView::editSelectionProperties() { } /** - 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 selected_conductors = selection.conductors(DiagramContent::AnyConductor | DiagramContent::SelectedOnly); if (selected_conductors.count() == 1) { editConductorColor(selected_conductors.at(0)); diff --git a/sources/diagramview.h b/sources/diagramview.h index 4dbd0e434..e821b18ec 100644 --- a/sources/diagramview.h +++ b/sources/diagramview.h @@ -49,10 +49,10 @@ class DiagramView : public QGraphicsView // 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 @@ class DiagramView : public QGraphicsView 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 @@ class DiagramView : public QGraphicsView 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 @@ class DiagramView : public QGraphicsView void selectAll(); void selectInvert(); void deleteSelection(); - void rotateSelection(); - void rotateTexts(); void setVisualisationMode(); void setSelectionMode(); void zoom(const qreal zoom_factor); diff --git a/sources/elementsmover.cpp b/sources/elementsmover.cpp index 9fbb85229..af0ddbee9 100644 --- a/sources/elementsmover.cpp +++ b/sources/elementsmover.cpp @@ -33,8 +33,8 @@ ElementsMover::ElementsMover() : movement_running_(false), current_movement_(), diagram_(nullptr), - movement_driver_(nullptr), - moved_content_() + m_movement_driver(nullptr), + m_moved_content() { } @@ -70,21 +70,21 @@ int ElementsMover::beginMovement(Diagram *diagram, QGraphicsItem *driver_item) { 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 @@ void ElementsMover::continueMovement(const QPointF &movement) { //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,18 +133,18 @@ void ElementsMover::endMovement() //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()); } //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(); diff --git a/sources/elementsmover.h b/sources/elementsmover.h index 091aa3b45..157a255f2 100644 --- a/sources/elementsmover.h +++ b/sources/elementsmover.h @@ -55,7 +55,7 @@ class ElementsMover { bool movement_running_; QPointF current_movement_; Diagram *diagram_; - QGraphicsItem *movement_driver_; - DiagramContent moved_content_; + QGraphicsItem *m_movement_driver; + DiagramContent m_moved_content; }; #endif diff --git a/sources/qetdiagrameditor.cpp b/sources/qetdiagrameditor.cpp index 9c350fbd2..03359d200 100644 --- a/sources/qetdiagrameditor.cpp +++ b/sources/qetdiagrameditor.cpp @@ -45,6 +45,8 @@ #include "dynamicelementtextitem.h" #include "conductortextitem.h" #include "elementtextitem.h" +#include "undocommand/rotateselectioncommand.h" +#include "rotatetextscommand.h" #include #include @@ -1038,12 +1040,15 @@ DiagramView *QETDiagramEditor::currentDiagram() const { * 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 selected_elements = dv -> diagram() -> selectedContent().m_elements.toList(); - if (selected_elements.count() != 1) return(nullptr); + QList selected_elements = DiagramContent(dv->diagram()).m_elements.toList(); + if (selected_elements.count() != 1) + return(nullptr); return(selected_elements.first()); } @@ -1262,9 +1267,17 @@ void QETDiagramEditor::selectionGroupTriggered(QAction *action) 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 @@ void QETDiagramEditor::slot_updateComplexActions() } Diagram *diagram_ = dv->diagram(); + DiagramContent dc(diagram_); bool ro = diagram_->isReadOnly(); @@ -1408,7 +1422,7 @@ void QETDiagramEditor::slot_updateComplexActions() 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 @@ void QETDiagramEditor::slot_updateComplexActions() 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 texts = DiagramContent(diagram_).selectedTexts(); + QList 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 + diff --git a/sources/qetgraphicsitem/elementtextitemgroup.cpp b/sources/qetgraphicsitem/elementtextitemgroup.cpp index 9b1912dba..21a95971c 100644 --- a/sources/qetgraphicsitem/elementtextitemgroup.cpp +++ b/sources/qetgraphicsitem/elementtextitemgroup.cpp @@ -20,6 +20,7 @@ #include "element.h" #include "diagram.h" #include "addelementtextcommand.h" +#include "QPropertyUndoCommand/qpropertyundocommand.h" #include #include @@ -37,7 +38,7 @@ ElementTextItemGroup::ElementTextItemGroup(const QString &name, Element *parent) QGraphicsItemGroup(parent), m_name(name) { - setFlags(QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsFocusable); + setFlags(QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsMovable); } ElementTextItemGroup::~ElementTextItemGroup() @@ -127,7 +128,6 @@ void ElementTextItemGroup::updateAlignment() item->setPos(ref.x(), ref.y()+y_offset); y_offset+=item->boundingRect().height(); } - return; } else if(m_alignment == Qt::AlignVCenter) { @@ -139,9 +139,7 @@ void ElementTextItemGroup::updateAlignment() 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 @@ void ElementTextItemGroup::updateAlignment() ref.y() + y_offset); y_offset+=item->boundingRect().height(); } - return; } + + setTransformOriginPoint(boundingRect().topLeft()); } } @@ -381,26 +380,30 @@ void ElementTextItemGroup::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) */ 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); - } - 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); + 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); + } } + event->ignore(); } diff --git a/sources/qetgraphicsitem/elementtextitemgroup.h b/sources/qetgraphicsitem/elementtextitemgroup.h index 8d8167840..60ea97c46 100644 --- a/sources/qetgraphicsitem/elementtextitemgroup.h +++ b/sources/qetgraphicsitem/elementtextitemgroup.h @@ -36,6 +36,7 @@ class ElementTextItemGroup : public QObject, public QGraphicsItemGroup 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); diff --git a/sources/undocommand/rotateselectioncommand.cpp b/sources/undocommand/rotateselectioncommand.cpp new file mode 100644 index 000000000..14e483bd7 --- /dev/null +++ b/sources/undocommand/rotateselectioncommand.cpp @@ -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 . +*/ +#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 + +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(item); + break; + case ConductorTextItem::Type: + m_text << static_cast(item); + break; + case IndependentTextItem::Type: + m_text << static_cast(item); + break; + case ElementTextItem::Type: + if(item->parentItem() && !item->parentItem()->isSelected()) + m_text << static_cast(item); + break; + case DynamicElementTextItem::Type: + if(item->parentItem() && !item->parentItem()->isSelected()) + m_text << static_cast(item); + break; + case QGraphicsItemGroup::Type: + if(ElementTextItemGroup *grp = dynamic_cast(item)) + if(grp->parentElement() && !grp->parentElement()->isSelected()) + m_group << grp; + break; + case DiagramImageItem::Type: + m_image << static_cast(item); + break; + default: + break; + } + } + } +} + +/** + * @brief RotateSelectionCommand::undo + */ +void RotateSelectionCommand::undo() +{ + m_diagram->showMe(); + + for(QPointer elmt : m_element) + if(elmt) + elmt.data()->rotateBy(-m_angle); + for(QPointer text : m_text) + { + if(text) + { + if(text.data()->type() == ConductorTextItem::Type) + { + ConductorTextItem *cti = static_cast(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 image : m_image) + if(image) + image.data()->rotateBy(-m_angle); + for(QPointer group : m_group) + if(group) + group.data()->setRotation(group.data()->rotation() - m_angle); +} + +/** + * @brief RotateSelectionCommand::redo + */ +void RotateSelectionCommand::redo() +{ + m_diagram->showMe(); + + for(QPointer elmt : m_element) + if(elmt) + elmt.data()->rotateBy(m_angle); + for(QPointer text : m_text) + { + if(text) + { + if(text.data()->type() == ConductorTextItem::Type) + { + ConductorTextItem *cti = static_cast(text.data()); + m_rotate_by_user.insert(text.data(), cti->wasRotateByUser()); + cti->forceRotateByUser(true); + } + text.data()->rotateBy(m_angle); + } + } + for(QPointer image : m_image) + if(image) + image.data()->rotateBy(m_angle); + for(QPointer 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; +} diff --git a/sources/undocommand/rotateselectioncommand.h b/sources/undocommand/rotateselectioncommand.h new file mode 100644 index 000000000..4d1b18d68 --- /dev/null +++ b/sources/undocommand/rotateselectioncommand.h @@ -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 . +*/ +#ifndef ROTATESELECTIONCOMMAND_H +#define ROTATESELECTIONCOMMAND_H + +#include +#include + +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> m_element; + QList> m_image; + QList> m_group; + QList> m_text; + QHash m_rotate_by_user; + +}; + +#endif // ROTATESELECTIONCOMMAND_H diff --git a/sources/undocommand/rotatetextscommand.cpp b/sources/undocommand/rotatetextscommand.cpp new file mode 100644 index 000000000..0b7774ad1 --- /dev/null +++ b/sources/undocommand/rotatetextscommand.cpp @@ -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 . +*/ +#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 texts_list; + QList groups_list; + + for(DiagramTextItem *dti : dc.selectedTexts()) + { + texts_list << dti; + if(dti->type() == ConductorTextItem::Type) + { + ConductorTextItem *cti = static_cast(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); +} diff --git a/sources/undocommand/rotatetextscommand.h b/sources/undocommand/rotatetextscommand.h new file mode 100644 index 000000000..31a4a6690 --- /dev/null +++ b/sources/undocommand/rotatetextscommand.h @@ -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 . +*/ +#ifndef ROTATETEXTSCOMMAND_H +#define ROTATETEXTSCOMMAND_H + +#include +#include + +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 m_diagram; + QHash m_cond_texts; + qreal m_rotation=0; + QParallelAnimationGroup *m_anim_group = nullptr; +}; + +#endif // ROTATETEXTSCOMMAND_H