diff --git a/dev_doc/enum_type_of_QGraphicsItem b/dev_doc/enum_type_of_QGraphicsItem index 67853f9e9..8777203f8 100644 --- a/dev_doc/enum_type_of_QGraphicsItem +++ b/dev_doc/enum_type_of_QGraphicsItem @@ -10,6 +10,7 @@ ConductorTextItem + 1006 DiagramImageItem + 1007 QetShapItem + 1008 crossRefItem + 1009 +DynamiqueElementTextItem + 1010 ElementPrimitiveDecorator + 2200 ###ELEMENT EDITOR### @@ -21,3 +22,6 @@ part terminal + 1106 part text + 1107 part text field + 1108 part rectangle + 1109 + +###QetGraphicsHandlerItem### +QetGraphicsHandlerItem = 1200 diff --git a/sources/diagram.cpp b/sources/diagram.cpp index e9fd4e5a9..7b0beea11 100644 --- a/sources/diagram.cpp +++ b/sources/diagram.cpp @@ -38,6 +38,7 @@ #include "elementcollectionhandler.h" #include "element.h" #include "diagramview.h" +#include "dynamicelementtextitem.h" const int Diagram::xGrid = 10; const int Diagram::yGrid = 10; @@ -75,7 +76,7 @@ Diagram::Diagram(QETProject *project) : //Init object for manage movement elements_mover_ = new ElementsMover(); - element_texts_mover_ = new ElementTextsMover(); + m_element_texts_mover = new ElementTextsMover(); connect(&border_and_titleblock, SIGNAL(needTitleBlockTemplate(const QString &)), this, SLOT(setTitleBlockTemplate(const QString &))); connect(&border_and_titleblock, SIGNAL(diagramTitleChanged(const QString &)), this, SLOT(titleChanged(const QString &))); @@ -91,31 +92,30 @@ Diagram::Diagram(QETProject *project) : * @brief Diagram::~Diagram * Destructor */ -Diagram::~Diagram() { - // clear undo stack to prevent errors, because contains pointers to this diagram and is elements. +Diagram::~Diagram() +{ + //First clear every selection to close an hypothetical editor + clearSelection(); + // clear undo stack to prevent errors, because contains pointers to this diagram and is elements. undoStack().clear(); - //delete of QGIManager, every elements he knows are removed + //delete of QGIManager, every elements he knows are removed delete qgi_manager_; - // remove of conductor setter + // remove of conductor setter delete conductor_setter_; - // delete of object for manage movement + // delete of object for manage movement delete elements_mover_; - delete element_texts_mover_; + delete m_element_texts_mover; - if (m_event_interface) delete m_event_interface; + if (m_event_interface) + delete m_event_interface; - // list removable items + // list removable items QList deletable_items; for(QGraphicsItem *qgi : items()) - { - if (qgi->parentItem()) - continue; - if (qgi->type() == Conductor::Type) - continue; - if (qgi->type() == QetGraphicsHandlerItem::Type) - continue; - + { + if (qgi -> parentItem()) continue; + if (qgraphicsitem_cast(qgi)) continue; deletable_items << qgi; } @@ -302,10 +302,10 @@ void Diagram::keyPressEvent(QKeyEvent *e) qreal top_position = 0; qreal left_position = 0; QList selected_elmts = this->selectedContent().items(); - if (!this->selectedContent().items(255).isEmpty()) { + if (!this->selectedContent().items(DiagramContent::All).isEmpty()) { switch(e -> key()) { case Qt::Key_Left: - foreach (Element *item, selectedContent().elements) { + foreach (Element *item, selectedContent().m_elements) { left_position = item->mapRectFromScene(item->boundingRect()).x(); if (left_position >= this->sceneRect().left() - item->boundingRect().width()) return; @@ -314,7 +314,7 @@ void Diagram::keyPressEvent(QKeyEvent *e) break; case Qt::Key_Right: movement = QPointF(+xGrid, 0.0); break; case Qt::Key_Up: - foreach (Element *item, selectedContent().elements) { + foreach (Element *item, selectedContent().m_elements) { top_position = item->mapRectFromScene(item->boundingRect()).y(); if (top_position >= this->sceneRect().top() - item->boundingRect().height()) return; @@ -378,8 +378,6 @@ void Diagram::keyReleaseEvent(QKeyEvent *e) * Diagram become the ownership of event_interface * If there is a previous interface, they will be delete before * and call init() to the new interface. - * The derivated class of DiagramEventInterface need to emit the signal "finish" when the job is done, - * diagram use this signal to delete the interface. If the signal isn't send, the interface will never be deleted. * @param event_interface */ void Diagram::setEventInterface(DiagramEventInterface *event_interface) @@ -968,20 +966,14 @@ bool Diagram::fromXml(QDomElement &document, QPointF position, bool consider_inf qgi -> setPos( qgi -> pos() += pos_); } - //Filling of optional lists + // remplissage des listes facultatives if (content_ptr) { - content_ptr -> elements = added_elements.toSet(); - content_ptr -> conductorsToMove = added_conductors.toSet(); - content_ptr -> textFields = added_texts.toSet(); - content_ptr -> images = added_images.toSet(); - content_ptr -> shapes = added_shapes.toSet(); + content_ptr -> m_elements = added_elements.toSet(); + content_ptr -> m_conductors_to_move = added_conductors.toSet(); + content_ptr -> m_text_fields = added_texts.toSet(); + content_ptr -> m_images = added_images.toSet(); + content_ptr -> m_shapes = added_shapes.toSet(); } - - //Ensure the texts of conductor are inside the border of the folio - //and so don't cause the annoying margin on the left border of the folio. - for(Conductor *cond : added_conductors) - cond->textItem()->setPos(cond->textItem()->pos()); - adjustSceneRect(); return(true); } @@ -1438,7 +1430,7 @@ void Diagram::endMoveElements() { @see ElementTextsMover */ int Diagram::beginMoveElementTexts(QGraphicsItem *driver_item) { - return(element_texts_mover_ -> beginMovement(this, driver_item)); + return(m_element_texts_mover -> beginMovement(this, driver_item)); } /** @@ -1447,7 +1439,7 @@ int Diagram::beginMoveElementTexts(QGraphicsItem *driver_item) { @see ElementTextsMover */ void Diagram::continueMoveElementTexts(const QPointF &movement) { - element_texts_mover_ -> continueMovement(movement); + m_element_texts_mover -> continueMovement(movement); } /** @@ -1455,7 +1447,7 @@ void Diagram::continueMoveElementTexts(const QPointF &movement) { @see ElementTextsMover */ void Diagram::endMoveElementTexts() { - element_texts_mover_ -> endMovement(); + m_element_texts_mover -> endMovement(); } /** @@ -1656,53 +1648,24 @@ QSet Diagram::selectedConductors() const { } /** - @return la liste de tous les textes selectionnes : les textes independants, - mais aussi ceux rattaches a des conducteurs ou des elements -*/ -QSet Diagram::selectedTexts() const { + * @brief Diagram::selectedTexts + * @return A list of every selected texts (every kind of texts) + */ +QSet Diagram::selectedTexts() const +{ QSet selected_texts; - foreach(QGraphicsItem *item, selectedItems()) { - if (ConductorTextItem *cti = qgraphicsitem_cast(item)) { - selected_texts << cti; - } else if (ElementTextItem *eti = qgraphicsitem_cast(item)) { - selected_texts << eti; - } else if (IndependentTextItem *iti = qgraphicsitem_cast(item)) { - selected_texts << iti; - } + 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); } -/** - * @brief Diagram::selectedConductorTexts - * @return the list of conductor texts selected - */ -QSet Diagram::selectedConductorTexts() const { - QSet selected_texts; - foreach(QGraphicsItem *item, selectedItems()) { - if (ConductorTextItem *cti = qgraphicsitem_cast(item)) { - selected_texts << cti; - } - } - return(selected_texts); -} - -/** - * @brief Diagram::selectedElementTexts - * @return the list of element texts selected - */ -QSet Diagram::selectedElementTexts() const { - QSet selected_texts; - foreach(QGraphicsItem *item, selectedItems()) { - if (ElementTextItem *cti = qgraphicsitem_cast< ElementTextItem*>(item)) { - selected_texts << cti; - } - } - return(selected_texts); -} - - - /// @return true si le presse-papier semble contenir un schema bool Diagram::clipboardMayContainDiagram() { QString clipboard_text = QApplication::clipboard() -> text().trimmed(); @@ -1775,47 +1738,53 @@ DiagramContent Diagram::content() const { DiagramContent dc; foreach(QGraphicsItem *qgi, items()) { if (Element *e = qgraphicsitem_cast(qgi)) { - dc.elements << e; + dc.m_elements << e; } else if (IndependentTextItem *iti = qgraphicsitem_cast(qgi)) { - dc.textFields << iti; + dc.m_text_fields << iti; } else if (Conductor *c = qgraphicsitem_cast(qgi)) { - dc.conductorsToMove << c; + dc.m_conductors_to_move << c; } } return(dc); } /** - @return le contenu selectionne du schema. -*/ -DiagramContent Diagram::selectedContent() { + * @brief Diagram::selectedContent + * @return the selected items, stored in a DiagramContent + */ +DiagramContent Diagram::selectedContent() +{ DiagramContent dc; - - // recupere les elements deplaces - foreach (QGraphicsItem *item, selectedItems()) { - if (Element *elmt = qgraphicsitem_cast(item)) { - dc.elements << elmt; - } else if (IndependentTextItem *iti = qgraphicsitem_cast(item)) { - dc.textFields << iti; - } else if (Conductor *c = qgraphicsitem_cast(item)) { + + //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.otherConductors << c; + dc.m_other_conductors << c; } - } else if (DiagramImageItem *dii = qgraphicsitem_cast(item)) { - dc.images << dii; - } else if (QetShapeItem *dsi = qgraphicsitem_cast(item)) { - dc.shapes << dsi; } + 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; } - // pour chaque element deplace, determine les conducteurs qui seront modifies - foreach(Element *elmt, dc.elements) { - foreach(Terminal *terminal, elmt -> terminals()) { - foreach(Conductor *conductor, terminal -> conductors()) { + //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; @@ -1823,10 +1792,10 @@ DiagramContent Diagram::selectedContent() { other_terminal = conductor -> terminal1; } // si les deux elements du conducteur sont deplaces - if (dc.elements.contains(other_terminal -> parentElement())) { - dc.conductorsToMove << conductor; + if (dc.m_elements.contains(other_terminal -> parentElement())) { + dc.m_conductors_to_move << conductor; } else { - dc.conductorsToUpdate << conductor; + dc.m_conductors_to_update << conductor; } } } @@ -1836,17 +1805,20 @@ DiagramContent Diagram::selectedContent() { } /** - @return true s'il est possible de tourner les elements selectionnes. - Concretement, cette methode retourne true s'il y a des elements selectionnes - et qu'au moins l'un d'entre eux peut etre pivote. -*/ -bool Diagram::canRotateSelection() const { - foreach(QGraphicsItem * qgi, selectedItems()) { - if (qgraphicsitem_cast(qgi) || - qgraphicsitem_cast(qgi) || - qgraphicsitem_cast(qgi) || - qgraphicsitem_cast(qgi) || - qgraphicsitem_cast(qgi)) return (true); + * @brief Diagram::canRotateSelection + * @return True if a least one of selected items can be rotated + */ +bool Diagram::canRotateSelection() const +{ + for (QGraphicsItem *qgi : selectedItems()) + { + if (qgi->type() == IndependentTextItem::Type || + qgi->type() == ConductorTextItem::Type || + qgi->type() == DiagramImageItem::Type || + qgi->type() == ElementTextItem::Type || + qgi->type() == Element::Type || + qgi->type() == DynamicElementTextItem::Type) return true; } - return(false); + + return false; } diff --git a/sources/diagram.h b/sources/diagram.h index 4c54ccaef..c71c91e5c 100644 --- a/sources/diagram.h +++ b/sources/diagram.h @@ -36,11 +36,8 @@ class DiagramTextItem; class Element; class ElementsLocation; class ElementsMover; -class ElementTextItem; -class IndependentTextItem; class QETProject; class Terminal; -class ConductorTextItem; class DiagramImageItem; class ElementTextsMover; class DiagramEventInterface; @@ -96,7 +93,7 @@ class Diagram : public QGraphicsScene private: QGraphicsLineItem *conductor_setter_; ElementsMover *elements_mover_; - ElementTextsMover *element_texts_mover_; + ElementTextsMover *m_element_texts_mover; QGIManager *qgi_manager_; QETProject *m_project; @@ -191,8 +188,6 @@ class Diagram : public QGraphicsScene QList elements() const; QList conductors() const; QSet selectedTexts() const; - QSet selectedConductorTexts() const; - QSet selectedElementTexts() const; QSet selectedConductors() const; DiagramContent content() const; DiagramContent selectedContent(); diff --git a/sources/diagramcommands.cpp b/sources/diagramcommands.cpp index ed41430c3..710748178 100644 --- a/sources/diagramcommands.cpp +++ b/sources/diagramcommands.cpp @@ -42,88 +42,6 @@ QString itemText(const Conductor *item) { return QObject::tr("un conducteur"); } -/** - Constructeur - @param dia Schema dont on supprime des elements et conducteurs - @param content Contenu supprime - @param parent QUndoCommand parent -*/ -DeleteElementsCommand::DeleteElementsCommand( - Diagram *dia, - const DiagramContent &content, - QUndoCommand *parent -) : - QUndoCommand(parent), - removed_content(content), - diagram(dia) -{ - setText( - QString( - QObject::tr( - "supprimer %1", - "undo caption - %1 is a sentence listing the removed content" - ) - ).arg(removed_content.sentence(DiagramContent::All)) - ); - diagram -> qgiManager().manage(removed_content.items(DiagramContent::All)); -} - -/// Destructeur -DeleteElementsCommand::~DeleteElementsCommand() { - diagram -> qgiManager().release(removed_content.items(DiagramContent::All)); -} - -/** - * @brief DeleteElementsCommand::undo - * Undo this command - */ -void DeleteElementsCommand::undo() -{ - diagram -> showMe(); - - foreach(QGraphicsItem *item, removed_content.items()) - diagram->addItem(item); - - //We relink element after every element was added to diagram - foreach(Element *e, removed_content.elements) - foreach (Element *elmt, m_link_hash[e]) - e -> linkToElement(elmt); -} - -/** - * @brief DeleteElementsCommand::redo - * Redo the delete command - */ -void DeleteElementsCommand::redo() -{ - diagram -> showMe(); - - foreach(Conductor *c, removed_content.conductors(DiagramContent::AnyConductor)) - { - //If option one text per folio is enable, and the text item of - //current conductor is visible (that mean the conductor have the single displayed text) - //We call adjustTextItemPosition to other conductor at the same potential to keep - //a visible text on this potential. - if (diagram -> defaultConductorProperties.m_one_text_per_folio && c -> textItem() -> isVisible()) - { - QList conductor_list; - conductor_list << c -> relatedPotentialConductors(false).toList(); - if (conductor_list.count()) - conductor_list.first() -> calculateTextItemPosition(); - } - } - - foreach(Element *e, removed_content.elements) - { - //Get linked element, for relink it at undo - if (!e->linkedElements().isEmpty()) - m_link_hash.insert(e, e->linkedElements()); - } - - foreach(QGraphicsItem *item, removed_content.items()) - diagram->removeItem(item); -} - /** * @brief PasteDiagramCommand::PasteDiagramCommand * Constructor @@ -176,7 +94,7 @@ void PasteDiagramCommand::redo() first_redo = false; //this is the first paste, we do some actions for the new element - const QList elmts_list = content.elements.toList(); + const QList elmts_list = content.m_elements.toList(); for (Element *e : elmts_list) { //make new uuid, because old uuid are the uuid of the copied element @@ -211,7 +129,7 @@ void PasteDiagramCommand::redo() eti -> setPlainText("_"); //Reset the text of conductors - const QList conductors_list = content.conductorsToMove.toList(); + const QList conductors_list = content.m_conductors_to_move.toList(); for (Conductor *c : conductors_list) { ConductorProperties cp = c -> properties(); @@ -253,7 +171,7 @@ CutDiagramCommand::CutDiagramCommand( const DiagramContent &content, QUndoCommand *parent ) : - DeleteElementsCommand(dia, content, parent) + DeleteQGraphicsItemCommand(dia, content, parent) { setText( QString( @@ -366,12 +284,12 @@ void MoveElementsCommand::move(const QPointF &actual_movement) { } // Move some conductors - foreach(Conductor *conductor, content_to_move.conductorsToMove) { + foreach(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.conductorsToUpdate) { + foreach(Conductor *conductor, content_to_move.m_conductors_to_update) { setupAnimation(conductor, "animPath", 1, 1); } } @@ -588,21 +506,6 @@ void RotateElementsCommand::redo() { foreach(DiagramImageItem *dii, images_to_rotate) dii -> rotateBy(applied_rotation_angle_); } -/** - Constructeur - @param previous_state Hash associant les textes impactes par l'action et leur angle de rotation avant l'action - @param applied_rotation Nouvel angle de rotation, a appliquer au textes concernes - @param parent QUndoCommand parent -*/ -RotateTextsCommand::RotateTextsCommand(const QHash &previous_state, double applied_rotation, QUndoCommand *parent) : - QUndoCommand(parent), - texts_to_rotate(previous_state), - applied_rotation_angle_(applied_rotation), - diagram(previous_state.key(0)->diagram()) -{ - defineCommandName(); -} - /** Constructeur @param texts Liste des textes impactes par l'action. L'objet retiendra leur angle de rotation au moment de sa construction. @@ -611,11 +514,11 @@ RotateTextsCommand::RotateTextsCommand(const QHash &p */ RotateTextsCommand::RotateTextsCommand(const QList &texts, double applied_rotation, QUndoCommand *parent) : QUndoCommand(parent), - applied_rotation_angle_(applied_rotation), - diagram(texts.first()->diagram()) + m_applied_rotation_angle(applied_rotation), + m_diagram(texts.first()->diagram()) { foreach(DiagramTextItem *text, texts) { - texts_to_rotate.insert(text, text -> rotationAngle()); + m_texts_to_rotate.insert(text, text -> rotationAngle()); } defineCommandName(); } @@ -630,11 +533,11 @@ RotateTextsCommand::~RotateTextsCommand() { Annule la rotation des textes */ void RotateTextsCommand::undo() { - diagram -> showMe(); - foreach(DiagramTextItem *text, texts_to_rotate.keys()) { + m_diagram -> showMe(); + foreach(DiagramTextItem *text, m_texts_to_rotate.keys()) { if (ConductorTextItem *cti = qgraphicsitem_cast(text)) - cti -> forceRotateByUser(previous_rotate_by_user_[cti]); - text -> setRotationAngle(texts_to_rotate[text]); + cti -> forceRotateByUser(m_previous_rotate_by_user[cti]); + text -> setRotationAngle(m_texts_to_rotate[text]); } } @@ -642,14 +545,14 @@ void RotateTextsCommand::undo() { Applique l'angle de rotation aux textes */ void RotateTextsCommand::redo() { - diagram -> showMe(); - foreach(DiagramTextItem *text, texts_to_rotate.keys()) { + 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 - previous_rotate_by_user_.insert(cti, cti -> wasRotateByUser()); + m_previous_rotate_by_user.insert(cti, cti -> wasRotateByUser()); cti -> forceRotateByUser(true); } - text -> setRotationAngle(applied_rotation_angle_); + text -> setRotationAngle(m_applied_rotation_angle); } } @@ -663,8 +566,8 @@ void RotateTextsCommand::defineCommandName() { "orienter %1 à %2°", "undo caption - %1 looks like '42 texts', %2 is a rotation angle" ) - ).arg(QET::ElementsAndConductorsSentence(0, 0, texts_to_rotate.count())) - .arg(applied_rotation_angle_) + ).arg(QET::ElementsAndConductorsSentence(0, 0, m_texts_to_rotate.count())) + .arg(m_applied_rotation_angle) ); } diff --git a/sources/diagramcommands.h b/sources/diagramcommands.h index 31dc75d42..4ca8d84be 100644 --- a/sources/diagramcommands.h +++ b/sources/diagramcommands.h @@ -26,6 +26,7 @@ #include "qetgraphicsitem/qetshapeitem.h" #include "conductorprofile.h" #include "diagram.h" +#include "undocommand/deleteqgraphicsitemcommand.h" class DiagramTextItem; class Element; @@ -80,32 +81,6 @@ QString itemText(const QetGraphicsItem *item); QString itemText(const IndependentTextItem *item); QString itemText(const Conductor *item); -/** - This command removes content from a particular diagram. -*/ -class DeleteElementsCommand : public QUndoCommand { - // constructors, destructor - public: - DeleteElementsCommand(Diagram *, const DiagramContent &, QUndoCommand * = 0); - virtual ~DeleteElementsCommand(); - private: - DeleteElementsCommand(const DeleteElementsCommand &); - - // methods - public: - virtual void undo(); - virtual void redo(); - - // attributes - private: - /// removed content - DiagramContent removed_content; - /// diagram which the content is removed from - Diagram *diagram; - /// keep linked element for each removed element linked to other element. - QHash > m_link_hash; -}; - /** This command pastes some content onto a particular diagram. */ @@ -137,7 +112,7 @@ class PasteDiagramCommand : public QUndoCommand { /** This command cuts content from a particular diagram. */ -class CutDiagramCommand : public DeleteElementsCommand { +class CutDiagramCommand : public DeleteQGraphicsItemCommand { // constructors, destructor public: CutDiagramCommand(Diagram *, const DiagramContent &, QUndoCommand * = 0); @@ -275,32 +250,32 @@ class RotateElementsCommand : public QUndoCommand { This command directs several text items to a same particular angle of rotation. */ -class RotateTextsCommand : public QUndoCommand { +class RotateTextsCommand : public QUndoCommand +{ // constructors, destructor public: - RotateTextsCommand(const QHash &, double, QUndoCommand * = 0); - RotateTextsCommand(const QList &, double, QUndoCommand * = 0); - virtual ~RotateTextsCommand(); + RotateTextsCommand(const QList &, double, QUndoCommand * = nullptr); + virtual ~RotateTextsCommand() override; private: - RotateTextsCommand(const RotateTextsCommand &); + RotateTextsCommand(const RotateTextsCommand &); // methods public: - virtual void undo(); - virtual void redo(); + virtual void undo() override; + virtual void redo() override; private: - void defineCommandName(); + void defineCommandName(); // attributes private: - /// hold rotated text items along with their former angle of rotation - QHash texts_to_rotate; - /// angle of rotation of all text items after the command - double applied_rotation_angle_; - /// previous state of each conductor text item - QHash previous_rotate_by_user_; - Diagram *diagram; + /// 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; }; /** diff --git a/sources/diagramcontent.cpp b/sources/diagramcontent.cpp index 50ab5057b..a887cc04f 100644 --- a/sources/diagramcontent.cpp +++ b/sources/diagramcontent.cpp @@ -23,61 +23,67 @@ #include "diagramimageitem.h" #include "elementtextitem.h" #include "qetshapeitem.h" +#include "dynamicelementtextitem.h" /** - Constructeur par defaut. Ne contient rien. -*/ -DiagramContent::DiagramContent() { -} + * @brief DiagramContent::DiagramContent + */ +DiagramContent::DiagramContent() {} /** - Constructeur de copie. -*/ + * @brief DiagramContent::DiagramContent + * Copy constructor + * @param other + */ DiagramContent::DiagramContent(const DiagramContent &other) : - elements(other.elements), - textFields(other.textFields), - images(other.images), - shapes(other.shapes), - conductorsToUpdate(other.conductorsToUpdate), - conductorsToMove(other.conductorsToMove), - otherConductors(other.otherConductors) + m_elements(other.m_elements), + m_text_fields(other.m_text_fields), + m_images(other.m_images), + m_shapes(other.m_shapes), + 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) +{} + +/** + * @brief DiagramContent::~DiagramContent + */ +DiagramContent::~DiagramContent() {} + +/** + * @brief DiagramContent::conductors + * @param filter + * @return Every conductors according to the filter + */ +QList DiagramContent::conductors(int filter) const { -} - -/** - Constructeur -*/ -DiagramContent::~DiagramContent() { -} - -/** - @param filter Types de conducteurs desires - @return tous les conducteurs -*/ -QList DiagramContent::conductors(int filter) const { QSet result; - if (filter & ConductorsToMove) result += conductorsToMove; - if (filter & ConductorsToUpdate) result += conductorsToUpdate; - if (filter & OtherConductors) result += otherConductors; + if (filter & ConductorsToMove) result += m_conductors_to_move; + if (filter & ConductorsToUpdate) result += m_conductors_to_update; + if (filter & OtherConductors) result += m_other_conductors; if (filter & SelectedOnly) { - foreach(Conductor *conductor, result) { - if (!conductor -> isSelected()) result.remove(conductor); + for(Conductor *conductor : result) { + if (!conductor->isSelected()) result.remove(conductor); } } return(result.toList()); } /** - Vide le conteneur -*/ -void DiagramContent::clear() { - elements.clear(); - textFields.clear(); - images.clear(); - shapes.clear(); - conductorsToUpdate.clear(); - conductorsToMove.clear(); - otherConductors.clear(); + * @brief DiagramContent::clear + * Remove all items from the diagram content + */ +void DiagramContent::clear() +{ + m_elements.clear(); + m_text_fields.clear(); + m_images.clear(); + m_shapes.clear(); + m_conductors_to_update.clear(); + m_conductors_to_move.clear(); + m_other_conductors.clear(); + m_element_texts.clear(); } /** @@ -89,42 +95,47 @@ int DiagramContent::removeNonMovableItems() { int count_ = 0; - foreach(Element *elmt, elements) { + for(Element *elmt : m_elements) { if (!elmt->isMovable()) { - elements.remove(elmt); + m_elements.remove(elmt); ++count_; } } - foreach(DiagramImageItem *img, images) { + for(DiagramImageItem *img : m_images) { if (!img->isMovable()) { - images.remove(img); + m_images.remove(img); ++count_; } } - foreach (QetShapeItem *shape, shapes) { + for(QetShapeItem *shape : m_shapes) { if (!shape->isMovable()) { - shapes.remove(shape); + m_shapes.remove(shape); ++count_; } } return count_; } -/** - @param filter Types desires - @return la liste des items formant le contenu du schema -*/ -QList DiagramContent::items(int filter) const { - QList items_list; - foreach(QGraphicsItem *qgi, conductors(filter)) items_list << qgi; - if (filter & Elements) foreach(QGraphicsItem *qgi, elements) items_list << qgi; - if (filter & TextFields) foreach(QGraphicsItem *qgi, textFields) items_list << qgi; - if (filter & Images) foreach(QGraphicsItem *qgi, images) items_list << qgi; - if (filter & Shapes) foreach(QGraphicsItem *qgi, shapes) items_list << qgi; +/** + * @brief DiagramContent::items + * @param filter + * @return The items of this diagram content according to @filter + */ +QList DiagramContent::items(int filter) const +{ + QList items_list; + + for(QGraphicsItem *qgi : conductors(filter)) items_list << qgi; + + if (filter & Elements) for(QGraphicsItem *qgi : m_elements) items_list << qgi; + if (filter & TextFields) for(QGraphicsItem *qgi : m_text_fields) items_list << qgi; + 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 & SelectedOnly) { - foreach(QGraphicsItem *qgi, items_list) { + for(QGraphicsItem *qgi : items_list) { if (!qgi -> isSelected()) items_list.removeOne(qgi); } } @@ -132,44 +143,50 @@ QList DiagramContent::items(int filter) const { } /** - @param filter Types desires - @return le nombre d'items formant le contenu du schema -*/ -int DiagramContent::count(int filter) const { + * @brief DiagramContent::count + * @param filter + * @return The number of items, according to @filter + */ +int DiagramContent::count(int filter) const +{ int count = 0; if (filter & SelectedOnly) { - if (filter & Elements) foreach(Element *element, elements) { if (element -> isSelected()) ++ count; } - if (filter & TextFields) foreach(DiagramTextItem *dti, textFields) { if (dti -> isSelected()) ++ count; } - if (filter & Images) foreach(DiagramImageItem *dii, images) { if (dii -> isSelected()) ++ count; } - if (filter & Shapes) foreach(QetShapeItem *dsi, shapes) { if (dsi -> isSelected()) ++ count; } - if (filter & ConductorsToMove) foreach(Conductor *conductor, conductorsToMove) { if (conductor -> isSelected()) ++ count; } - if (filter & ConductorsToUpdate) foreach(Conductor *conductor, conductorsToUpdate) { if (conductor -> isSelected()) ++ count; } - if (filter & OtherConductors) foreach(Conductor *conductor, otherConductors) { if (conductor -> isSelected()) ++ count; } + if (filter & Elements) for(Element *element : m_elements) { if (element -> isSelected()) ++ count; } + if (filter & TextFields) for(DiagramTextItem *dti : m_text_fields) { if (dti -> isSelected()) ++ count; } + if (filter & Images) for(DiagramImageItem *dii : m_images) { if (dii -> isSelected()) ++ count; } + if (filter & Shapes) for(QetShapeItem *dsi : m_shapes) { if (dsi -> isSelected()) ++ count; } + 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; } } else { - if (filter & Elements) count += elements.count(); - if (filter & TextFields) count += textFields.count(); - if (filter & Images) count += images.count(); - if (filter & Shapes) count += shapes.count(); - if (filter & ConductorsToMove) count += conductorsToMove.count(); - if (filter & ConductorsToUpdate) count += conductorsToUpdate.count(); - if (filter & OtherConductors) count += otherConductors.count(); + if (filter & Elements) count += m_elements.count(); + if (filter & TextFields) count += m_text_fields.count(); + if (filter & Images) count += m_images.count(); + if (filter & Shapes) count += m_shapes.count(); + if (filter & ConductorsToMove) count += m_conductors_to_move.count(); + 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(); } return(count); } /** - Permet de composer rapidement la proposition "x elements, y conducteurs et - z champs de texte". - @param filter Types desires - @return la proposition decrivant le contenu. -*/ -QString DiagramContent::sentence(int filter) const { - int elements_count = (filter & Elements) ? elements.count() : 0; + * @brief DiagramContent::sentence + * @param filter + * @return A string that describe the items of the diagram content according to @filter. + * Exemple : X elements, Y conductors etc.... + */ +QString DiagramContent::sentence(int filter) const +{ + int elements_count = (filter & Elements) ? m_elements.count() : 0; int conductors_count = conductors(filter).count(); - int textfields_count = (filter & TextFields) ? (textFields.count()) : 0; - int images_count = (filter & Images) ? images.count() : 0; - int shapes_count = (filter & Shapes) ? shapes.count() : 0; + int textfields_count = (filter & TextFields) ? (m_text_fields.count()) : 0; + int images_count = (filter & Images) ? m_images.count() : 0; + int shapes_count = (filter & Shapes) ? m_shapes.count() : 0; + int elmt_text_count = (filter & ElementTextFields) ? m_element_texts.count() : 0; return( QET::ElementsAndConductorsSentence( @@ -177,16 +194,18 @@ QString DiagramContent::sentence(int filter) const { conductors_count, textfields_count, images_count, - shapes_count + shapes_count, + elmt_text_count ) ); } /** - Permet de debugger un contenu de schema - @param d Object QDebug a utiliser pour l'affichage des informations de debug - @param content Contenu de schema a debugger -*/ + * @brief operator << Use to debug a diagram content + * @param d : QDebug to use for display the debug info + * @param content : content to debug + * @return + */ QDebug &operator<<(QDebug d, DiagramContent &content) { Q_UNUSED(content); d << "DiagramContent {" << "\n"; diff --git a/sources/diagramcontent.h b/sources/diagramcontent.h index ba2e35f6a..60f4d5e9d 100644 --- a/sources/diagramcontent.h +++ b/sources/diagramcontent.h @@ -27,6 +27,7 @@ class IndependentTextItem; class DiagramImageItem; class ElementTextItem; class QetShapeItem; +class DynamicElementTextItem; /** This class provides a container that makes the transmission of diagram content @@ -37,48 +38,43 @@ class QetShapeItem; Please note this container does not systematically contains a whole diagram: it may describe only a part of it, e.g. selected items. */ -class DiagramContent { +class DiagramContent +{ public: - DiagramContent(); - DiagramContent(const DiagramContent &); - ~DiagramContent(); - - /// Used to filter the different items carried by this container. - enum Filter { - Elements = 1, - TextFields = 2, - ElementTextFields = 4, - Images = 8, - ConductorsToMove = 16, - ConductorsToUpdate = 32, - OtherConductors = 64, - AnyConductor = 112, - Shapes = 128, - All = 255, - SelectedOnly = 256 - }; - - /// Hold electrical elements - QSet elements; - /// Hold independent text items - QSet textFields; - /// Hold image - QSet images; - /// Hold shape - QSet shapes; - /// Hold conductors that would get updated considering electrical elements are moved - QSet conductorsToUpdate; - /// Hold conductors that would be moved as is considering electrical elements are moved - QSet conductorsToMove; - /// Hold conductors that would be left untouched considering electrical elements are moved - QSet otherConductors; - - QList conductors(int = AnyConductor) const; - QList items(int = All) const; - QString sentence(int = All) const; - int count(int = All) const; - void clear(); - int removeNonMovableItems(); + DiagramContent(); + DiagramContent(const DiagramContent &); + ~DiagramContent(); + + /// Used to filter the different items carried by this container. + enum Filter { + Elements = 1, + TextFields = 2, + ElementTextFields = 4, + Images = 8, + ConductorsToMove = 16, + ConductorsToUpdate = 32, + OtherConductors = 64, + AnyConductor = 112, + Shapes = 128, + All = 255, + SelectedOnly = 256 + }; + + QSet m_elements; + QSet m_text_fields; + QSet m_images; + QSet m_shapes; + QSet m_conductors_to_update; + QSet m_conductors_to_move; + QSet m_other_conductors; + QSet m_element_texts; + + QList conductors(int = AnyConductor) const; + QList items(int = All) const; + QString sentence(int = All) const; + int count(int = All) const; + void clear(); + int removeNonMovableItems(); }; QDebug &operator<<(QDebug, DiagramContent &); #endif diff --git a/sources/diagramview.cpp b/sources/diagramview.cpp index 1ca107017..f6711e1d1 100644 --- a/sources/diagramview.cpp +++ b/sources/diagramview.cpp @@ -45,6 +45,8 @@ #include "diagrameventaddelement.h" #include "QPropertyUndoCommand/qpropertyundocommand.h" #include "qetshapeitem.h" +#include "undocommand/deleteqgraphicsitemcommand.h" +#include "dynamicelementtextitem.h" /** Constructeur @@ -52,10 +54,8 @@ @param parent Le QWidget parent de cette vue de schema */ DiagramView::DiagramView(Diagram *diagram, QWidget *parent) : - QGraphicsView (parent), - m_scene (diagram), - m_event_interface (nullptr), - m_first_activation (true) + QGraphicsView (parent), + m_diagram (diagram) { grabGesture(Qt::PinchGesture); setAttribute(Qt::WA_DeleteOnClose, true); @@ -74,8 +74,8 @@ DiagramView::DiagramView(Diagram *diagram, QWidget *parent) : setRenderHint(QPainter::TextAntialiasing, true); setRenderHint(QPainter::SmoothPixmapTransform, true); - setScene(m_scene); - m_scene -> undoStack().setClean(); + setScene(m_diagram); + m_diagram -> undoStack().setClean(); setWindowIcon(QET::Icons::QETLogo); setTransformationAnchor(QGraphicsView::AnchorUnderMouse); setResizeAnchor(QGraphicsView::AnchorUnderMouse); @@ -83,17 +83,17 @@ DiagramView::DiagramView(Diagram *diagram, QWidget *parent) : setSelectionMode(); adjustSceneRect(); updateWindowTitle(); - m_scene->loadElmtFolioSeq(); - m_scene->loadCndFolioSeq(); + m_diagram->loadElmtFolioSeq(); + m_diagram->loadCndFolioSeq(); - context_menu = new QMenu(this); - paste_here = new QAction(QET::Icons::EditPaste, tr("Coller ici", "context menu action"), this); - connect(paste_here, SIGNAL(triggered()), this, SLOT(pasteHere())); + m_context_menu = new QMenu(this); + m_paste_here = new QAction(QET::Icons::EditPaste, tr("Coller ici", "context menu action"), this); + connect(m_paste_here, SIGNAL(triggered()), this, SLOT(pasteHere())); - connect(m_scene, SIGNAL(showDiagram(Diagram*)), this, SIGNAL(showDiagram(Diagram*))); - connect(m_scene, SIGNAL(selectionChanged()), this, SIGNAL(selectionChanged())); - connect(m_scene, SIGNAL(sceneRectChanged(QRectF)), this, SLOT(adjustSceneRect())); - connect(&(m_scene -> border_and_titleblock), SIGNAL(diagramTitleChanged(const QString &)), this, SLOT(updateWindowTitle())); + connect(m_diagram, SIGNAL(showDiagram(Diagram*)), this, SIGNAL(showDiagram(Diagram*))); + connect(m_diagram, SIGNAL(selectionChanged()), this, SIGNAL(selectionChanged())); + connect(m_diagram, SIGNAL(sceneRectChanged(QRectF)), this, SLOT(adjustSceneRect())); + connect(&(m_diagram -> border_and_titleblock), SIGNAL(diagramTitleChanged(const QString &)), this, SLOT(updateWindowTitle())); connect(diagram, SIGNAL(editElementRequired(ElementsLocation)), this, SIGNAL(editElementRequired(ElementsLocation))); connect(diagram, SIGNAL(findElementRequired(ElementsLocation)), this, SIGNAL(findElementRequired(ElementsLocation))); @@ -111,93 +111,113 @@ DiagramView::~DiagramView() { Selectionne tous les objets du schema */ void DiagramView::selectAll() { - m_scene -> selectAll(); + m_diagram -> selectAll(); } /** Deslectionne tous les objets selectionnes */ void DiagramView::selectNothing() { - m_scene -> deselectAll(); + m_diagram -> deselectAll(); } /** Inverse l'etat de selection de tous les objets du schema */ void DiagramView::selectInvert() { - m_scene -> invertSelection(); + m_diagram -> invertSelection(); } /** - Supprime les composants selectionnes -*/ -void DiagramView::deleteSelection() { - if (m_scene -> isReadOnly()) return; - DiagramContent removed_content = m_scene -> selectedContent(); - m_scene -> clearSelection(); - m_scene -> undoStack().push(new DeleteElementsCommand(m_scene, removed_content)); + * @brief DiagramView::deleteSelection + * Delete the selected items + */ +void DiagramView::deleteSelection() +{ + if (m_diagram -> isReadOnly()) + return; + DiagramContent removed_content = m_diagram->selectedContent(); + m_diagram->clearSelection(); + m_diagram->undoStack().push(new DeleteQGraphicsItemCommand(m_diagram, removed_content)); adjustSceneRect(); } /** - Pivote les composants selectionnes -*/ -void DiagramView::rotateSelection() { - if (m_scene -> isReadOnly()) return; + * @brief DiagramView::rotateSelection + * Rotate the selected items + */ +void DiagramView::rotateSelection() +{ + if (m_diagram->isReadOnly()) + return; - // recupere les elements et les champs de texte a pivoter QList elements_to_rotate; QList texts_to_rotate; QList images_to_rotate; - foreach (QGraphicsItem *item, m_scene -> selectedItems()) { - if (Element *e = qgraphicsitem_cast(item)) { + + for (QGraphicsItem *item : m_diagram->selectedItems()) + { + if (Element *e = qgraphicsitem_cast(item)) elements_to_rotate << e; - } else if (ConductorTextItem *cti = qgraphicsitem_cast(item)) { + else if (ConductorTextItem *cti = qgraphicsitem_cast(item)) texts_to_rotate << cti; - } else if (IndependentTextItem *iti = qgraphicsitem_cast(item)) { + else if (IndependentTextItem *iti = qgraphicsitem_cast(item)) texts_to_rotate << iti; - } else if (ElementTextItem *eti = qgraphicsitem_cast(item)) { - // on ne pivote un texte d'element que si son parent n'est pas selectionne - if (eti -> parentItem() && !eti -> parentItem() -> isSelected()) { + 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 (DiagramImageItem *dii = qgraphicsitem_cast(item)) { - images_to_rotate << dii; } + 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; } - // effectue les rotations s'il y a quelque chose a pivoter - if (elements_to_rotate.isEmpty() && texts_to_rotate.isEmpty() && images_to_rotate.isEmpty()) return; - m_scene -> undoStack().push(new RotateElementsCommand(elements_to_rotate, texts_to_rotate, images_to_rotate)); + //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)); } -void DiagramView::rotateTexts() { - if (m_scene -> isReadOnly()) return; +/** + * @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; - // recupere les champs de texte a orienter + //Get the texts fields QList texts_to_rotate; - foreach (QGraphicsItem *item, m_scene -> selectedItems()) { - if (ConductorTextItem *cti = qgraphicsitem_cast(item)) { + for (QGraphicsItem *item : m_diagram->selectedItems()) + { + if (ConductorTextItem *cti = qgraphicsitem_cast(item)) texts_to_rotate << cti; - } else if (IndependentTextItem *iti = qgraphicsitem_cast(item)) { + else if (IndependentTextItem *iti = qgraphicsitem_cast(item)) texts_to_rotate << iti; - } else if (ElementTextItem *eti = qgraphicsitem_cast(item)) { - // ici, on pivote un texte d'element meme si son parent est selectionne + 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; - // effectue les rotations s'il y a quelque chose a pivoter - if (texts_to_rotate.isEmpty()) return; - - // demande un angle a l'utilisateur + //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")); -// ori_text_dialog.setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); QTextOrientationSpinBoxWidget *ori_widget = QETApp::createTextOrientationSpinBoxWidget(); @@ -207,22 +227,18 @@ void DiagramView::rotateTexts() { } ori_widget -> spinBox() -> selectAll(); - // boutons QDialogButtonBox buttons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); connect(&buttons, SIGNAL(accepted()), &ori_text_dialog, SLOT(accept())); connect(&buttons, SIGNAL(rejected()), &ori_text_dialog, SLOT(reject())); - - // ajout dans une disposition verticale + QVBoxLayout layout_v(&ori_text_dialog); layout_v.setSizeConstraint(QLayout::SetFixedSize); layout_v.addWidget(ori_widget); layout_v.addStretch(); layout_v.addWidget(&buttons); - // si le dialogue est accepte - if (ori_text_dialog.exec() == QDialog::Accepted) { - m_scene -> undoStack().push(new RotateTextsCommand(texts_to_rotate, ori_widget -> orientation())); - } + if (ori_text_dialog.exec() == QDialog::Accepted) + m_diagram -> undoStack().push(new RotateTextsCommand(texts_to_rotate, ori_widget -> orientation())); } /** @@ -307,11 +323,11 @@ void DiagramView::handleTitleBlockDrop(QDropEvent *e) { if (tbt_loc.isValid()) { // fetch the current title block properties - TitleBlockProperties titleblock_properties_before = m_scene->border_and_titleblock.exportTitleBlock(); + TitleBlockProperties titleblock_properties_before = m_diagram->border_and_titleblock.exportTitleBlock(); // check the provided template is not already applied QETProject *tbt_parent_project = tbt_loc.parentProject(); - if (tbt_parent_project && tbt_parent_project == m_scene -> project()) + if (tbt_parent_project && tbt_parent_project == m_diagram -> project()) { // same parent project and same name = same title block template if (tbt_loc.name() == titleblock_properties_before.template_name) @@ -324,7 +340,7 @@ void DiagramView::handleTitleBlockDrop(QDropEvent *e) { { IntegrationMoveTitleBlockTemplatesHandler *handler = new IntegrationMoveTitleBlockTemplatesHandler(this); //QString error_message; - integrated_template_name = m_scene->project()->integrateTitleBlockTemplate(tbt_loc, handler); + integrated_template_name = m_diagram->project()->integrateTitleBlockTemplate(tbt_loc, handler); if (integrated_template_name.isEmpty()) return; @@ -336,7 +352,7 @@ void DiagramView::handleTitleBlockDrop(QDropEvent *e) { TitleBlockProperties titleblock_properties_after = titleblock_properties_before; titleblock_properties_after.template_name = integrated_template_name; - m_scene->undoStack().push(new ChangeTitleBlockCommand(m_scene, titleblock_properties_before, titleblock_properties_after)); + m_diagram->undoStack().push(new ChangeTitleBlockCommand(m_diagram, titleblock_properties_before, titleblock_properties_after)); adjustSceneRect(); } @@ -348,7 +364,7 @@ void DiagramView::handleTitleBlockDrop(QDropEvent *e) { * @param e the QDropEvent describing the current drag'n drop */ void DiagramView::handleTextDrop(QDropEvent *e) { - if (m_scene -> isReadOnly() || (e -> mimeData() -> hasText() == false) ) return; + if (m_diagram -> isReadOnly() || (e -> mimeData() -> hasText() == false) ) return; IndependentTextItem *iti = new IndependentTextItem (e -> mimeData() -> text()); @@ -356,7 +372,7 @@ void DiagramView::handleTextDrop(QDropEvent *e) { iti -> setHtml (e -> mimeData() -> text()); } - m_scene -> undoStack().push(new AddItemCommand(iti, m_scene, mapToScene(e->pos()))); + m_diagram -> undoStack().push(new AddItemCommand(iti, m_diagram, mapToScene(e->pos()))); } /** @@ -398,9 +414,8 @@ void DiagramView::zoom(const qreal zoom_factor) (horizontalScrollBar()->maximum() || verticalScrollBar()->maximum()) ) scale(zoom_factor, zoom_factor); } - m_scene->adjustSceneRect(); + m_diagram->adjustSceneRect(); adjustGridToZoom(); - adjustSceneRect(); } /** @@ -410,7 +425,7 @@ void DiagramView::zoom(const qreal zoom_factor) */ void DiagramView::zoomFit() { adjustSceneRect(); - fitInView(m_scene->sceneRect(), Qt::KeepAspectRatio); + fitInView(m_diagram->sceneRect(), Qt::KeepAspectRatio); adjustGridToZoom(); } @@ -418,7 +433,7 @@ void DiagramView::zoomFit() { Adjust zoom to fit all elements in the view, regardless of diagram borders. */ void DiagramView::zoomContent() { - fitInView(m_scene -> itemsBoundingRect(), Qt::KeepAspectRatio); + fitInView(m_diagram -> itemsBoundingRect(), Qt::KeepAspectRatio); adjustGridToZoom(); } @@ -435,9 +450,9 @@ void DiagramView::zoomReset() { */ void DiagramView::cut() { copy(); - DiagramContent cut_content = m_scene -> selectedContent(); - m_scene -> clearSelection(); - m_scene -> undoStack().push(new CutDiagramCommand(m_scene, cut_content)); + DiagramContent cut_content = m_diagram -> selectedContent(); + m_diagram -> clearSelection(); + m_diagram -> undoStack().push(new CutDiagramCommand(m_diagram, cut_content)); } /** @@ -445,7 +460,7 @@ void DiagramView::cut() { */ void DiagramView::copy() { QClipboard *presse_papier = QApplication::clipboard(); - QString contenu_presse_papier = m_scene -> toXml(false).toString(4); + QString contenu_presse_papier = m_diagram -> toXml(false).toString(4); if (presse_papier -> supportsSelection()) presse_papier -> setText(contenu_presse_papier, QClipboard::Selection); presse_papier -> setText(contenu_presse_papier); } @@ -457,7 +472,7 @@ void DiagramView::copy() { @param clipboard_mode Type de presse-papier a prendre en compte */ void DiagramView::paste(const QPointF &pos, QClipboard::Mode clipboard_mode) { - if (!isInteractive() || m_scene -> isReadOnly()) return; + if (!isInteractive() || m_diagram -> isReadOnly()) return; QString texte_presse_papier = QApplication::clipboard() -> text(clipboard_mode); if ((texte_presse_papier).isEmpty()) return; @@ -468,12 +483,12 @@ void DiagramView::paste(const QPointF &pos, QClipboard::Mode clipboard_mode) { // objet pour recuperer le contenu ajoute au schema par le coller DiagramContent content_pasted; this->diagram()->item_paste = true; - m_scene -> fromXml(document_xml, pos, false, &content_pasted); + m_diagram -> fromXml(document_xml, pos, false, &content_pasted); // si quelque chose a effectivement ete ajoute au schema, on cree un objet d'annulation if (content_pasted.count()) { - m_scene -> clearSelection(); - m_scene -> undoStack().push(new PasteDiagramCommand(m_scene, content_pasted)); + m_diagram -> clearSelection(); + m_diagram -> undoStack().push(new PasteDiagramCommand(m_diagram, content_pasted)); adjustSceneRect(); } this->diagram()->item_paste = false; @@ -483,7 +498,7 @@ void DiagramView::paste(const QPointF &pos, QClipboard::Mode clipboard_mode) { Colle le contenu du presse-papier sur le schema a la position de la souris */ void DiagramView::pasteHere() { - paste(mapToScene(paste_here_pos)); + paste(mapToScene(m_paste_here_pos)); } /** @@ -492,10 +507,10 @@ void DiagramView::pasteHere() { */ void DiagramView::mousePressEvent(QMouseEvent *e) { - if (fresh_focus_in_) + if (m_fresh_focus_in) { switchToVisualisationModeIfNeeded(e); - fresh_focus_in_ = false; + m_fresh_focus_in = false; } if (m_event_interface && m_event_interface->mousePressEvent(e)) return; @@ -503,7 +518,7 @@ void DiagramView::mousePressEvent(QMouseEvent *e) //Start drag view when hold the middle button if (e->button() == Qt::MidButton) { - rubber_band_origin = e->pos(); + m_rubber_band_origin = e->pos(); viewport()->setCursor(Qt::ClosedHandCursor); } @@ -523,11 +538,10 @@ void DiagramView::mouseMoveEvent(QMouseEvent *e) { QScrollBar *h = horizontalScrollBar(); QScrollBar *v = verticalScrollBar(); - QPointF pos = rubber_band_origin - e -> pos(); - rubber_band_origin = e -> pos(); + QPointF pos = m_rubber_band_origin - e -> pos(); + m_rubber_band_origin = e -> pos(); h -> setValue(h -> value() + pos.x()); v -> setValue(v -> value() + pos.y()); - adjustSceneRect(); } else QGraphicsView::mouseMoveEvent(e); @@ -619,7 +633,7 @@ bool DiagramView::gestureEvent(QGestureEvent *event) */ void DiagramView::focusInEvent(QFocusEvent *e) { if (e -> reason() == Qt::MouseFocusReason) { - fresh_focus_in_ = true; + m_fresh_focus_in = true; } } @@ -641,10 +655,10 @@ switch(e -> key()) case Qt::Key_Home: if (!hasTextItems()) { if ( - qgraphicsitem_cast(m_scene->focusItem()) || - qgraphicsitem_cast(m_scene->focusItem()) || - qgraphicsitem_cast(m_scene->focusItem()) || - qgraphicsitem_cast(m_scene->focusItem()) + qgraphicsitem_cast(m_diagram->focusItem()) || + qgraphicsitem_cast(m_diagram->focusItem()) || + qgraphicsitem_cast(m_diagram->focusItem()) || + qgraphicsitem_cast(m_diagram->focusItem()) ) break; current_project->changeFirstTab(); @@ -654,10 +668,10 @@ switch(e -> key()) case Qt::Key_End: if (!hasTextItems()) { if ( - qgraphicsitem_cast(m_scene->focusItem()) || - qgraphicsitem_cast(m_scene->focusItem()) || - qgraphicsitem_cast(m_scene->focusItem()) || - qgraphicsitem_cast(m_scene->focusItem()) + qgraphicsitem_cast(m_diagram->focusItem()) || + qgraphicsitem_cast(m_diagram->focusItem()) || + qgraphicsitem_cast(m_diagram->focusItem()) || + qgraphicsitem_cast(m_diagram->focusItem()) ) break; current_project->changeLastTab(); @@ -677,19 +691,19 @@ switch(e -> key()) if (e->modifiers() & Qt::ControlModifier) zoom(1.15); case Qt::Key_Up: - if(!(m_scene->selectedContent().items(255).isEmpty())){ + if(!(m_diagram->selectedContent().items(DiagramContent::All).isEmpty())){ scrollOnMovement(e); } case Qt::Key_Down: - if(!(m_scene->selectedContent().items(255).isEmpty())){ + if(!(m_diagram->selectedContent().items(DiagramContent::All).isEmpty())){ scrollOnMovement(e); } case Qt::Key_Left: - if(!(m_scene->selectedContent().items(255).isEmpty())){ + if(!(m_diagram->selectedContent().items(DiagramContent::All).isEmpty())){ scrollOnMovement(e); } case Qt::Key_Right: - if(!(m_scene->selectedContent().items(255).isEmpty())){ + if(!(m_diagram->selectedContent().items(DiagramContent::All).isEmpty())){ scrollOnMovement(e); } } @@ -714,7 +728,7 @@ void DiagramView::keyReleaseEvent(QKeyEvent *e) { or below the editor SceneRect is expanded */ void DiagramView::scrollOnMovement(QKeyEvent *e){ - QList selected_elmts = m_scene->selectedContent().items(255); + QList selected_elmts = m_diagram->selectedContent().items(DiagramContent::All); QRectF viewed_scene = viewedSceneRect(); foreach (QGraphicsItem *qgi, selected_elmts){ if (qgraphicsitem_cast(qgi)) continue; @@ -755,10 +769,10 @@ void DiagramView::scrollOnMovement(QKeyEvent *e){ h_increment = 2*qgi->boundingRect().right(); if (h_increment == 0) h_increment = -2*qgi->boundingRect().width(); } - if (((elmt_right >= m_scene->sceneRect().right() - qgi->boundingRect().right()) || - (elmt_bottom >= m_scene->sceneRect().bottom() - qgi->boundingRect().bottom())) && + if (((elmt_right >= m_diagram->sceneRect().right() - qgi->boundingRect().right()) || + (elmt_bottom >= m_diagram->sceneRect().bottom() - qgi->boundingRect().bottom())) && (e->key()==Qt::Key_Right || e->key()==Qt::Key_Down)){ - m_scene->adjustSceneRect(); + m_diagram->adjustSceneRect(); } h -> setValue(h -> value() + h_increment); v -> setValue(v -> value() + v_increment); @@ -775,7 +789,7 @@ void DiagramView::scrollOnMovement(QKeyEvent *e){ */ QString DiagramView::title() const { QString view_title; - QString diagram_title(m_scene -> title()); + QString diagram_title(m_diagram -> title()); if (diagram_title.isEmpty()) { view_title = tr("Sans titre", "what to display for untitled diagrams"); } else { @@ -789,14 +803,14 @@ QString DiagramView::title() const { * Edit the properties of the viewed digram */ void DiagramView::editDiagramProperties() { - DiagramPropertiesDialog::diagramPropertiesDialog(m_scene, diagramEditor()); + DiagramPropertiesDialog::diagramPropertiesDialog(m_diagram, diagramEditor()); } /** @return true s'il y a des items selectionnes sur le schema, false sinon */ bool DiagramView::hasSelectedItems() { - return(m_scene -> selectedItems().size() > 0); + return(m_diagram -> selectedItems().size() > 0); } /** @@ -804,7 +818,7 @@ bool DiagramView::hasSelectedItems() { peuvent etre copies dans le presse-papier, false sinon */ bool DiagramView::hasCopiableItems() { - foreach(QGraphicsItem *qgi, m_scene -> selectedItems()) { + foreach(QGraphicsItem *qgi, m_diagram -> selectedItems()) { if ( qgraphicsitem_cast(qgi) || qgraphicsitem_cast(qgi) || @@ -821,7 +835,7 @@ bool DiagramView::hasCopiableItems() { @return true if there is any Text Item selected */ bool DiagramView::hasTextItems() { - foreach(QGraphicsItem *qgi, m_scene -> selectedItems()) { + foreach(QGraphicsItem *qgi, m_diagram -> selectedItems()) { if ( qgraphicsitem_cast(qgi) || qgraphicsitem_cast(qgi) || @@ -835,20 +849,20 @@ bool DiagramView::hasTextItems() { } /** - @return true s'il y a des items selectionnes sur le schema et que ceux-ci - peuvent etre supprimes, false sinon -*/ -bool DiagramView::hasDeletableItems() { - foreach(QGraphicsItem *qgi, m_scene -> selectedItems()) { - if ( - qgraphicsitem_cast(qgi) || - qgraphicsitem_cast(qgi) || - qgraphicsitem_cast(qgi) || - qgraphicsitem_cast(qgi) || - qgraphicsitem_cast(qgi) - ) { - return(true); - } + * @brief DiagramView::hasDeletableItems + * @return True if a least on of selected item can be deleted + */ +bool DiagramView::hasDeletableItems() +{ + for(QGraphicsItem *qgi : m_diagram->selectedItems()) + { + if (qgi->type() == Element::Type || + qgi->type() == Conductor::Type || + qgi->type() == IndependentTextItem::Type || + qgi->type() == QetShapeItem::Type || + qgi->type() == DiagramImageItem::Type || + qgi->type() == DynamicElementTextItem::Type) + return true; } return(false); } @@ -857,64 +871,55 @@ bool DiagramView::hasDeletableItems() { Ajoute une colonne au schema. */ void DiagramView::addColumn() { - if (m_scene -> isReadOnly()) return; - BorderProperties old_bp = m_scene -> border_and_titleblock.exportBorder(); - BorderProperties new_bp = m_scene -> border_and_titleblock.exportBorder(); + if (m_diagram -> isReadOnly()) return; + BorderProperties old_bp = m_diagram -> border_and_titleblock.exportBorder(); + BorderProperties new_bp = m_diagram -> border_and_titleblock.exportBorder(); new_bp.columns_count += 1; - m_scene -> undoStack().push(new ChangeBorderCommand(m_scene, old_bp, new_bp)); + m_diagram -> undoStack().push(new ChangeBorderCommand(m_diagram, old_bp, new_bp)); } /** Enleve une colonne au schema. */ void DiagramView::removeColumn() { - if (m_scene -> isReadOnly()) return; - BorderProperties old_bp = m_scene -> border_and_titleblock.exportBorder(); - BorderProperties new_bp = m_scene -> border_and_titleblock.exportBorder(); + if (m_diagram -> isReadOnly()) return; + BorderProperties old_bp = m_diagram -> border_and_titleblock.exportBorder(); + BorderProperties new_bp = m_diagram -> border_and_titleblock.exportBorder(); new_bp.columns_count -= 1; - m_scene -> undoStack().push(new ChangeBorderCommand(m_scene, old_bp, new_bp)); + m_diagram -> undoStack().push(new ChangeBorderCommand(m_diagram, old_bp, new_bp)); } /** Agrandit le schema en hauteur */ void DiagramView::addRow() { - if (m_scene -> isReadOnly()) return; - BorderProperties old_bp = m_scene -> border_and_titleblock.exportBorder(); - BorderProperties new_bp = m_scene -> border_and_titleblock.exportBorder(); + if (m_diagram -> isReadOnly()) return; + BorderProperties old_bp = m_diagram -> border_and_titleblock.exportBorder(); + BorderProperties new_bp = m_diagram -> border_and_titleblock.exportBorder(); new_bp.rows_count += 1; - m_scene -> undoStack().push(new ChangeBorderCommand(m_scene, old_bp, new_bp)); + m_diagram -> undoStack().push(new ChangeBorderCommand(m_diagram, old_bp, new_bp)); } /** Retrecit le schema en hauteur */ void DiagramView::removeRow() { - if (m_scene -> isReadOnly()) return; - BorderProperties old_bp = m_scene -> border_and_titleblock.exportBorder(); - BorderProperties new_bp = m_scene -> border_and_titleblock.exportBorder(); + if (m_diagram -> isReadOnly()) return; + BorderProperties old_bp = m_diagram -> border_and_titleblock.exportBorder(); + BorderProperties new_bp = m_diagram -> border_and_titleblock.exportBorder(); new_bp.rows_count -= 1; - m_scene -> undoStack().push(new ChangeBorderCommand(m_scene, old_bp, new_bp)); + m_diagram -> undoStack().push(new ChangeBorderCommand(m_diagram, old_bp, new_bp)); } /** * @brief DiagramView::adjustSceneRect * Calcul and set the area of the scene visualized by this view + * The area are diagram sceneRect * 2. */ void DiagramView::adjustSceneRect() { - QRectF scene_rect = m_scene->sceneRect(); + QRectF scene_rect = m_diagram->sceneRect(); scene_rect.adjust(-Diagram::margin, -Diagram::margin, Diagram::margin, Diagram::margin); - - QSettings settings; - if (settings.value("diagrameditor/zoom-out-beyond-of-folio", false).toBool()) - { - //When zoom out beyong of folio is active, - //we always adjust the scene rect to be 1/3 bigger than the wiewport - QRectF vpbr = mapToScene(viewport()->rect()).boundingRect(); - vpbr.adjust(0, 0, vpbr.width()/3, vpbr.height()/3); - scene_rect = scene_rect.united(vpbr); - } setSceneRect(scene_rect); } @@ -931,9 +936,9 @@ void DiagramView::updateWindowTitle() { void DiagramView::adjustGridToZoom() { QRectF viewed_scene = viewedSceneRect(); if (diagramEditor()->drawGrid()) - m_scene->setDisplayGrid(viewed_scene.width() < 2000 || viewed_scene.height() < 2000); + m_diagram->setDisplayGrid(viewed_scene.width() < 2000 || viewed_scene.height() < 2000); else - m_scene->setDisplayGrid(false); + m_diagram->setDisplayGrid(false); } /** @@ -965,7 +970,7 @@ bool DiagramView::mustIntegrateTitleBlockTemplate(const TitleBlockTemplateLocati QETProject *tbt_parent_project = tbt_loc.parentProject(); if (!tbt_parent_project) return(true); - return(tbt_parent_project != m_scene -> project()); + return(tbt_parent_project != m_diagram -> project()); } /** @@ -973,9 +978,9 @@ bool DiagramView::mustIntegrateTitleBlockTemplate(const TitleBlockTemplateLocati seule */ void DiagramView::applyReadOnly() { - if (!m_scene) return; + if (!m_diagram) return; - bool is_writable = !m_scene -> isReadOnly(); + bool is_writable = !m_diagram -> isReadOnly(); setInteractive(is_writable); setAcceptDrops(is_writable); } @@ -985,7 +990,7 @@ void DiagramView::applyReadOnly() { */ void DiagramView::editSelectionProperties() { // get selection - DiagramContent selection = m_scene -> selectedContent(); + DiagramContent selection = m_diagram -> selectedContent(); // if selection contains nothing return int selected_items_count = selection.count(DiagramContent::All | DiagramContent::SelectedOnly); @@ -999,8 +1004,8 @@ void DiagramView::editSelectionProperties() { if (selection.conductors(DiagramContent::AnyConductor | DiagramContent::SelectedOnly).size()) selection.conductors().first()->editProperty(); // edit element - else if (selection.elements.size()) - selection.elements.toList().first() -> editProperty(); + else if (selection.m_elements.size()) + selection.m_elements.toList().first() -> editProperty(); } else { @@ -1022,7 +1027,7 @@ void DiagramView::editSelectionProperties() { */ void DiagramView::editSelectedConductorColor() { // retrieve selected content - DiagramContent selection = m_scene -> selectedContent(); + DiagramContent selection = m_diagram -> selectedContent(); // we'll focus on the selected conductor (we do not handle multiple conductors edition) QList selected_conductors = selection.conductors(DiagramContent::AnyConductor | DiagramContent::SelectedOnly); @@ -1037,7 +1042,7 @@ void DiagramView::editSelectedConductorColor() { */ void DiagramView::editConductorColor(Conductor *edited_conductor) { - if (m_scene -> isReadOnly() || !edited_conductor) return; + if (m_diagram -> isReadOnly() || !edited_conductor) return; // store the initial properties of the provided conductor ConductorProperties initial_properties = edited_conductor -> properties(); @@ -1073,9 +1078,9 @@ void DiagramView::editConductorColor(Conductor *edited_conductor) Reinitialise le profil des conducteurs selectionnes */ void DiagramView::resetConductors() { - if (m_scene -> isReadOnly()) return; + if (m_diagram -> isReadOnly()) return; // recupere les conducteurs selectionnes - QSet selected_conductors = m_scene -> selectedConductors(); + QSet selected_conductors = m_diagram -> selectedConductors(); // repere les conducteurs modifies (= profil non nul) QHash conductors_and_profiles; @@ -1092,7 +1097,7 @@ void DiagramView::resetConductors() { } if (conductors_and_profiles.isEmpty()) return; - m_scene -> undoStack().push(new ResetConductorCommand(conductors_and_profiles)); + m_diagram -> undoStack().push(new ResetConductorCommand(conductors_and_profiles)); } /** @@ -1186,9 +1191,9 @@ bool DiagramView::isCtrlShifting(QInputEvent *e) { */ bool DiagramView::selectedItemHasFocus() { return( - m_scene -> hasFocus() && - m_scene -> focusItem() && - m_scene -> focusItem() -> isSelected() + m_diagram -> hasFocus() && + m_diagram -> focusItem() && + m_diagram -> focusItem() -> isSelected() ); } @@ -1197,9 +1202,9 @@ bool DiagramView::selectedItemHasFocus() { * Edit the selected item if he can be edited and if only one item is selected */ void DiagramView::editSelection() { - if (m_scene -> isReadOnly() || m_scene -> selectedItems().size() != 1 ) return; + if (m_diagram -> isReadOnly() || m_diagram -> selectedItems().size() != 1 ) return; - QGraphicsItem *item = m_scene->selectedItems().first(); + QGraphicsItem *item = m_diagram->selectedItems().first(); //We use dynamic_cast instead of qgraphicsitem_cast for QetGraphicsItem //because they haven't got they own type(). @@ -1230,31 +1235,31 @@ void DiagramView::setEventInterface(DVEventInterface *event_interface) @param e Evenement decrivant la demande de menu contextuel */ void DiagramView::contextMenuEvent(QContextMenuEvent *e) { - if (QGraphicsItem *qgi = m_scene -> itemAt(mapToScene(e -> pos()), transform())) { - if (!qgi -> isSelected()) m_scene -> clearSelection(); + if (QGraphicsItem *qgi = m_diagram -> itemAt(mapToScene(e -> pos()), transform())) { + if (!qgi -> isSelected()) m_diagram -> clearSelection(); qgi -> setSelected(true); } if (QETDiagramEditor *qde = diagramEditor()) { - context_menu -> clear(); - if (m_scene -> selectedItems().isEmpty()) { - paste_here_pos = e -> pos(); - paste_here -> setEnabled(Diagram::clipboardMayContainDiagram()); - context_menu -> addAction(paste_here); - context_menu -> addSeparator(); - context_menu -> addAction(qde -> infos_diagram); - context_menu -> addActions(qde -> m_row_column_actions_group.actions()); + m_context_menu -> clear(); + if (m_diagram -> selectedItems().isEmpty()) { + m_paste_here_pos = e -> pos(); + m_paste_here -> setEnabled(Diagram::clipboardMayContainDiagram()); + m_context_menu -> addAction(m_paste_here); + m_context_menu -> addSeparator(); + m_context_menu -> addAction(qde -> infos_diagram); + m_context_menu -> addActions(qde -> m_row_column_actions_group.actions()); } else { - context_menu -> addAction(qde -> cut); - context_menu -> addAction(qde -> copy); - context_menu -> addSeparator(); - context_menu -> addAction(qde -> conductor_reset); - context_menu -> addSeparator(); - context_menu -> addActions(qde -> m_selection_actions_group.actions()); + m_context_menu -> addAction(qde -> m_cut); + m_context_menu -> addAction(qde -> m_copy); + m_context_menu -> addSeparator(); + m_context_menu -> addAction(qde -> m_conductor_reset); + m_context_menu -> addSeparator(); + m_context_menu -> addActions(qde -> m_selection_actions_group.actions()); } // affiche le menu contextuel - context_menu -> popup(e -> globalPos()); + m_context_menu -> popup(e -> globalPos()); } e -> accept(); } @@ -1280,7 +1285,7 @@ void DiagramView::mouseDoubleClickEvent(QMouseEvent *e) { if (m_event_interface && m_event_interface -> mouseDoubleClickEvent(e)) return; - BorderTitleBlock &bi = m_scene -> border_and_titleblock; + BorderTitleBlock &bi = m_diagram -> border_and_titleblock; //Get the click pos on the diagram QPointF click_pos = viewportTransform().inverted().map(e -> pos()); diff --git a/sources/diagramview.h b/sources/diagramview.h index 09c11b37f..eadcb7cb9 100644 --- a/sources/diagramview.h +++ b/sources/diagramview.h @@ -49,15 +49,14 @@ class DiagramView : public QGraphicsView // attributes - Diagram *m_scene; - DVEventInterface *m_event_interface; - QMenu *context_menu; - QAction *paste_here; - QPoint paste_here_pos; - QPointF rubber_band_origin; - bool fresh_focus_in_; ///< Indicate the focus was freshly gained - bool m_first_activation; - + Diagram *m_diagram; + DVEventInterface *m_event_interface = nullptr; + QMenu *m_context_menu; + QAction *m_paste_here; + QPoint m_paste_here_pos; + QPointF m_rubber_band_origin; + bool m_fresh_focus_in, + m_first_activation = true; public: QString title() const; void editDiagramProperties(); @@ -66,7 +65,7 @@ class DiagramView : public QGraphicsView void addRow(); void removeRow(); /// @return the diagram rendered by this view - Diagram *diagram() { return(m_scene); } + Diagram *diagram() { return(m_diagram); } QETDiagramEditor *diagramEditor() const; bool hasSelectedItems(); bool hasCopiableItems(); diff --git a/sources/elementsmover.cpp b/sources/elementsmover.cpp index 6df1e7dd0..a7ab60da8 100644 --- a/sources/elementsmover.cpp +++ b/sources/elementsmover.cpp @@ -105,12 +105,12 @@ void ElementsMover::continueMovement(const QPointF &movement) { } // Move some conductors - foreach(Conductor *conductor, moved_content_.conductorsToMove) { + foreach(Conductor *conductor, moved_content_.m_conductors_to_move) { conductor -> setPos(conductor -> pos() + movement); } // Recalcul the path of other conductors - foreach(Conductor *conductor, moved_content_.conductorsToUpdate) { + foreach(Conductor *conductor, moved_content_.m_conductors_to_update) { conductor -> updatePath(); } } @@ -142,7 +142,7 @@ void ElementsMover::endMovement() moved_content_.items(dc::Elements).size() == 1 && diagram_ -> project() -> autoConductor()) { - Element *elmt = moved_content_.elements.toList().first(); + Element *elmt = moved_content_.m_elements.toList().first(); int acc = elmt->AlignedFreeTerminals().size(); diff --git a/sources/elementtextsmover.cpp b/sources/elementtextsmover.cpp index 7ab0c9dd0..7316dacd3 100644 --- a/sources/elementtextsmover.cpp +++ b/sources/elementtextsmover.cpp @@ -19,15 +19,12 @@ #include "elementtextitem.h" #include "diagram.h" #include "QPropertyUndoCommand/qpropertyundocommand.h" +#include "dynamicelementtextitem.h" /** * @brief ElementTextsMover::ElementTextsMover */ -ElementTextsMover::ElementTextsMover() : - movement_running_(false), - diagram_(nullptr), - movement_driver_(nullptr) -{} +ElementTextsMover::ElementTextsMover() {} /** * @brief ElementTextsMover::isReady @@ -35,7 +32,7 @@ ElementTextsMover::ElementTextsMover() : * False if this ElementTextsMover is actually process a movement */ bool ElementTextsMover::isReady() const { - return(!movement_running_); + return(!m_movement_running); } /** @@ -47,24 +44,24 @@ bool ElementTextsMover::isReady() const { */ int ElementTextsMover::beginMovement(Diagram *diagram, QGraphicsItem *driver_item) { - if (movement_running_ || !diagram) return(-1); + if (m_movement_running || !diagram) return(-1); - diagram_ = diagram; - movement_driver_ = driver_item; + m_diagram = diagram; + m_movement_driver = driver_item; m_texts_item_H.clear(); - foreach(QGraphicsItem *item, diagram -> selectedItems()) + for(QGraphicsItem *item : diagram->selectedItems()) { - if (item->type() == ElementTextItem::Type) + if (item->type() == ElementTextItem::Type || item->type() == DynamicElementTextItem::Type) { - ElementTextItem *eti = static_cast (item); - m_texts_item_H.insert(eti, eti->pos()); + DiagramTextItem *dti = static_cast (item); + m_texts_item_H.insert(dti, dti->pos()); } } if (!m_texts_item_H.size()) return(-1); - movement_running_ = true; + m_movement_running = true; return(m_texts_item_H.size()); } @@ -77,13 +74,14 @@ int ElementTextsMover::beginMovement(Diagram *diagram, QGraphicsItem *driver_ite */ void ElementTextsMover::continueMovement(const QPointF &movement) { - if (!movement_running_ || movement.isNull()) return; + if (!m_movement_running || movement.isNull()) return; - foreach(ElementTextItem *text_item, m_texts_item_H.keys()) + for(DiagramTextItem *text_item : m_texts_item_H.keys()) { - if (text_item == movement_driver_) continue; - QPointF applied_movement = text_item -> mapMovementToParent(text_item-> mapMovementFromScene(movement)); - text_item -> setPos(text_item -> pos() + applied_movement); + if (text_item == m_movement_driver) + continue; + QPointF applied_movement = text_item->mapMovementToParent(text_item->mapMovementFromScene(movement)); + text_item->setPos(text_item->pos() + applied_movement); } } @@ -94,31 +92,25 @@ void ElementTextsMover::continueMovement(const QPointF &movement) void ElementTextsMover::endMovement() { //No movement running, or no text to move - if (!movement_running_ || m_texts_item_H.isEmpty()) return; - //Movement is null - ElementTextItem *eti = m_texts_item_H.keys().first(); - if (eti->pos() == m_texts_item_H.value(eti)) return; + if (!m_movement_running || m_texts_item_H.isEmpty()) + return; - QPropertyUndoCommand *undo = nullptr; - - foreach (ElementTextItem *eti, m_texts_item_H.keys()) + //Movement is null + DiagramTextItem *dti = m_texts_item_H.keys().first(); + if (dti->pos() == m_texts_item_H.value(dti)) + return; + + QUndoCommand *undo = new QUndoCommand(m_texts_item_H.size() == 1 ? QString(QObject::tr("Déplacer un texte d'élément")) : + QString(QObject::tr("Déplacer %1 textes d'élément").arg(m_texts_item_H.size()))); + + for (DiagramTextItem *dti : m_texts_item_H.keys()) { - if (undo) - { - QPropertyUndoCommand *child_undo = new QPropertyUndoCommand(eti, "pos", m_texts_item_H.value(eti), eti->pos(), undo); - child_undo->enableAnimation(); - } - else - { - undo = new QPropertyUndoCommand(eti, "pos", m_texts_item_H.value(eti), eti->pos()); - undo->enableAnimation(); - QString txt = m_texts_item_H.size() == 1? QString(QObject::tr("Déplacer un texte d'élément")) : - QString(QObject::tr("Déplacer %1 textes d'élément").arg(m_texts_item_H.size())); - undo->setText(txt); - } + QPropertyUndoCommand *child_undo = new QPropertyUndoCommand(dti, "pos", m_texts_item_H.value(dti), dti->pos(), undo); + child_undo->enableAnimation(); + } - diagram_->undoStack().push(undo); + m_diagram->undoStack().push(undo); - movement_running_ = false; + m_movement_running = false; } diff --git a/sources/elementtextsmover.h b/sources/elementtextsmover.h index 81efc11cd..01621fc21 100644 --- a/sources/elementtextsmover.h +++ b/sources/elementtextsmover.h @@ -22,7 +22,7 @@ #include class QGraphicsItem; -class ElementTextItem; +class DiagramTextItem; class Diagram; /** @@ -38,14 +38,14 @@ class ElementTextsMover public: bool isReady() const; - int beginMovement(Diagram *, QGraphicsItem * = 0); + int beginMovement(Diagram *diagram, QGraphicsItem *driver_item = nullptr); void continueMovement(const QPointF &); void endMovement(); private: - bool movement_running_; - Diagram *diagram_; - QGraphicsItem *movement_driver_; - QHash m_texts_item_H; + bool m_movement_running = false; + Diagram *m_diagram = nullptr; + QGraphicsItem *m_movement_driver = nullptr; + QHash m_texts_item_H; }; #endif diff --git a/sources/qet.cpp b/sources/qet.cpp index cfc3c6c31..cb4f6e86a 100644 --- a/sources/qet.cpp +++ b/sources/qet.cpp @@ -232,7 +232,7 @@ bool QET::attributeIsAReal(const QDomElement &e, QString nom_attribut, qreal *re @return la proposition decrivant le nombre d'elements, de conducteurs et de textes */ -QString QET::ElementsAndConductorsSentence(int elements_count, int conductors_count, int texts_count, int images_count, int shapes_count) { +QString QET::ElementsAndConductorsSentence(int elements_count, int conductors_count, int texts_count, int images_count, int shapes_count, int element_text_count) { QString text; if (elements_count) { text += QObject::tr( @@ -240,61 +240,28 @@ QString QET::ElementsAndConductorsSentence(int elements_count, int conductors_co "part of a sentence listing the content of a diagram", elements_count ); - if ((conductors_count && texts_count) || - (conductors_count && images_count) || - (texts_count && images_count)) { - text += QObject::tr( - ", ", - "separator between elements and conductors in a sentence " - "listing the content of a diagram" - ); - } else if (conductors_count || texts_count || images_count) { - text += QObject::tr( - " et ", - "separator between elements and conductors (or texts) in a " - "sentence listing the content of a diagram" - ); - } } if (conductors_count) { + if (!text.isEmpty()) text += ", "; text += QObject::tr( "%n conducteur(s)", "part of a sentence listing the content of a diagram", conductors_count ); - if (texts_count && images_count) { - text += QObject::tr( - ", ", - "separator between elements and conductors in a sentence " - "listing the content of a diagram" - ); - } - else if (texts_count || images_count) { - text += QObject::tr( - " et ", - "separator between conductors and texts in a sentence listing " - "the content of a diagram" - ); - } } if (texts_count) { + if (!text.isEmpty()) text += ", "; text += QObject::tr( "%n champ(s) de texte", "part of a sentence listing the content of a diagram", texts_count ); - if (images_count) { - text += QObject::tr( - " et ", - "separator between conductors and texts in a sentence listing " - "the content of a diagram" - ); - } } if (images_count) { + if (!text.isEmpty()) text += ", "; text += QObject::tr( "%n image(s)", "part of a sentence listing the content of a diagram", @@ -303,12 +270,22 @@ QString QET::ElementsAndConductorsSentence(int elements_count, int conductors_co } if (shapes_count) { + if (!text.isEmpty()) text += ", "; text += QObject::tr( "%n forme(s)", "part of a sentence listing the content of a diagram", shapes_count ); } + + if (element_text_count) { + if (!text.isEmpty()) text += ", "; + text += QObject::tr( + "%n texte(s) d'élément", + "part of a sentence listing the content of a diagram", + element_text_count); + } + return(text); } diff --git a/sources/qet.h b/sources/qet.h index 437e88e84..f0c53550d 100644 --- a/sources/qet.h +++ b/sources/qet.h @@ -143,7 +143,7 @@ namespace QET { bool orthogonalProjection(const QPointF &, const QLineF &, QPointF * = 0); bool attributeIsAnInteger(const QDomElement &, QString , int * = NULL); bool attributeIsAReal(const QDomElement &, QString , qreal * = NULL); - QString ElementsAndConductorsSentence(int, int, int = 0, int = 0, int = 0); + QString ElementsAndConductorsSentence(int, int, int = 0, int = 0, int = 0, int = 0); QList findInDomElement(const QDomElement &, const QString &); QList findInDomElement(const QDomElement &, const QString &, const QString &); QList forbiddenCharacters(); diff --git a/sources/qetdiagrameditor.cpp b/sources/qetdiagrameditor.cpp index f60720fd9..8b5a7202b 100644 --- a/sources/qetdiagrameditor.cpp +++ b/sources/qetdiagrameditor.cpp @@ -42,6 +42,9 @@ #include "diagrameventaddtext.h" #include "elementscollectionwidget.h" #include "autonumberingdockwidget.h" +#include "dynamicelementtextitem.h" +#include "conductortextitem.h" +#include "elementtextitem.h" #include #include @@ -242,24 +245,24 @@ void QETDiagramEditor::setUpActions() redo -> setStatusTip(tr("Restaure l'action annulée", "status bar tip")); //cut copy past action - cut = new QAction(QET::Icons::EditCut, tr("Co&uper"), this); - copy = new QAction(QET::Icons::EditCopy, tr("Cop&ier"), this); + m_cut = new QAction(QET::Icons::EditCut, tr("Co&uper"), this); + m_copy = new QAction(QET::Icons::EditCopy, tr("Cop&ier"), this); paste = new QAction(QET::Icons::EditPaste, tr("C&oller"), this); - cut -> setShortcut(QKeySequence::Cut); - copy -> setShortcut(QKeySequence::Copy); + m_cut -> setShortcut(QKeySequence::Cut); + m_copy -> setShortcut(QKeySequence::Copy); paste -> setShortcut(QKeySequence::Paste); - cut -> setStatusTip(tr("Transfère les éléments sélectionnés dans le presse-papier", "status bar tip")); - copy -> setStatusTip(tr("Copie les éléments sélectionnés dans le presse-papier", "status bar tip")); + m_cut -> setStatusTip(tr("Transfère les éléments sélectionnés dans le presse-papier", "status bar tip")); + m_copy -> setStatusTip(tr("Copie les éléments sélectionnés dans le presse-papier", "status bar tip")); paste -> setStatusTip(tr("Place les éléments du presse-papier sur le folio", "status bar tip")); - connect(cut, SIGNAL(triggered()), this, SLOT(slot_cut())); - connect(copy, SIGNAL(triggered()), this, SLOT(slot_copy())); + connect(m_cut, SIGNAL(triggered()), this, SLOT(slot_cut())); + connect(m_copy, SIGNAL(triggered()), this, SLOT(slot_copy())); connect(paste, SIGNAL(triggered()), this, SLOT(slot_paste())); - conductor_reset = new QAction(QET::Icons::ConductorSettings, tr("Réinitialiser les conducteurs"), this); - conductor_reset -> setShortcut( QKeySequence( tr("Ctrl+K") ) ); + m_conductor_reset = new QAction(QET::Icons::ConductorSettings, tr("Réinitialiser les conducteurs"), this); + m_conductor_reset -> setShortcut( QKeySequence( tr("Ctrl+K") ) ); m_auto_conductor = new QAction (QET::Icons::Autoconnect, tr("Création automatique de conducteur(s)","Tool tip of auto conductor"), this); m_auto_conductor -> setStatusTip (tr("Utiliser la création automatique de conducteur(s) quand cela est possible", "Status tip of auto conductor")); @@ -348,27 +351,27 @@ void QETDiagramEditor::setUpActions() connect(&m_row_column_actions_group, &QActionGroup::triggered, this, &QETDiagramEditor::rowColumnGroupTriggered); //Selections Actions (related to a selected item) - delete_selection = m_selection_actions_group.addAction( QET::Icons::EditDelete, tr("Supprimer") ); - rotate_selection = m_selection_actions_group.addAction( QET::Icons::ObjectRotateRight, tr("Pivoter") ); - rotate_texts = m_selection_actions_group.addAction( QET::Icons::ObjectRotateRight, tr("Orienter les textes") ); - find_element = m_selection_actions_group.addAction( tr("Retrouver dans le panel") ); - edit_selection = m_selection_actions_group.addAction( QET::Icons::ElementEdit, tr("Éditer l'item sélectionné") ); + m_delete_selection = m_selection_actions_group.addAction( QET::Icons::EditDelete, tr("Supprimer") ); + m_rotate_selection = m_selection_actions_group.addAction( QET::Icons::ObjectRotateRight, tr("Pivoter") ); + m_rotate_texts = m_selection_actions_group.addAction( QET::Icons::ObjectRotateRight, tr("Orienter les textes") ); + m_find_element = m_selection_actions_group.addAction( tr("Retrouver dans le panel") ); + m_edit_selection = m_selection_actions_group.addAction( QET::Icons::ElementEdit, tr("Éditer l'item sélectionné") ); - delete_selection -> setShortcut( QKeySequence::Delete); - rotate_selection -> setShortcut( QKeySequence( tr("Space") ) ); - rotate_texts -> setShortcut( QKeySequence( tr("Ctrl+Space") ) ); - edit_selection -> setShortcut( QKeySequence( tr("Ctrl+E") ) ); + m_delete_selection -> setShortcut( QKeySequence::Delete); + m_rotate_selection -> setShortcut( QKeySequence( tr("Space") ) ); + m_rotate_texts -> setShortcut( QKeySequence( tr("Ctrl+Space") ) ); + m_edit_selection -> setShortcut( QKeySequence( tr("Ctrl+E") ) ); - delete_selection -> setStatusTip( tr("Enlève les éléments sélectionnés du folio", "status bar tip")); - rotate_selection -> setStatusTip( tr("Pivote les éléments et textes sélectionnés", "status bar tip")); - rotate_texts -> setStatusTip( tr("Pivote les textes sélectionnés à un angle précis", "status bar tip")); - find_element -> setStatusTip( tr("Retrouve l'élément sélectionné dans le panel", "status bar tip")); + m_delete_selection -> setStatusTip( tr("Enlève les éléments sélectionnés du folio", "status bar tip")); + m_rotate_selection -> setStatusTip( tr("Pivote les éléments et textes sélectionnés", "status bar tip")); + m_rotate_texts -> setStatusTip( tr("Pivote les textes sélectionnés à un angle précis", "status bar tip")); + m_find_element -> setStatusTip( tr("Retrouve l'élément sélectionné dans le panel", "status bar tip")); - delete_selection ->setData("delete_selection"); - rotate_selection ->setData("rotate_selection"); - rotate_texts ->setData("rotate_selected_text"); - find_element ->setData("find_selected_element"); - edit_selection ->setData("edit_selected_element"); + m_delete_selection ->setData("delete_selection"); + m_rotate_selection ->setData("rotate_selection"); + m_rotate_texts ->setData("rotate_selected_text"); + m_find_element ->setData("find_selected_element"); + m_edit_selection ->setData("edit_selected_element"); connect(&m_selection_actions_group, &QActionGroup::triggered, this, &QETDiagramEditor::selectionGroupTriggered); @@ -452,7 +455,7 @@ void QETDiagramEditor::setUpActions() export_diagram -> setStatusTip(tr("Exporte le folio courant dans un autre format", "status bar tip")); print -> setStatusTip(tr("Imprime un ou plusieurs folios du projet courant", "status bar tip")); quit_editor -> setStatusTip(tr("Ferme l'application QElectroTech", "status bar tip")); - conductor_reset -> setStatusTip(tr("Recalcule les chemins des conducteurs sans tenir compte des modifications", "status bar tip")); + m_conductor_reset -> setStatusTip(tr("Recalcule les chemins des conducteurs sans tenir compte des modifications", "status bar tip")); infos_diagram -> setStatusTip(tr("Édite les propriétés du folio (dimensions, informations du cartouche, propriétés des conducteurs...)", "status bar tip")); windowed_view_mode -> setStatusTip(tr("Présente les différents projets ouverts dans des sous-fenêtres", "status bar tip")); @@ -503,7 +506,7 @@ void QETDiagramEditor::setUpActions() connect(cascade_window, SIGNAL(triggered()), &workspace, SLOT(cascadeSubWindows()) ); connect(next_window, SIGNAL(triggered()), &workspace, SLOT(activateNextSubWindow()) ); connect(prev_window, SIGNAL(triggered()), &workspace, SLOT(activatePreviousSubWindow()) ); - connect(conductor_reset, SIGNAL(triggered()), this, SLOT(slot_resetConductors()) ); + connect(m_conductor_reset, SIGNAL(triggered()), this, SLOT(slot_resetConductors()) ); connect(infos_diagram, SIGNAL(triggered()), this, SLOT(editCurrentDiagramProperties())); } @@ -526,12 +529,12 @@ void QETDiagramEditor::setUpToolBar() { main_bar -> addAction(undo); main_bar -> addAction(redo); main_bar -> addSeparator(); - main_bar -> addAction(cut); - main_bar -> addAction(copy); + main_bar -> addAction(m_cut); + main_bar -> addAction(m_copy); main_bar -> addAction(paste); main_bar -> addSeparator(); - main_bar -> addAction(delete_selection); - main_bar -> addAction(rotate_selection); + main_bar -> addAction(m_delete_selection); + main_bar -> addAction(m_rotate_selection); // Modes selection / visualisation et zoom view_bar -> addAction(mode_selection); @@ -543,7 +546,7 @@ void QETDiagramEditor::setUpToolBar() { view_bar -> addActions(m_zoom_action_toolBar); diagram_bar -> addAction (infos_diagram); - diagram_bar -> addAction (conductor_reset); + diagram_bar -> addAction (m_conductor_reset); diagram_bar -> addAction (m_auto_conductor); m_add_item_toolBar = new QToolBar(tr("Ajouter"), this); @@ -592,15 +595,15 @@ void QETDiagramEditor::setUpMenu() { menu_edition -> addAction(undo); menu_edition -> addAction(redo); menu_edition -> addSeparator(); - menu_edition -> addAction(cut); - menu_edition -> addAction(copy); + menu_edition -> addAction(m_cut); + menu_edition -> addAction(m_copy); menu_edition -> addAction(paste); menu_edition -> addSeparator(); menu_edition -> addActions(m_select_actions_group.actions()); menu_edition -> addSeparator(); menu_edition -> addActions(m_selection_actions_group.actions()); menu_edition -> addSeparator(); - menu_edition -> addAction(conductor_reset); + menu_edition -> addAction(m_conductor_reset); menu_edition -> addSeparator(); menu_edition -> addAction(infos_diagram); menu_edition -> addActions(m_row_column_actions_group.actions()); @@ -1039,7 +1042,7 @@ Element *QETDiagramEditor::currentElement() const { DiagramView *dv = currentDiagram(); if (!dv) return(0); - QList selected_elements = dv -> diagram() -> selectedContent().elements.toList(); + QList selected_elements = dv -> diagram() -> selectedContent().m_elements.toList(); if (selected_elements.count() != 1) return(0); return(selected_elements.first()); @@ -1383,76 +1386,90 @@ void QETDiagramEditor::slot_updateUndoStack() * Manage the actions who need some conditions to be enable or not. * This method does nothing if there is no project opened */ -void QETDiagramEditor::slot_updateComplexActions() { +void QETDiagramEditor::slot_updateComplexActions() +{ DiagramView *dv = currentDiagram(); - bool editable_diagram = (dv && !dv -> diagram() -> isReadOnly()); + if(!dv) + { + QList action_list; + action_list << m_conductor_reset << m_find_element << m_cut << m_copy << m_delete_selection << m_rotate_selection << m_edit_selection; + for(QAction *action : action_list) + action->setEnabled(false); + + return; + } + + Diagram *diagram_ = dv->diagram(); + bool ro = diagram_->isReadOnly(); + //Number of selected conductors - int selected_conductors_count = dv ? dv -> diagram() -> selectedConductors().count() : 0; - conductor_reset -> setEnabled(editable_diagram && selected_conductors_count); + int selected_conductors_count = diagram_->selectedConductors().count(); + m_conductor_reset->setEnabled(!ro && selected_conductors_count); // number of selected elements - int selected_elements_count = dv ? dv -> diagram() -> selectedContent().count(DiagramContent::Elements) : 0; - find_element -> setEnabled(selected_elements_count == 1); + int selected_elements_count = diagram_->selectedContent().count(DiagramContent::Elements); + m_find_element->setEnabled(selected_elements_count == 1); //Action that need items (elements, conductors, texts...) selected, to be enabled - bool copiable_items = dv ? (dv -> hasCopiableItems()) : false; - bool deletable_items = dv ? (dv -> hasDeletableItems()) : false; - cut -> setEnabled(editable_diagram && copiable_items); - copy -> setEnabled(copiable_items); - delete_selection -> setEnabled(editable_diagram && deletable_items); - rotate_selection -> setEnabled(editable_diagram && dv -> diagram() -> canRotateSelection()); + bool copiable_items = dv->hasCopiableItems(); + bool deletable_items = dv->hasDeletableItems(); + m_cut -> setEnabled(!ro && copiable_items); + m_copy -> setEnabled(copiable_items); + m_delete_selection -> setEnabled(!ro && deletable_items); + m_rotate_selection -> setEnabled(!ro && diagram_->canRotateSelection()); //Action that need selected texts - int selected_texts = dv ? (dv -> diagram() -> selectedTexts().count()) : 0; - int selected_conductor_texts = dv ? (dv -> diagram() -> selectedConductorTexts().count()) : 0; - int selected_element_texts = dv ? (dv -> diagram() -> selectedElementTexts().count()) : 0; - rotate_texts -> setEnabled(editable_diagram && 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); // actions need only one editable item - int selected_image = dv ? dv -> diagram() -> selectedContent().count(DiagramContent::Images) : 0; + int selected_image = diagram_-> selectedContent().count(DiagramContent::Images); - int selected_shape = dv ? dv -> diagram() -> selectedContent().count(DiagramContent::Shapes) : 0; + int selected_shape = diagram_-> selectedContent().count(DiagramContent::Shapes); int selected_editable = selected_elements_count + - (selected_texts - selected_conductor_texts - selected_element_texts) + + (selected_texts - selected_conductor_texts - selected_element_texts - selected_dynamic_elmt_text) + selected_image + selected_shape + selected_conductors_count; if (selected_editable == 1) { - edit_selection -> setEnabled(true); + m_edit_selection -> setEnabled(true); //edit element if (selected_elements_count) { - edit_selection -> setText(tr("Éditer l'élement", "edit element")); - edit_selection -> setIcon(QET::Icons::ElementEdit); + m_edit_selection -> setText(tr("Éditer l'élement", "edit element")); + m_edit_selection -> setIcon(QET::Icons::ElementEdit); } //edit text field else if (selected_texts) { - edit_selection -> setText(tr("Éditer le champ de texte", "edit text field")); - edit_selection -> setIcon(QET::Icons::EditText); + m_edit_selection -> setText(tr("Éditer le champ de texte", "edit text field")); + m_edit_selection -> setIcon(QET::Icons::EditText); } //edit image else if (selected_image) { - edit_selection -> setText(tr("Éditer l'image", "edit image")); - edit_selection -> setIcon(QET::Icons::resize_image); + m_edit_selection -> setText(tr("Éditer l'image", "edit image")); + m_edit_selection -> setIcon(QET::Icons::resize_image); } //edit conductor else if (selected_conductors_count) { - edit_selection -> setText(tr("Éditer le conducteur", "edit conductor")); - edit_selection -> setIcon(QET::Icons::ElementEdit); + m_edit_selection -> setText(tr("Éditer le conducteur", "edit conductor")); + m_edit_selection -> setIcon(QET::Icons::ElementEdit); } } //not an editable item else { - edit_selection -> setText(tr("Éditer l'objet sélectionné", "edit selected item")); - edit_selection -> setIcon(QET::Icons::ElementEdit); - edit_selection -> setEnabled(false); + m_edit_selection -> setText(tr("Éditer l'objet sélectionné", "edit selected item")); + m_edit_selection -> setIcon(QET::Icons::ElementEdit); + m_edit_selection -> setEnabled(false); } } diff --git a/sources/qetdiagrameditor.h b/sources/qetdiagrameditor.h index 48a6285de..82dab46f7 100644 --- a/sources/qetdiagrameditor.h +++ b/sources/qetdiagrameditor.h @@ -174,9 +174,9 @@ class QETDiagramEditor : public QETMainWindow { QAction *redo; ///< Redo the latest cancelled operation public: QAction *infos_diagram; ///< Show a dialog to edit diagram properties - QAction *conductor_reset; ///< Reset paths of selected conductors - QAction *cut; ///< Cut selection to clipboard - QAction *copy; ///< Copy selection to clipboard + QAction *m_conductor_reset; ///< Reset paths of selected conductors + QAction *m_cut; ///< Cut selection to clipboard + QAction *m_copy; ///< Copy selection to clipboard private: QAction *paste; ///< Paste clipboard content on the current diagram QAction *m_auto_conductor; ///< Enable/Disable the use of auto conductor @@ -194,7 +194,7 @@ class QETDiagramEditor : public QETMainWindow { QAction *cascade_window; ///< Show MDI subwindows as cascade QAction *prev_window; ///< Switch to the previous document QAction *next_window; ///< Switch to the next document - QAction *edit_selection; ///< To edit selected item + QAction *m_edit_selection; ///< To edit selected item QActionGroup m_add_item_actions_group; ///Action related to adding (add text image shape...) @@ -207,10 +207,10 @@ class QETDiagramEditor : public QETMainWindow { QActionGroup m_row_column_actions_group; /// Action related to add/remove rows/column in diagram QActionGroup m_selection_actions_group; ///Action related to edit a selected item private: - QAction *delete_selection; ///< Delete selection - QAction *rotate_selection; ///< Rotate selected elements and text items by 90 degrees - QAction *rotate_texts; ///< Direct selected text items to a specific angle - QAction *find_element; ///< Find the selected element in the panel + QAction *m_delete_selection; ///< Delete selection + QAction *m_rotate_selection; ///< Rotate selected elements and text items by 90 degrees + QAction *m_rotate_texts; ///< Direct selected text items to a specific angle + QAction *m_find_element; ///< Find the selected element in the panel QActionGroup m_file_actions_group; ///Actions related to file (open, close, save...) QAction *close_file; ///< Close current project file diff --git a/sources/qetgraphicsitem/diagramtextitem.cpp b/sources/qetgraphicsitem/diagramtextitem.cpp index 19e13925f..ab97207d2 100644 --- a/sources/qetgraphicsitem/diagramtextitem.cpp +++ b/sources/qetgraphicsitem/diagramtextitem.cpp @@ -27,10 +27,7 @@ */ DiagramTextItem::DiagramTextItem(QGraphicsItem *parent) : QGraphicsTextItem(parent), - m_mouse_hover(false), - previous_text_(), - rotation_angle_(0.0), - m_first_move (true) + m_rotation_angle(0.0) { build(); } /** @@ -41,8 +38,8 @@ DiagramTextItem::DiagramTextItem(QGraphicsItem *parent) : DiagramTextItem::DiagramTextItem(const QString &text, QGraphicsItem *parent) : QGraphicsTextItem(text, parent), m_mouse_hover(false), - previous_text_(text), - rotation_angle_(0.0) + m_previous_html_text(text), + m_rotation_angle(0.0) { build(); } /** @@ -83,7 +80,7 @@ QDomElement DiagramTextItem::toXml(QDomDocument &) const { @return l'angle de rotation actuel de ce texte */ qreal DiagramTextItem::rotationAngle() const { - return(rotation_angle_); + return(m_rotation_angle); } /** @@ -94,8 +91,8 @@ qreal DiagramTextItem::rotationAngle() const { */ void DiagramTextItem::setRotationAngle(const qreal &rotation) { qreal applied_rotation = QET::correctAngle(rotation); - applyRotation(applied_rotation - rotation_angle_); - rotation_angle_ = applied_rotation; + applyRotation(applied_rotation - m_rotation_angle); + m_rotation_angle = applied_rotation; } /** @@ -106,7 +103,7 @@ void DiagramTextItem::setRotationAngle(const qreal &rotation) { */ void DiagramTextItem::rotateBy(const qreal &added_rotation) { qreal applied_added_rotation = QET::correctAngle(added_rotation); - rotation_angle_ = QET::correctAngle(rotation_angle_ + applied_added_rotation); + m_rotation_angle = QET::correctAngle(m_rotation_angle + applied_added_rotation); applyRotation(applied_added_rotation); } @@ -186,8 +183,25 @@ QPointF DiagramTextItem::mapMovementFromParent(const QPointF &movement) const { return(local_movement_point - local_origin); } -void DiagramTextItem::setFontSize(int &s) { - setFont(QETApp::diagramTextsFont(s)); +void DiagramTextItem::setFontSize(int s) +{ + setFont(QETApp::diagramTextsFont(s)); + emit fontSizeChanged(s); +} + +int DiagramTextItem::fontSize() const +{ + return font().pointSize(); +} + +void DiagramTextItem::setColor(QColor color) +{ + setDefaultTextColor(color); + emit colorChanged(color); +} + +QColor DiagramTextItem::color() const { + return defaultTextColor(); } /** @@ -226,42 +240,39 @@ void DiagramTextItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *o } /** - Gere la prise de focus du champ de texte - @param e Objet decrivant la prise de focus -*/ -void DiagramTextItem::focusInEvent(QFocusEvent *e) { - QGraphicsTextItem::focusInEvent(e); - - // empeche le deplacement du texte pendant son edition + * @brief DiagramTextItem::focusInEvent + * @param e + */ +void DiagramTextItem::focusInEvent(QFocusEvent *event) +{ + QGraphicsTextItem::focusInEvent(event); + setFlag(QGraphicsItem::ItemIsMovable, false); - // memorise le texte avant que l'utilisateur n'y touche - previous_text_ = toHtml(); - // cela permettra de determiner si l'utilisateur a modifie le texte a la fin de l'edition + m_previous_html_text = toHtml(); + m_previous_text = toPlainText(); } /** - Gere la perte de focus du champ de texte - @param e Objet decrivant la perte de focus -*/ -void DiagramTextItem::focusOutEvent(QFocusEvent *e) { - QGraphicsTextItem::focusOutEvent(e); + * @brief DiagramTextItem::focusOutEvent + * @param event + */ +void DiagramTextItem::focusOutEvent(QFocusEvent *event) +{ + QGraphicsTextItem::focusOutEvent(event); + + if (toHtml() != m_previous_html_text) + emit(diagramTextChanged(this, m_previous_html_text, toHtml())); + if(toPlainText() != m_previous_text) + emit textEdited(m_previous_text, toPlainText()); - // signale la modification du texte si besoin - if (toPlainText() != previous_text_) { - emit(diagramTextChanged(this, previous_text_, toHtml())); - previous_text_ = toHtml(); - } - - // deselectionne le texte QTextCursor cursor = textCursor(); cursor.clearSelection(); setTextCursor(cursor); - - // hack a la con pour etre re-entrant + + //Bad hack to be re-entrant setTextInteractionFlags(Qt::NoTextInteraction); - - // autorise de nouveau le deplacement du texte + setFlag(QGraphicsItem::ItemIsMovable, true); setFlag(QGraphicsTextItem::ItemIsFocusable, false); } @@ -271,7 +282,7 @@ void DiagramTextItem::focusOutEvent(QFocusEvent *e) { @param event un QGraphicsSceneMouseEvent decrivant le double-clic */ void DiagramTextItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) { - if (!(textInteractionFlags() & Qt::TextEditable) && !no_editable) { + if (!(textInteractionFlags() & Qt::TextEditable) && !m_no_editable) { // rend le champ de texte editable setTextInteractionFlags(Qt::TextEditorInteraction); diff --git a/sources/qetgraphicsitem/diagramtextitem.h b/sources/qetgraphicsitem/diagramtextitem.h index 89c5ec57f..83ff3983b 100644 --- a/sources/qetgraphicsitem/diagramtextitem.h +++ b/sources/qetgraphicsitem/diagramtextitem.h @@ -32,6 +32,13 @@ class QDomDocument; class DiagramTextItem : public QGraphicsTextItem { Q_OBJECT + + Q_PROPERTY(int fontSize READ fontSize WRITE setFontSize NOTIFY fontSizeChanged) + Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged) + + signals: + void fontSizeChanged(int size); + void colorChanged(QColor color); public: DiagramTextItem(QGraphicsItem * = 0); @@ -42,7 +49,7 @@ class DiagramTextItem : public QGraphicsTextItem public: enum { Type = UserType + 1004 }; - virtual int type() const { return Type; } + virtual int type() const override { return Type; } Diagram *diagram() const; virtual void fromXml(const QDomElement &) = 0; @@ -57,35 +64,43 @@ class DiagramTextItem : public QGraphicsTextItem QPointF mapMovementToParent (const QPointF &) const; QPointF mapMovementFromParent (const QPointF &) const; - void setFontSize(int &s); - void setNoEditable(bool e = true) {no_editable = e;} + void setFontSize(int s); + int fontSize()const; + + void setColor(QColor color); + QColor color() const; + + void setNoEditable(bool e = true) {m_no_editable = e;} protected: - virtual void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *); - virtual void focusInEvent(QFocusEvent *); - virtual void focusOutEvent(QFocusEvent *); + virtual void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *) override; + virtual void focusInEvent(QFocusEvent *) override; + virtual void focusOutEvent(QFocusEvent *) override; - virtual void mouseDoubleClickEvent (QGraphicsSceneMouseEvent *event); - virtual void mousePressEvent (QGraphicsSceneMouseEvent *event); - virtual void mouseMoveEvent (QGraphicsSceneMouseEvent *event); - virtual void mouseReleaseEvent (QGraphicsSceneMouseEvent *event); + virtual void mouseDoubleClickEvent (QGraphicsSceneMouseEvent *event) override; + virtual void mousePressEvent (QGraphicsSceneMouseEvent *event) override; + virtual void mouseMoveEvent (QGraphicsSceneMouseEvent *event) override; + virtual void mouseReleaseEvent (QGraphicsSceneMouseEvent *event) override; - virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *); - virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent *); - virtual void hoverMoveEvent(QGraphicsSceneHoverEvent *); + virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *) override; + virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent *) override; + virtual void hoverMoveEvent(QGraphicsSceneHoverEvent *) override; virtual void applyRotation(const qreal &); signals: - /// signal emitted after text was changed void diagramTextChanged(DiagramTextItem *, const QString &, const QString &); + void textEdited(const QString &old_str, const QString &new_str); protected: - bool m_mouse_hover; - QString previous_text_; - qreal rotation_angle_; - bool no_editable; - bool m_first_move; + bool m_mouse_hover = false, + m_first_move = true, + m_no_editable; + + QString m_previous_html_text, + m_previous_text; + + qreal m_rotation_angle; QPointF m_mouse_to_origin_movement; }; #endif diff --git a/sources/qetgraphicsitem/dynamicelementtextitem.cpp b/sources/qetgraphicsitem/dynamicelementtextitem.cpp new file mode 100644 index 000000000..84b2a9169 --- /dev/null +++ b/sources/qetgraphicsitem/dynamicelementtextitem.cpp @@ -0,0 +1,255 @@ +/* + 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 "dynamicelementtextitem.h" +#include "qet.h" +#include "element.h" +#include "qetapp.h" +#include "diagram.h" +#include "QPropertyUndoCommand/qpropertyundocommand.h" + +#include +#include +#include + +/** + * @brief DynamicElementTextItem::DynamicElementTextItem + * Constructor + * @param parent_element + */ +DynamicElementTextItem::DynamicElementTextItem(Element *parent_element) : + m_parent_element(parent_element), + m_uuid(QUuid::createUuid()) +{ + setFont(QETApp::diagramTextsFont(9)); + setText(tr("Texte")); + setParentItem(parent_element); + + connect(this, &DynamicElementTextItem::textEdited, [this](const QString &old_str, const QString &new_str) + { + if(this->m_parent_element && this->m_parent_element->diagram()) + { + QUndoCommand *undo = new QPropertyUndoCommand(this, "text", old_str, new_str); + undo->setText(tr("Éditer un texte d'élément")); + this->m_parent_element->diagram()->undoStack().push(undo); + } + + }); +} + +DynamicElementTextItem::~DynamicElementTextItem() +{} + +/** + * @brief DynamicElementTextItem::toXml + * Export this text to xml + * @param dom_doc + * @return + */ +QDomElement DynamicElementTextItem::toXml(QDomDocument &dom_doc) const +{ + QDomElement root_element = dom_doc.createElement(xmlTaggName()); + + root_element.setAttribute("x", QString::number(pos().x())); + root_element.setAttribute("y", QString::number(pos().y())); + root_element.setAttribute("rotation", QString::number(QET::correctAngle(rotation()))); + root_element.setAttribute("font_size", font().pointSize()); + root_element.setAttribute("uuid", m_uuid.toString()); + + QMetaEnum me = metaObject()->enumerator(metaObject()->indexOfEnumerator("TextFrom")); + root_element.setAttribute("text_from", me.valueToKey(m_text_from)); + + QDomElement dom_text = dom_doc.createElement("text"); + dom_text.appendChild(dom_doc.createTextNode(toPlainText())); + root_element.appendChild(dom_text); + + //tagg + if (!m_tagg.isEmpty()) + { + QDomElement dom_tagg = dom_doc.createElement("tagg"); + dom_tagg.appendChild(dom_doc.createTextNode(m_tagg)); + root_element.appendChild(dom_tagg); + } + + //Color + if(color() != QColor(Qt::black)) + { + QDomElement dom_color = dom_doc.createElement("color"); + dom_color.appendChild(dom_doc.createTextNode(color().name())); + root_element.appendChild(dom_color); + } + + return root_element; +} + +/** + * @brief DynamicElementTextItem::fromXml + * Import this text from xml + * @param dom_elmt + */ +void DynamicElementTextItem::fromXml(const QDomElement &dom_elmt) +{ + if (dom_elmt.tagName() != xmlTaggName()) { + qDebug() << "DynamicElementTextItem::fromXml : Wrong tagg name"; + return; + } + + QGraphicsTextItem::setPos(dom_elmt.attribute("x", QString::number(0)).toDouble(), + dom_elmt.attribute("y", QString::number(0)).toDouble()); + QGraphicsTextItem::setRotation(dom_elmt.attribute("rotation", QString::number(0)).toDouble()); + setFont(QETApp::diagramTextsFont(dom_elmt.attribute("font_size", QString::number(9)).toInt())); + m_uuid = QUuid(dom_elmt.attribute("uuid", QUuid::createUuid().toString())); + + QMetaEnum me = metaObject()->enumerator(metaObject()->indexOfEnumerator("TextFrom")); + m_text_from = DynamicElementTextItem::TextFrom(me.keyToValue(dom_elmt.attribute("text_from").toStdString().data())); + setNoEditable(m_text_from == ElementInfo? true : false); + + //Text + QDomElement dom_text = dom_elmt.firstChildElement("text"); + if (!dom_text.isNull()) + setPlainText(dom_text.text()); + + //tagg + QDomElement dom_tagg = dom_elmt.firstChildElement("tagg"); + if (!dom_tagg.isNull()) + m_tagg = dom_tagg.text(); + + //Color + QDomElement dom_color = dom_elmt.firstChildElement("color"); + if(!dom_color.isNull()) + setColor(QColor(dom_color.text())); +} + +/** + * @brief DynamicElementTextItem::ParentElement + * @return a pointer to the parent element. Note the pointer can be null. + */ +Element *DynamicElementTextItem::ParentElement() const { + return m_parent_element; +} + +/** + * @brief DynamicElementTextItem::textFrom + * @return what the final text is created from. + */ +DynamicElementTextItem::TextFrom DynamicElementTextItem::textFrom() const { + return m_text_from; +} + +/** + * @brief DynamicElementTextItem::setTextFrom + * Set the final text is created from. + * @param text_from + */ +void DynamicElementTextItem::setTextFrom(DynamicElementTextItem::TextFrom text_from) +{ + m_text_from = text_from; + setNoEditable(m_text_from == ElementInfo? true : false); + emit TextFromChanged(m_text_from); +} + +/** + * @brief DynamicElementTextItem::tagg + * @return the tagg of this text + */ +QString DynamicElementTextItem::tagg() const { + return m_tagg; +} + +/** + * @brief DynamicElementTextItem::setTagg + * set the taggof this text + * @param tagg + */ +void DynamicElementTextItem::setTagg(const QString &tagg) +{ + m_tagg = tagg; + emit taggChanged(m_tagg); +} + +/** + * @brief DynamicElementTextItem::text + * @return the text of this text + */ +QString DynamicElementTextItem::text() const { + return m_text; +} + +/** + * @brief DynamicElementTextItem::setText + * Set the text of this text + * @param formula + */ +void DynamicElementTextItem::setText(const QString &text) +{ + m_text = text; + setPlainText(m_text); + emit textChanged(m_text); +} + +/** + * @brief DynamicElementTextItem::mouseMoveEvent + * @param event + */ +void DynamicElementTextItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) +{ + if(event->buttons() & Qt::LeftButton) + { + QPointF old_pos = pos(); //The old pos + QPointF movement = event->pos() - event->buttonDownPos(Qt::LeftButton); //The movement since the button down pos + QPointF new_pos = pos() + mapMovementToParent(movement); //The new pos with this event + event->modifiers() == Qt::ControlModifier ? setPos(new_pos) : setPos(Diagram::snapToGrid(new_pos)); + + if(m_parent_element && m_parent_element->diagram()) + { + Diagram *diagram = m_parent_element->diagram(); + + if(m_first_move) + { + if(diagram->beginMoveElementTexts(this) == 1) + m_parent_element->setHighlighted(true); + } + + //Because setPos() can be snaped to grid or not, we calcule the real movement + QPointF effective_movement = pos() - old_pos; + QPointF scene_effective_movement = mapMovementToScene(mapMovementFromParent(effective_movement)); + diagram->continueMoveElementTexts(scene_effective_movement); + } + } + else + event->ignore(); + + if(m_first_move) + m_first_move = false; +} + +/** + * @brief DynamicElementTextItem::mouseReleaseEvent + * @param event + */ +void DynamicElementTextItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) +{ + if (m_parent_element) + m_parent_element->setHighlighted(false); + + if(m_parent_element && m_parent_element->diagram()) + m_parent_element->diagram()->endMoveElementTexts(); + + if(!(event->modifiers() & Qt::ControlModifier)) + QGraphicsTextItem::mouseReleaseEvent(event); +} + diff --git a/sources/qetgraphicsitem/dynamicelementtextitem.h b/sources/qetgraphicsitem/dynamicelementtextitem.h new file mode 100644 index 000000000..567a7158e --- /dev/null +++ b/sources/qetgraphicsitem/dynamicelementtextitem.h @@ -0,0 +1,87 @@ +/* + 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 DYNAMICELEMENTTEXTITEM_H +#define DYNAMICELEMENTTEXTITEM_H + +#include "diagramtextitem.h" +#include + +class Element; + +/** + * @brief The DynamicElementTextItem class + * This class provide a simple text field of element who can be added or removed directly from the diagram editor. + * This text is created to compensate a big lack of the ElementTextItem : ElementTextItem can't be added or removed directly in the diagram editor + * + */ +class DynamicElementTextItem : public DiagramTextItem +{ + Q_OBJECT + + Q_PROPERTY(QString tagg READ tagg WRITE setTagg NOTIFY taggChanged) + Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged) + Q_PROPERTY(TextFrom textFrom READ textFrom WRITE setTextFrom NOTIFY TextFromChanged) + + public: + Q_ENUMS(TextFrom) + enum TextFrom { + UserText, + ElementInfo + }; + enum {Type = UserType + 1010}; + virtual int type() const override {return Type;} + + signals: + void taggChanged(QString tagg); + void textChanged(QString text); + void TextFromChanged(DynamicElementTextItem::TextFrom text_from); + + public: + DynamicElementTextItem(Element *parent_element); + virtual ~DynamicElementTextItem() override; + private: + DynamicElementTextItem(const DynamicElementTextItem &); + + public: + virtual QDomElement toXml(QDomDocument &dom_doc) const override; + virtual void fromXml(const QDomElement &dom_elmt) override; + + Element *ParentElement() const; + + DynamicElementTextItem::TextFrom textFrom() const; + void setTextFrom (DynamicElementTextItem::TextFrom text_from); + QString tagg() const; + void setTagg(const QString &tagg); + QString text() const; + void setText(const QString &text); + static QString xmlTaggName() {return QString("dynamic_elmt_text");} + + protected: + virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override; + virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override; + + private: + Element *m_parent_element = nullptr; + QString m_tagg, + m_text, + m_elmt_info_name; + DynamicElementTextItem::TextFrom m_text_from = UserText; + QUuid m_uuid; +}; + +#endif // DYNAMICELEMENTTEXTITEM_H diff --git a/sources/qetgraphicsitem/element.cpp b/sources/qetgraphicsitem/element.cpp index 6d6ecd4bc..743709d59 100644 --- a/sources/qetgraphicsitem/element.cpp +++ b/sources/qetgraphicsitem/element.cpp @@ -29,6 +29,7 @@ #include "numerotationcontextcommands.h" #include "diagramcontext.h" #include "changeelementinformationcommand.h" +#include "dynamicelementtextitem.h" class ElementXmlRetroCompatibility { @@ -77,7 +78,9 @@ Element::Element(QGraphicsItem *parent) : /** Destructeur */ -Element::~Element() { +Element::~Element() +{ + qDeleteAll(m_dynamic_text_list); } void Element::editProperty() @@ -529,6 +532,15 @@ bool Element::fromXml(QDomElement &e, QHash &table_id_adr, bool } else { applyRotation(90*read_ori); } + + //Dynamic texts + for (QDomElement qde : QET::findInDomElement(e, "dynamic_texts", DynamicElementTextItem::xmlTaggName())) + { + DynamicElementTextItem *deti = new DynamicElementTextItem(this); + addDynamicTextItem(deti); + deti->fromXml(qde); + } + return(true); } @@ -608,14 +620,59 @@ QDomElement Element::toXml(QDomDocument &document, QHash &table element.appendChild(links_uuids); } - //save information of this element + //save information of this element if (! m_element_informations.keys().isEmpty()) { QDomElement infos = document.createElement("elementInformations"); m_element_informations.toXml(infos, "elementInformation"); element.appendChild(infos); } + + //Dynamic texts + QDomElement dyn_text = document.createElement("dynamic_texts"); + for (DynamicElementTextItem *deti : m_dynamic_text_list) + dyn_text.appendChild(deti->toXml(document)); + element.appendChild(dyn_text); - return(element); + return(element); +} + +/** + * @brief Element::addDynamiqueTextItem + * Add @deti as a dynamic text item of this element + * If @deti is null, a new DynamicElementTextItem is created and added to this element. + * @param deti + */ +void Element::addDynamicTextItem(DynamicElementTextItem *deti) +{ + if (deti && !m_dynamic_text_list.contains(deti)) + { + m_dynamic_text_list.append(deti); + } + else + { + DynamicElementTextItem *text = new DynamicElementTextItem(this); + m_dynamic_text_list.append(text); + } +} + +/** + * @brief Element::removeDynamicTextItem + * Remove @deti as dynamic text item of this element. + * The parent item of deti stay this item. + * @param deti + */ +void Element::removeDynamicTextItem(DynamicElementTextItem *deti) +{ + if (m_dynamic_text_list.contains(deti)) + m_dynamic_text_list.removeOne(deti); +} + +/** + * @brief Element::dynamicTextItems + * @return all dynamic text items of this element + */ +QList Element::dynamicTextItems() const { + return m_dynamic_text_list; } /** diff --git a/sources/qetgraphicsitem/element.h b/sources/qetgraphicsitem/element.h index 910ec34dd..81d501ad1 100644 --- a/sources/qetgraphicsitem/element.h +++ b/sources/qetgraphicsitem/element.h @@ -30,6 +30,7 @@ class Terminal; class Conductor; class NumerotationContext; class DiagramTextItem; +class DynamicElementTextItem; /** This is the base class for electrical elements. @@ -158,9 +159,6 @@ class Element : public QetGraphicsItem bool m_freeze_label = false; QString m_F_str; - /** - Draw this element - */ public: virtual void paint(QPainter *, const QStyleOptionGraphicsItem *) = 0; /// @return This element type ID @@ -177,25 +175,29 @@ class Element : public QetGraphicsItem QSize size() const; QPixmap pixmap(); - // methods related to the hotspot - QPoint setHotspot(QPoint); - QPoint hotspot() const; - - // selection-related methods - void select(); - void deselect(); - - virtual void rotateBy(const qreal &); - virtual void editProperty(); - - // methods related to XML import/export - static bool valideXml(QDomElement &); - virtual bool fromXml(QDomElement &, QHash &, bool = false); - virtual QDomElement toXml(QDomDocument &, QHash &) const; - QUuid uuid() const; - - // orientation-related methods - int orientation() const; + // methods related to the hotspot + QPoint setHotspot(QPoint); + QPoint hotspot() const; + + // selection-related methods + void select(); + void deselect(); + + virtual void rotateBy(const qreal &); + virtual void editProperty(); + + // methods related to XML import/export + static bool valideXml(QDomElement &); + virtual bool fromXml(QDomElement &, QHash &, bool = false); + virtual QDomElement toXml(QDomDocument &, QHash &) const; + QUuid uuid() const; + + // orientation-related methods + int orientation() const; + + void addDynamicTextItem(DynamicElementTextItem *deti = nullptr); + void removeDynamicTextItem(DynamicElementTextItem *deti); + QList dynamicTextItems() const; protected: void drawAxes(QPainter *, const QStyleOptionGraphicsItem *); @@ -216,6 +218,7 @@ class Element : public QetGraphicsItem private: bool m_mouse_over; QString m_prefix; + QList m_dynamic_text_list; }; diff --git a/sources/ui/diagrampropertieseditordockwidget.cpp b/sources/ui/diagrampropertieseditordockwidget.cpp index c37ed407c..35c58c9ce 100644 --- a/sources/ui/diagrampropertieseditordockwidget.cpp +++ b/sources/ui/diagrampropertieseditordockwidget.cpp @@ -23,6 +23,7 @@ #include "imagepropertieswidget.h" #include "qetshapeitem.h" #include "shapegraphicsitempropertieswidget.h" +#include "dynamicelementtextitem.h" /** * @brief DiagramPropertiesEditorDockWidget::DiagramPropertiesEditorDockWidget @@ -56,7 +57,7 @@ void DiagramPropertiesEditorDockWidget::setDiagram(Diagram *diagram) if (diagram) { m_diagram = diagram; - connect(m_diagram, SIGNAL(selectionChanged()), this, SLOT(selectionChanged())); + connect(m_diagram, SIGNAL(selectionChanged()), this, SLOT(selectionChanged()), Qt::QueuedConnection); connect(m_diagram, SIGNAL(destroyed()), this, SLOT(diagramWasDeleted())); selectionChanged(); } @@ -119,6 +120,22 @@ void DiagramPropertiesEditorDockWidget::selectionChanged() m_edited_qgi_type = type_; addEditor(new ShapeGraphicsItemPropertiesWidget(static_cast(item), this)); break; } + + case DynamicElementTextItem::Type: { + DynamicElementTextItem *deti = static_cast(item); + + //For dynamic element text, we open the element editor + //We already edit an element, just update the editor with a new element + if (m_edited_qgi_type == Element::Type) + { + static_cast(editors().first())->setElement(deti->ParentElement()); + return; + } + + clear(); + m_edited_qgi_type = Element::Type; + addEditor(new ElementPropertiesWidget(deti->ParentElement(), this)); + break; } default: m_edited_qgi_type = -1; diff --git a/sources/ui/dynamicelementtextitemeditor.cpp b/sources/ui/dynamicelementtextitemeditor.cpp new file mode 100644 index 000000000..440640ae6 --- /dev/null +++ b/sources/ui/dynamicelementtextitemeditor.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 "dynamicelementtextitemeditor.h" +#include "ui_dynamicelementtextitemeditor.h" +#include "dynamicelementtextitem.h" +#include "element.h" +#include "dynamicelementtextmodel.h" +#include "diagram.h" +#include "undocommand/deleteqgraphicsitemcommand.h" +#include "undocommand/addelementtextcommand.h" + +#include +#include + +DynamicElementTextItemEditor::DynamicElementTextItemEditor(Element *element, QWidget *parent) : + AbstractElementPropertiesEditorWidget(parent), + ui(new Ui::DynamicElementTextItemEditor) +{ + ui->setupUi(this); + m_tree_view = new QTreeView(this); + m_tree_view->header()->setDefaultSectionSize(150); + m_tree_view->setItemDelegate(new DynamicTextItemDelegate(m_tree_view)); + m_tree_view->setAlternatingRowColors(true); + ui->verticalLayout->addWidget(m_tree_view); + setElement(element); +} + +DynamicElementTextItemEditor::~DynamicElementTextItemEditor() +{ + delete ui; +} + +void DynamicElementTextItemEditor::setElement(Element *element) +{ + if (m_element == element) + return; + + m_element = element; + + DynamicElementTextModel *old_model = m_model; + m_model = new DynamicElementTextModel(m_tree_view); + connect(m_model, &DynamicElementTextModel::itemChanged, this, &DynamicElementTextItemEditor::dataEdited); + + for (DynamicElementTextItem *deti : m_element->dynamicTextItems()) + m_model->addText(deti); + + m_tree_view->setModel(m_model); + + if(old_model) + delete old_model; +} + +bool DynamicElementTextItemEditor::setLiveEdit(bool live_edit) +{ + m_live_edit = live_edit; + return true; +} + +void DynamicElementTextItemEditor::apply() +{ + QList undo_list; + for (DynamicElementTextItem *deti : m_element->dynamicTextItems()) + { + QUndoCommand *undo = m_model->undoForEditedText(deti); + if(undo->childCount()) + undo_list << undo; + else + delete undo; + } + + for (DynamicElementTextItem *deti : m_element->dynamicTextItems()) + deti->blockSignals(true); + + if(!undo_list.isEmpty() && m_element->diagram()) + { + if (undo_list.size() == 1) + m_element->diagram()->undoStack().push(undo_list.first()); + else + { + QUndoStack &us = m_element->diagram()->undoStack(); + us.beginMacro(tr("Modifier des texte d'élément")); + for (QUndoCommand *quc : undo_list) + us.push(quc); + us.endMacro(); + } + } + + for (DynamicElementTextItem *deti : m_element->dynamicTextItems()) + deti->blockSignals(false); +} + +void DynamicElementTextItemEditor::dataEdited(QStandardItem *qsi) +{ + Q_UNUSED(qsi) + if (m_live_edit) + apply(); +} + +/** + * @brief DynamicElementTextItemEditor::on_m_add_text_clicked + * Add a new dynamic text + */ +void DynamicElementTextItemEditor::on_m_add_text_clicked() +{ + if (!m_element) + return; + + DynamicElementTextItem *deti = new DynamicElementTextItem(m_element); + if (m_element->diagram()) + { + m_element->diagram()->undoStack().push(new AddElementTextCommand(m_element, deti)); + m_model->addText(deti); + } + else + { + delete deti; + } +} + +/** + * @brief DynamicElementTextItemEditor::on_m_remove_text_clicked + * Remove the selected text field + */ +void DynamicElementTextItemEditor::on_m_remove_text_clicked() +{ + DynamicElementTextItem *deti = m_model->textFromIndex(m_tree_view->currentIndex()); + if(deti) + { + if(m_element->diagram()) + { + DiagramContent dc; + dc.m_element_texts << deti; + m_element->diagram()->undoStack().push(new DeleteQGraphicsItemCommand(m_element->diagram(), dc)); + m_model->removeText(deti); + } + } +} diff --git a/sources/ui/dynamicelementtextitemeditor.h b/sources/ui/dynamicelementtextitemeditor.h new file mode 100644 index 000000000..a2a3bf4f2 --- /dev/null +++ b/sources/ui/dynamicelementtextitemeditor.h @@ -0,0 +1,59 @@ +/* + 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 DYNAMICELEMENTTEXTITEMEDITOR_H +#define DYNAMICELEMENTTEXTITEMEDITOR_H + +#include "abstractelementpropertieseditorwidget.h" + +class DynamicElementTextItem; +class DynamicElementTextModel; +class QTreeView; +class QStandardItem; + +namespace Ui { + class DynamicElementTextItemEditor; +} + +class DynamicElementTextItemEditor : public AbstractElementPropertiesEditorWidget +{ + Q_OBJECT + + public: + explicit DynamicElementTextItemEditor(Element *element, QWidget *parent = 0); + ~DynamicElementTextItemEditor(); + + virtual void setElement(Element *element); + virtual QString title() const {return tr("Textes");} + virtual bool setLiveEdit(bool live_edit); + virtual void apply(); + + private: + void dataEdited(QStandardItem *qsi); + + private slots: + void on_m_add_text_clicked(); + void on_m_remove_text_clicked(); + + private: + Ui::DynamicElementTextItemEditor *ui; + QTreeView *m_tree_view = nullptr; + DynamicElementTextModel *m_model = nullptr; + +}; + +#endif // DYNAMICELEMENTTEXTITEMEDITOR_H diff --git a/sources/ui/dynamicelementtextitemeditor.ui b/sources/ui/dynamicelementtextitemeditor.ui new file mode 100644 index 000000000..303071ca8 --- /dev/null +++ b/sources/ui/dynamicelementtextitemeditor.ui @@ -0,0 +1,62 @@ + + + DynamicElementTextItemEditor + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + :/ico/16x16/list-add.png:/ico/16x16/list-add.png + + + + + + + + + + + :/ico/16x16/list-remove.png:/ico/16x16/list-remove.png + + + + + + + + + + + + diff --git a/sources/ui/dynamicelementtextmodel.cpp b/sources/ui/dynamicelementtextmodel.cpp new file mode 100644 index 000000000..b26f27698 --- /dev/null +++ b/sources/ui/dynamicelementtextmodel.cpp @@ -0,0 +1,407 @@ +/* + 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 "dynamicelementtextmodel.h" +#include "dynamicelementtextitem.h" +#include +#include +#include +#include +#include +#include +#include "QPropertyUndoCommand/qpropertyundocommand.h" + +DynamicElementTextModel::DynamicElementTextModel(QObject *parent) : +QStandardItemModel(parent) +{ + setColumnCount(2); + setHeaderData(0, Qt::Horizontal, tr("Propriété"), Qt::DisplayRole); + setHeaderData(1, Qt::Horizontal, tr("Valeur"), Qt::DisplayRole); + + connect(this, &DynamicElementTextModel::itemChanged, this, &DynamicElementTextModel::dataEdited); +} + +DynamicElementTextModel::~DynamicElementTextModel() +{ + //Connection is not destroy automaticaly, + //because was not connected to a slot, but a lambda + for(DynamicElementTextItem *deti : m_hash_text_connect.keys()) + setConnection(deti, false); +} + +/** + * @brief DynamicElementTextModel::addText + * @param deti + */ +void DynamicElementTextModel::addText(DynamicElementTextItem *deti) +{ + if(m_texts_list.keys().contains(deti)) + return; + + QList qsi_list; + + QStandardItem *qsi = new QStandardItem(deti->toPlainText()); + qsi->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + + + //Source of text + QStandardItem *src = new QStandardItem(tr("Source du texte")); + src->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + + QStandardItem *srca = new QStandardItem(deti->textFrom() == DynamicElementTextItem::UserText ? tr("Texte utilisateur") : tr("Information de l'élément")); + srca->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable); + srca->setData(textFrom, Qt::UserRole+1); + + qsi_list << src << srca; + qsi->appendRow(qsi_list); + + //User text + QStandardItem *usr = new QStandardItem(tr("Texte")); + usr->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + + QStandardItem *usra = new QStandardItem(deti->toPlainText()); + usra->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable); + usra->setData(DynamicElementTextModel::userText, Qt::UserRole+1); + + qsi_list.clear(); + qsi_list << usr << usra; + src->appendRow(qsi_list); + + //Info text + QStandardItem *info = new QStandardItem(tr("Information")); + info->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + + QStandardItem *infoa = new QStandardItem(deti->toPlainText()); + infoa->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable); + infoa->setData(DynamicElementTextModel::infoText, Qt::UserRole+1); + + qsi_list.clear(); + qsi_list << info << infoa; + src->appendRow(qsi_list); + + + //Size + QStandardItem *size = new QStandardItem(tr("Taille")); + size->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + + QStandardItem *siza = new QStandardItem(); + siza->setData(deti->fontSize(), Qt::EditRole); + siza->setData(DynamicElementTextModel::size, Qt::UserRole+1); + siza->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable); + + qsi_list.clear(); + qsi_list << size << siza; + qsi->appendRow(qsi_list); + + //Tagg + QStandardItem *tagg = new QStandardItem(tr("Tagg")); + tagg->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + + QStandardItem *tagga = new QStandardItem(deti->tagg()); + tagga->setData(DynamicElementTextModel::tagg, Qt::UserRole+1); + tagga->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable); + + qsi_list.clear(); + qsi_list << tagg << tagga; + qsi->appendRow(qsi_list); + + //Color + QStandardItem *color = new QStandardItem(tr("Couleur")); + color->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + + QStandardItem *colora = new QStandardItem; + colora->setData(deti->color(), Qt::ForegroundRole); + colora->setData(deti->color(), Qt::EditRole); + colora->setData(DynamicElementTextModel::color, Qt::UserRole+1); + colora->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable); + + qsi_list.clear(); + qsi_list << color << colora; + qsi->appendRow(qsi_list); + + qsi_list.clear(); + QStandardItem *empty_qsi = new QStandardItem(0); + empty_qsi->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + qsi_list << qsi << empty_qsi; + this->appendRow(qsi_list); + + m_texts_list.insert(deti, qsi); + blockSignals(true); + enableSourceText(deti, deti->textFrom()); + blockSignals(false); + setConnection(deti, true); +} + +/** + * @brief DynamicElementTextModel::removeText + * @param deti + */ +void DynamicElementTextModel::removeText(DynamicElementTextItem *deti) +{ + if (!m_texts_list.contains(deti)) + return; + + QModelIndex text_index = m_texts_list.value(deti)->index(); + this->removeRow(text_index.row(), text_index.parent()); + m_texts_list.remove(deti); + setConnection(deti, false); +} + +/** + * @brief DynamicElementTextModel::textFromIndex + * @param index + * @return the text associated with @index. Return value can be nullptr + * @Index can be a child of an index associated with a text + */ +DynamicElementTextItem *DynamicElementTextModel::textFromIndex(const QModelIndex &index) const +{ + if(!index.isValid()) + return nullptr; + + if (QStandardItem *item = itemFromIndex(index)) + return textFromItem(item); + else + return nullptr; +} + +/** + * @brief DynamicElementTextModel::textFromItem + * @param item + * @return the text associated with @item. Return value can be nullptr + * @item can be a child of an item associated with a text + */ +DynamicElementTextItem *DynamicElementTextModel::textFromItem(QStandardItem *item) const +{ + QStandardItem *text_item = item; + while (text_item->parent()) + text_item = text_item->parent(); + + if (m_texts_list.values().contains(text_item)) + return m_texts_list.key(text_item); + else + return nullptr; +} + +/** + * @brief DynamicElementTextModel::undoForEditedText + * @param deti + * @return A QUndoCommand that describe all changes made for @deti. + * Each change made for @deti is append as a child of the returned QUndoCommand. + * In other word, if the returned QUndoCommand have no child, that mean there is no change. + */ +QUndoCommand *DynamicElementTextModel::undoForEditedText(DynamicElementTextItem *deti) const +{ + QUndoCommand *undo = new QUndoCommand(tr("Éditer un texte d'élément")); + + if (!m_texts_list.contains(deti)) + return undo; + + QStandardItem *text_qsi = m_texts_list.value(deti); + + QString from = text_qsi->child(0,1)->data(Qt::DisplayRole).toString(); + if ((from == tr("Texte utilisateur")) && (deti->textFrom() != DynamicElementTextItem::UserText)) + new QPropertyUndoCommand(deti, "textFrom", QVariant(deti->textFrom()), QVariant(DynamicElementTextItem::UserText), undo); + else if ((from == tr("Information de l'élément")) && (deti->textFrom() != DynamicElementTextItem::ElementInfo)) + new QPropertyUndoCommand(deti, "textFrom", QVariant(deti->textFrom()), QVariant(DynamicElementTextItem::ElementInfo), undo); + + QString text = text_qsi->child(0,0)->child(0,1)->data(Qt::DisplayRole).toString(); + if (text != deti->text()) + new QPropertyUndoCommand(deti, "text", QVariant(deti->text()), QVariant(text), undo); + + int fs = text_qsi->child(1,1)->data(Qt::EditRole).toInt(); + if (fs != deti->fontSize()) + new QPropertyUndoCommand(deti, "fontSize", QVariant(deti->fontSize()), QVariant(fs), undo); + + QString tagg = text_qsi->child(2,1)->data(Qt::DisplayRole).toString(); + if(tagg != deti->tagg()) + new QPropertyUndoCommand(deti, "tagg", QVariant(deti->tagg()), QVariant(tagg), undo); + + QColor color = text_qsi->child(3,1)->data(Qt::EditRole).value(); + if(color != deti->color()) + new QPropertyUndoCommand(deti, "color", QVariant(deti->color()), QVariant(color), undo); + + return undo; +} + +/** + * @brief DynamicElementTextModel::enableSourceText + * Enable the good field, according to the current source of text, for the edited text @deti + * @param deti + * @param tf + */ +void DynamicElementTextModel::enableSourceText(DynamicElementTextItem *deti, DynamicElementTextItem::TextFrom tf) +{ + if (!m_texts_list.contains(deti)) + return; + + QStandardItem *qsi = m_texts_list.value(deti)->child(0,0); + + bool usr = true, info = false; + if(tf == DynamicElementTextItem::ElementInfo) { + usr = false; info = true;} + + //User text + qsi->child(0,0)->setEnabled(usr); + qsi->child(0,1)->setEnabled(usr); + //Info text + qsi->child(1,0)->setEnabled(info); + qsi->child(1,1)->setEnabled(info); +} + +void DynamicElementTextModel::dataEdited(QStandardItem *qsi) +{ + DynamicElementTextItem *deti = textFromItem(qsi); + if (!deti) + return; + + if (qsi->data().toInt() == textFrom) + { + QString from = qsi->data(Qt::DisplayRole).toString(); + if (from == tr("Texte utilisateur")) + enableSourceText(deti, DynamicElementTextItem::UserText); + else + enableSourceText(deti, DynamicElementTextItem::ElementInfo); + } + else if (qsi->data().toInt() == userText) + { + QString text = qsi->data(Qt::DisplayRole).toString(); + m_texts_list.value(deti)->setData(text, Qt::DisplayRole); + } +} + +/** + * @brief DynamicElementTextModel::setConnection + * Set up the connection for @deti to keep up to date the data of this model and the text. + * Is notably use with the use of QUndoCommand. + * @param deti - text to setup connection + * @param set - true = set connection - false unset connection + */ +void DynamicElementTextModel::setConnection(DynamicElementTextItem *deti, bool set) +{ + if(set) + { + if(m_hash_text_connect.keys().contains(deti)) + return; + + QList connection_list; + connection_list << connect(deti, &DynamicElementTextItem::colorChanged, [deti,this](){this->updateDataFromText(deti, color);}); + connection_list << connect(deti, &DynamicElementTextItem::fontSizeChanged, [deti,this](){this->updateDataFromText(deti, size);}); + connection_list << connect(deti, &DynamicElementTextItem::taggChanged, [deti,this](){this->updateDataFromText(deti, tagg);}); + connection_list << connect(deti, &DynamicElementTextItem::textChanged, [deti,this](){this->updateDataFromText(deti, userText);}); + connection_list << connect(deti, &DynamicElementTextItem::TextFromChanged, [deti,this](){this->updateDataFromText(deti, textFrom);}); + + m_hash_text_connect.insert(deti, connection_list); + } + else + { + if(!m_hash_text_connect.keys().contains(deti)) + return; + + for (QMetaObject::Connection con : m_hash_text_connect.value(deti)) + disconnect(con); + + m_hash_text_connect.remove(deti); + } +} + +void DynamicElementTextModel::updateDataFromText(DynamicElementTextItem *deti, ValueType type) +{ + QStandardItem *qsi = m_texts_list.value(deti); + if (!qsi) + return; + + switch (type) + { + case textFrom: + qsi->child(0,1)->setData(deti->textFrom() == DynamicElementTextItem::UserText ? tr("Texte utilisateur") : tr("Information de l'élément"), Qt::DisplayRole); + break; + case userText: + { + QStandardItem *qsia = qsi->child(0,0); + qsia->child(0,1)->setData(deti->toPlainText(), Qt::DisplayRole); + qsi->setData(deti->toPlainText(), Qt::DisplayRole); + break; + } + case infoText: + break; + case size: + qsi->child(1,1)->setData(deti->fontSize(), Qt::EditRole); + break; + case tagg: + qsi->child(2,1)->setData(deti->tagg(), Qt::DisplayRole); + break; + case color: + { + qsi->child(3,1)->setData(deti->color(), Qt::EditRole); + qsi->child(3,1)->setData(deti->color(), Qt::ForegroundRole); + break; + } + } +} + + +/*************************************************** + * A little delegate only for add a combobox and a color dialog, + * for use with the model + ***************************************************/ + +DynamicTextItemDelegate::DynamicTextItemDelegate(QObject *parent) : + QStyledItemDelegate(parent) +{} + +QWidget *DynamicTextItemDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const +{ + switch (index.data(Qt::UserRole+1).toInt()) + { + case DynamicElementTextModel::textFrom: + { + QComboBox *qcb = new QComboBox(parent); + qcb->addItem(tr("Texte utilisateur")); + qcb->addItem(tr("Information de l'élément")); + return qcb; + } + case DynamicElementTextModel::color: + { + QColorDialog *cd = new QColorDialog(index.data(Qt::EditRole).value()); + return cd; + } + } + return QStyledItemDelegate::createEditor(parent, option, index); +} + +void DynamicTextItemDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const +{ + if (index.isValid()) + { + if (QStandardItemModel *qsim = dynamic_cast(model)) + { + QStandardItem *qsi = qsim->itemFromIndex(index); + if(qsi) + { + if(QColorDialog *cd = dynamic_cast (editor)) + { + qsi->setData(cd->selectedColor(), Qt::EditRole); + qsi->setData(cd->selectedColor(), Qt::ForegroundRole); + return; + } + } + + } + } + + QStyledItemDelegate::setModelData(editor, model, index); +} diff --git a/sources/ui/dynamicelementtextmodel.h b/sources/ui/dynamicelementtextmodel.h new file mode 100644 index 000000000..615beac10 --- /dev/null +++ b/sources/ui/dynamicelementtextmodel.h @@ -0,0 +1,76 @@ +/* + 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 DYNAMICELEMENTTEXTMODEL_H +#define DYNAMICELEMENTTEXTMODEL_H + +#include +#include +#include "dynamicelementtextitem.h" + +class QUndoCommand; + +/** + * @brief The DynamicElementTextModel class + * A model to use with QtView. + * This model display and can edit the value of dynamic text of an element. + * Set the delegate DynamicTextItemDelegate as delegate of this model. + */ +class DynamicElementTextModel : public QStandardItemModel +{ + Q_OBJECT + + public: + enum ValueType { + textFrom =1, + userText, + infoText, + size, + tagg, + color + }; + + DynamicElementTextModel(QObject *parent = nullptr); + ~DynamicElementTextModel(); + + void addText(DynamicElementTextItem *deti); + void removeText(DynamicElementTextItem *deti); + DynamicElementTextItem *textFromIndex(const QModelIndex &index) const; + DynamicElementTextItem *textFromItem(QStandardItem *item) const; + QUndoCommand *undoForEditedText(DynamicElementTextItem *deti) const; + + private: + void enableSourceText(DynamicElementTextItem *deti, DynamicElementTextItem::TextFrom tf ); + void dataEdited(QStandardItem *qsi); + void setConnection(DynamicElementTextItem *deti, bool set); + void updateDataFromText(DynamicElementTextItem *deti, DynamicElementTextModel::ValueType type); + + private: + QHash m_texts_list; + QHash > m_hash_text_connect; +}; + +class DynamicTextItemDelegate : public QStyledItemDelegate +{ + public: + DynamicTextItemDelegate(QObject *parent = Q_NULLPTR); + + virtual QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const; + virtual void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const; +}; + +#endif // DYNAMICELEMENTTEXTMODEL_H diff --git a/sources/ui/elementpropertieswidget.cpp b/sources/ui/elementpropertieswidget.cpp index 5927f68c5..734abea1c 100644 --- a/sources/ui/elementpropertieswidget.cpp +++ b/sources/ui/elementpropertieswidget.cpp @@ -24,6 +24,7 @@ #include "diagram.h" #include "diagramposition.h" #include "qeticons.h" +#include "dynamicelementtextitemeditor.h" #include #include @@ -203,9 +204,10 @@ void ElementPropertiesWidget::updateUi() default: break; } + m_list_editor << new DynamicElementTextItemEditor(m_element, this); //Add each editors in tab widget - foreach (AbstractElementPropertiesEditorWidget *aepew, m_list_editor) + for (AbstractElementPropertiesEditorWidget *aepew : m_list_editor) { aepew->setLiveEdit(m_live_edit); m_tab->addTab(aepew, aepew->title()); @@ -296,7 +298,7 @@ QWidget *ElementPropertiesWidget::generalWidget() connect(find_in_panel, SIGNAL(clicked()), this, SLOT(findInPanel())); QPushButton *edit_element = new QPushButton(QET::Icons::ElementEdit, tr("Éditer l'élément"), general_widget); connect(edit_element, SIGNAL(clicked()), this, SLOT(editElement())); - QHBoxLayout *hlayout_ = new QHBoxLayout; + QHBoxLayout *hlayout_ = new QHBoxLayout; hlayout_->addWidget(find_in_panel); hlayout_->addWidget(edit_element); vlayout_->addLayout(hlayout_); diff --git a/sources/undocommand/addelementtextcommand.cpp b/sources/undocommand/addelementtextcommand.cpp new file mode 100644 index 000000000..3ebccf455 --- /dev/null +++ b/sources/undocommand/addelementtextcommand.cpp @@ -0,0 +1,83 @@ +/* + 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 "addelementtextcommand.h" +#include "element.h" +#include "dynamicelementtextitem.h" +#include + +AddElementTextCommand::AddElementTextCommand(Element *element, DynamicElementTextItem *deti, QUndoCommand *parent): + QUndoCommand(parent), + m_element(element), + m_text(deti) +{ + setText(QObject::tr("Ajouter un texte d'élément")); +} + +AddElementTextCommand::~AddElementTextCommand() +{ + if(!m_element->dynamicTextItems().contains(m_text)) + delete m_text; +} + +void AddElementTextCommand::undo() +{ + m_element->removeDynamicTextItem(m_text); + m_text->setParentItem(nullptr); + if(m_text->scene()) + m_text->scene()->removeItem(m_text); +} + +void AddElementTextCommand::redo() +{ + m_text->setParentItem(m_element); + m_element->addDynamicTextItem(m_text); +} + +//RemoveElementTextCommand::RemoveElementTextCommand(DynamicElementTextItem *deti, QUndoCommand *parent) : +// QUndoCommand(parent), +// m_text(deti) +//{ +// setText(QObject::tr("Supprimer un texte d'élément")); +// m_element = deti->ParentElement(); +//} + +//RemoveElementTextCommand::~RemoveElementTextCommand() +//{ +// if(m_element && !m_element->dynamicTextItems().contains(m_text)) +// delete m_text; +//} + +//void RemoveElementTextCommand::undo() +//{ +// if(m_element) +// { +// m_text->setParentItem(m_element); +// m_element->addDynamicTextItem(m_text); +// } +//} + +//void RemoveElementTextCommand::redo() +//{ +// if(m_element && m_text->scene()) +// { + +// m_element->removeDynamicTextItem(m_text); +// m_text->setParentItem(nullptr); +// m_text->scene()->removeItem(m_text); +// } +//} diff --git a/sources/undocommand/addelementtextcommand.h b/sources/undocommand/addelementtextcommand.h new file mode 100644 index 000000000..09420e471 --- /dev/null +++ b/sources/undocommand/addelementtextcommand.h @@ -0,0 +1,54 @@ +/* + 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 ADDELEMENTTEXTCOMMAND_H +#define ADDELEMENTTEXTCOMMAND_H + +#include + +class Element; +class DynamicElementTextItem; + +class AddElementTextCommand : public QUndoCommand +{ + public: + AddElementTextCommand(Element *element, DynamicElementTextItem *deti, QUndoCommand *parent = nullptr); + virtual ~AddElementTextCommand(); + + virtual void undo(); + virtual void redo(); + + private: + Element *m_element = nullptr; + DynamicElementTextItem *m_text = nullptr; +}; + +//class RemoveElementTextCommand : public QUndoCommand +//{ +// public: +// RemoveElementTextCommand(DynamicElementTextItem *deti, QUndoCommand *parent = nullptr); +// virtual ~RemoveElementTextCommand(); + +// virtual void undo(); +// virtual void redo(); + +// private: +// Element *m_element = nullptr; +// DynamicElementTextItem *m_text = nullptr; +//}; + +#endif // ADDELEMENTTEXTCOMMAND_H diff --git a/sources/undocommand/deleteqgraphicsitemcommand.cpp b/sources/undocommand/deleteqgraphicsitemcommand.cpp new file mode 100644 index 000000000..68f1c34c0 --- /dev/null +++ b/sources/undocommand/deleteqgraphicsitemcommand.cpp @@ -0,0 +1,119 @@ +/* + 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 "deleteqgraphicsitemcommand.h" +#include "dynamicelementtextitem.h" +#include "diagram.h" +#include "element.h" +#include "conductor.h" +#include "conductortextitem.h" + +/** + * @brief DeleteQGraphicsItemCommand::DeleteQGraphicsItemCommand + * @param diagram : deigram where this undo work + * @param content : content to remove + * @param parent : parent undo + */ +DeleteQGraphicsItemCommand::DeleteQGraphicsItemCommand(Diagram *diagram, const DiagramContent &content, QUndoCommand *parent) : + QUndoCommand(parent), + m_removed_contents(content), + m_diagram(diagram) +{ + //If parent element of a dynamic element text item is also in @m_removed_content, + //we remove it, because when the element will be removed from the scene every child's will also be removed. + const QSet elmt_set = m_removed_contents.m_element_texts; + for(DynamicElementTextItem *deti : elmt_set) + { + if (m_removed_contents.m_elements.contains(deti->ParentElement())) + m_removed_contents.m_element_texts.remove(deti); + + } + + for(DynamicElementTextItem *deti : m_removed_contents.m_element_texts) + m_elmt_text_hash.insert(deti, deti->ParentElement()); + + setText(QString(QObject::tr("supprimer %1", "undo caption - %1 is a sentence listing the removed content")).arg(m_removed_contents.sentence(DiagramContent::All))); + m_diagram->qgiManager().manage(m_removed_contents.items(DiagramContent::All)); +} + +DeleteQGraphicsItemCommand::~DeleteQGraphicsItemCommand() { + m_diagram->qgiManager().release(m_removed_contents.items(DiagramContent::All)); +} + +/** + * @brief DeleteQGraphicsItemCommand::undo + * Undo this command + */ +void DeleteQGraphicsItemCommand::undo() +{ + m_diagram->showMe(); + + for(QGraphicsItem *item : m_removed_contents.items()) + m_diagram->addItem(item); + + //We relink element after every element was added to diagram + for(Element *e : m_removed_contents.m_elements) + for(Element *elmt : m_link_hash[e]) + e->linkToElement(elmt); + + for(DynamicElementTextItem *deti : m_removed_contents.m_element_texts) + { + deti->setParentItem(m_elmt_text_hash.value(deti)); + m_elmt_text_hash.value(deti)->addDynamicTextItem(deti); + } +} + +/** + * @brief DeleteQGraphicsItemCommand::redo + * Redo the delete command + */ +void DeleteQGraphicsItemCommand::redo() +{ + m_diagram -> showMe(); + + for(Conductor *c : m_removed_contents.conductors(DiagramContent::AnyConductor)) + { + //If option one text per folio is enable, and the text item of + //current conductor is visible (that mean the conductor have the single displayed text) + //We call adjustTextItemPosition to other conductor at the same potential to keep + //a visible text on this potential. + if (m_diagram -> defaultConductorProperties.m_one_text_per_folio && c -> textItem() -> isVisible()) + { + QList conductor_list; + conductor_list << c -> relatedPotentialConductors(false).toList(); + if (conductor_list.count()) + conductor_list.first() -> calculateTextItemPosition(); + } + } + + for(Element *e : m_removed_contents.m_elements) + { + //Get linked element, for relink it at undo + if (!e->linkedElements().isEmpty()) + m_link_hash.insert(e, e->linkedElements()); + } + + for(DynamicElementTextItem *deti : m_removed_contents.m_element_texts) + { + deti->ParentElement()->removeDynamicTextItem(deti); + deti->setParentItem(nullptr); + } + + + for(QGraphicsItem *item : m_removed_contents.items()) + m_diagram->removeItem(item); +} diff --git a/sources/undocommand/deleteqgraphicsitemcommand.h b/sources/undocommand/deleteqgraphicsitemcommand.h new file mode 100644 index 000000000..c5906434b --- /dev/null +++ b/sources/undocommand/deleteqgraphicsitemcommand.h @@ -0,0 +1,46 @@ +/* + 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 DELETEQGRAPHICSITEMCOMMAND_H +#define DELETEQGRAPHICSITEMCOMMAND_H + +#include +#include "diagramcontent.h" + +class Diagram; + +class DeleteQGraphicsItemCommand : public QUndoCommand +{ + public: + DeleteQGraphicsItemCommand(Diagram *diagram, const DiagramContent &content, QUndoCommand * parent = nullptr); + virtual ~DeleteQGraphicsItemCommand() override; + private: + DeleteQGraphicsItemCommand(const DeleteQGraphicsItemCommand &); + + public: + virtual void undo() override; + virtual void redo() override; + + // attributes + private: + DiagramContent m_removed_contents; + Diagram *m_diagram; + QHash > m_link_hash; /// keep linked element for each removed element linked to other element. + QHash m_elmt_text_hash; /// Keep the parent element of each deleted dynamic element text item +}; + +#endif // DELETEQGRAPHICSITEMCOMMAND_H