diff --git a/sources/editor/editorcommands.cpp b/sources/editor/editorcommands.cpp index e1c64cbc8..4da027e0c 100644 --- a/sources/editor/editorcommands.cpp +++ b/sources/editor/editorcommands.cpp @@ -331,14 +331,22 @@ ChangePartCommand::ChangePartCommand( ChangePartCommand::~ChangePartCommand() { } -/// Annule le changement -void ChangePartCommand::undo() { +/** + * @brief ChangePartCommand::undo + */ +void ChangePartCommand::undo() +{ cep -> setProperty(property, old_value); + ElementEditionCommand::undo(); } -/// Refait le changement -void ChangePartCommand::redo() { +/** + * @brief ChangePartCommand::redo + */ +void ChangePartCommand::redo() +{ cep -> setProperty(property, new_value); + ElementEditionCommand::redo(); } /** diff --git a/sources/editor/editorcommands.h b/sources/editor/editorcommands.h index 41a9ac5d2..f57640bba 100644 --- a/sources/editor/editorcommands.h +++ b/sources/editor/editorcommands.h @@ -26,31 +26,33 @@ #include /** - ElementEditionCommand is the base class for all commands classes involved in + * @brief The ElementEditionCommand class + * ElementEditionCommand is the base class for all commands classes involved in the edition of an electrical element. It provides commonly required methods and attributes, such as accessors to the modified scene and view. -*/ -class ElementEditionCommand : public QUndoCommand { - // constructors, destructor + */ +class ElementEditionCommand : public QUndoCommand +{ + // constructors, destructor public: - ElementEditionCommand(ElementScene * = 0, ElementView * = 0, QUndoCommand * = 0); - ElementEditionCommand(const QString &, ElementScene * = 0, ElementView * = 0, QUndoCommand * = 0); - virtual ~ElementEditionCommand(); + ElementEditionCommand(ElementScene * = 0, ElementView * = 0, QUndoCommand * = 0); + ElementEditionCommand(const QString &, ElementScene * = 0, ElementView * = 0, QUndoCommand * = 0); + virtual ~ElementEditionCommand(); private: - ElementEditionCommand(const ElementEditionCommand &); + ElementEditionCommand(const ElementEditionCommand &); - // methods + // methods public: - ElementScene *elementScene() const; - void setElementScene(ElementScene *); - ElementView *elementView() const; - void setElementView(ElementView *); + ElementScene *elementScene() const; + void setElementScene(ElementScene *); + ElementView *elementView() const; + void setElementView(ElementView *); - // attributes + // attributes protected: - /// Element editor/view/scene the command should take place on - ElementScene *editor_scene_; - ElementView *editor_view_; + /// Element editor/view/scene the command should take place on + ElementScene *editor_scene_; + ElementView *editor_view_; }; /** diff --git a/sources/editor/elementitemeditor.cpp b/sources/editor/elementitemeditor.cpp index 614920bd9..e4854b0ed 100644 --- a/sources/editor/elementitemeditor.cpp +++ b/sources/editor/elementitemeditor.cpp @@ -75,6 +75,38 @@ void ElementItemEditor::addChangePartCommand(const QString &desc, CustomElementP ); } +/** + * @brief ElementItemEditor::addChangePartCommand + * Add a ChangePartCommand with child for each part of part_list to the undo stack + * @param undo_text : text of undo command to display + * @param part_list : list of parts to modify + * @param property : QProperty (of CustomElementPart) to modify + * @param new_value : the new value of the QProperty + */ +void ElementItemEditor::addChangePartCommand(const QString &undo_text, QList part_list, const char *property, const QVariant &new_value) +{ + if (part_list.isEmpty()) return; + + //Get only the parts concerned by modification + QList updated_part; + foreach (CustomElementPart *cep, part_list) + if (cep->property(property) != new_value) + updated_part << cep; + + //There is not part to modify + if(updated_part.isEmpty()) return; + + //Set the first part has parent undo + CustomElementPart *p_cep = updated_part.takeFirst(); + QUndoCommand *parent_undo = new ChangePartCommand (undo_text, p_cep, property, p_cep->property(property), new_value); + + //And other parts are just child of parent + foreach (CustomElementPart *cep, updated_part) + new ChangePartCommand (undo_text, cep, property, cep->property(property), new_value, parent_undo); + + undoStack().push(parent_undo); +} + /// @return Le nom du type d'element edite QString ElementItemEditor::elementTypeName() const { return(element_type_name); diff --git a/sources/editor/elementitemeditor.h b/sources/editor/elementitemeditor.h index 208023076..2a30d3b86 100644 --- a/sources/editor/elementitemeditor.h +++ b/sources/editor/elementitemeditor.h @@ -26,31 +26,38 @@ class CustomElementPart; provides methods to access the editor itself, the undo stack, the edition scene and even a method to easily take a ChangePartCommand into account. */ -class ElementItemEditor : public QWidget { - Q_OBJECT - // constructors, destructor +class ElementItemEditor : public QWidget +{ + Q_OBJECT + // constructors, destructor public: - ElementItemEditor(QETElementEditor *, QWidget * = 0); - virtual ~ElementItemEditor() {}; + ElementItemEditor(QETElementEditor *, QWidget * = 0); + virtual ~ElementItemEditor() {}; private: - ElementItemEditor(const ElementItemEditor &); + ElementItemEditor(const ElementItemEditor &); - // methods + // methods public: - virtual QETElementEditor *elementEditor() const; - virtual ElementScene *elementScene() const; - virtual QUndoStack &undoStack() const; - virtual void addChangePartCommand(const QString &, CustomElementPart *, const char *, const QVariant &); - virtual QString elementTypeName() const; - virtual void setElementTypeName(const QString &); - virtual void detach(); - virtual bool setPart(CustomElementPart *) = 0; - virtual CustomElementPart *currentPart() const = 0; - virtual void updateForm() = 0; + virtual QETElementEditor *elementEditor() const; + virtual ElementScene *elementScene() const; + virtual QUndoStack &undoStack() const; + + virtual void addChangePartCommand(const QString &, CustomElementPart *, const char *, const QVariant &); + virtual void addChangePartCommand(const QString &, QList, const char *, const QVariant &); + + virtual QString elementTypeName() const; + virtual void setElementTypeName(const QString &); + virtual void detach(); + + virtual bool setPart(CustomElementPart *) = 0; + virtual bool setParts(QList ) {return false;} + + virtual CustomElementPart *currentPart() const = 0; + virtual void updateForm() = 0; - // attributes + // attributes private: - QETElementEditor *element_editor; - QString element_type_name; + QETElementEditor *element_editor; + QString element_type_name; }; #endif diff --git a/sources/editor/graphicspart/customelementgraphicpart.cpp b/sources/editor/graphicspart/customelementgraphicpart.cpp index b59405fa7..9b44c7a33 100644 --- a/sources/editor/graphicspart/customelementgraphicpart.cpp +++ b/sources/editor/graphicspart/customelementgraphicpart.cpp @@ -65,6 +65,30 @@ void CustomElementGraphicPart::drawCross(const QPointF ¢er, QPainter *painte painter -> restore(); } +/** + * @brief CustomElementGraphicPart::setLineStyle + * Set line style to ls + * @param ls + */ +void CustomElementGraphicPart::setLineStyle(const LineStyle ls) +{ + if (_linestyle == ls) return; + _linestyle = ls; + update(); +} + +/** + * @brief CustomElementGraphicPart::setLineWeight + * Set line weight to lw + * @param lw + */ +void CustomElementGraphicPart::setLineWeight(const LineWeight lw) +{ + if (_lineweight == lw) return; + _lineweight = lw; + update(); +} + /** * @brief CustomElementGraphicPart::penWeight * @return the weight of pen @@ -78,6 +102,42 @@ qreal CustomElementGraphicPart::penWeight() const return 1; } +/** + * @brief CustomElementGraphicPart::setFilling + * Set filling to f + * @param f + */ +void CustomElementGraphicPart::setFilling(const Filling f) +{ + if (_filling == f) return; + _filling = f; + update(); +} + +/** + * @brief CustomElementGraphicPart::setColor + * Set color to c + * @param c + */ +void CustomElementGraphicPart::setColor(const Color c) +{ + if (_color == c) return; + _color = c; + update(); +} + +/** + * @brief CustomElementGraphicPart::setAntialiased + * Set antialias to b + * @param b + */ +void CustomElementGraphicPart::setAntialiased(const bool b) +{ + if (_antialiased == b) return; + _antialiased = b; + update(); +} + /** * @brief CustomElementGraphicPart::stylesToXml * Write the curent style to xml element. diff --git a/sources/editor/graphicspart/customelementgraphicpart.h b/sources/editor/graphicspart/customelementgraphicpart.h index d3cb8e722..348252712 100644 --- a/sources/editor/graphicspart/customelementgraphicpart.h +++ b/sources/editor/graphicspart/customelementgraphicpart.h @@ -61,7 +61,6 @@ class CustomElementGraphicPart : public QGraphicsObject, public CustomElementPar //Line color enum Color {BlackColor, WhiteColor, GreenColor, RedColor, BlueColor}; - // constructors, destructor public: @@ -71,21 +70,21 @@ class CustomElementGraphicPart : public QGraphicsObject, public CustomElementPar static void drawCross (const QPointF ¢er, QPainter *painter); //Getter and setter - LineStyle lineStyle () const {return _linestyle;} - void setLineStyle (const LineStyle ls) {_linestyle = ls;} + LineStyle lineStyle () const {return _linestyle;} + void setLineStyle (const LineStyle ls); - LineWeight lineWeight () const {return _lineweight;} - void setLineWeight (const LineWeight lw) {_lineweight = lw;} + LineWeight lineWeight () const {return _lineweight;} + void setLineWeight (const LineWeight lw); qreal penWeight () const; - Filling filling () const {return _filling;} - void setFilling(const Filling f) {_filling = f;} + Filling filling () const {return _filling;} + void setFilling(const Filling f); - Color color () const {return _color;} - void setColor(const Color c) {_color = c;} + Color color () const {return _color;} + void setColor(const Color c); - bool antialiased () const {return _antialiased;} - void setAntialiased(const bool b) {_antialiased = b;} + bool antialiased () const {return _antialiased;} + void setAntialiased(const bool b); //End of getter and setter diff --git a/sources/editor/qetelementeditor.cpp b/sources/editor/qetelementeditor.cpp index b208fcd07..2540c25d9 100644 --- a/sources/editor/qetelementeditor.cpp +++ b/sources/editor/qetelementeditor.cpp @@ -40,6 +40,7 @@ #include "textfieldeditor.h" #include "partterminal.h" #include "parttextfield.h" +#include "styleeditor.h" #include "eseventaddline.h" #include "eseventaddrect.h" @@ -499,6 +500,7 @@ void QETElementEditor::setupInterface() { editors_["terminal"] = new TerminalEditor(this); editors_["text"] = new TextEditor(this); editors_["input"] = new TextFieldEditor(this); + editors_["style"] = new StyleEditor(this); // panel sur le cote pour editer les parties tools_dock = new QDockWidget(tr("Informations", "dock title"), this); @@ -565,33 +567,73 @@ void QETElementEditor::slot_setNoDragToView() { */ void QETElementEditor::slot_updateInformations() { QList selected_qgis = ce_scene -> selectedItems(); + QList cep_list; + bool style_editable = false; + + //Test if part are editable by style editor + if (selected_qgis.size() >= 2) + { + style_editable = true; + foreach (QGraphicsItem *qgi, selected_qgis) + { + if (CustomElementPart *cep = dynamic_cast(qgi)) + cep_list << cep; + else + style_editable = false; + } + if (style_editable) + style_editable = StyleEditor::isStyleEditable(cep_list); + + } clearToolsDock(); - // s'il n'y a qu'une seule primitive selectionnee - if (selected_qgis.size() == 1) { + //There's one selected item + if (selected_qgis.size() == 1) + { QGraphicsItem *qgi = selected_qgis.first(); - if (CustomElementPart *selection = dynamic_cast(qgi)) { + if (CustomElementPart *selection = dynamic_cast(qgi)) + { // on en ajoute le widget d'edition QString selection_xml_name = selection -> xmlName(); ElementItemEditor *selection_editor = editors_[selection_xml_name]; - if (selection_editor) { - if (selection_editor -> setPart(selection)) { + if (selection_editor) + { + if (selection_editor -> setPart(selection)) + { tools_dock_scroll_area_ -> setWidget(selection_editor); tools_dock_stack_ -> setCurrentIndex(1); - } else { + } + else + { qDebug() << "Editor refused part."; } } } - } else { - default_informations -> setText( - tr( - "%n partie(s) s\351lectionn\351e(s).", - "", - selected_qgis.size() - ) - ); + } + //There's several parts selecteds and all can be edited by style editor. + else if (style_editable) + { + ElementItemEditor *selection_editor = editors_["style"]; + if (selection_editor) + { + if (selection_editor -> setParts(cep_list)) + { + tools_dock_scroll_area_ -> setWidget(selection_editor); + tools_dock_stack_ -> setCurrentIndex(1); + } + else + { + qDebug() << "Editor refused part."; + } + } + } + //Else we only display the number of selected items + else + { + default_informations -> setText(tr("%n partie(s) s\351lectionn\351e(s).", + "", + selected_qgis.size())); default_informations -> setAlignment(Qt::AlignHCenter | Qt::AlignTop); tools_dock_stack_ -> setCurrentIndex(0); } diff --git a/sources/editor/styleeditor.cpp b/sources/editor/styleeditor.cpp index ab794467d..60f8619cf 100644 --- a/sources/editor/styleeditor.cpp +++ b/sources/editor/styleeditor.cpp @@ -112,60 +112,148 @@ void StyleEditor::updatePart() { } /// Update antialiasing with undo command -void StyleEditor::updatePartAntialiasing() { addChangePartCommand(tr("style antialiasing"), part, "antialias", antialiasing -> isChecked()); } +void StyleEditor::updatePartAntialiasing() +{ + if (part) + addChangePartCommand(tr("style antialiasing"), part, "antialias", antialiasing -> isChecked()); + else if (!m_part_list.isEmpty()) + addChangePartCommand(tr("style antialiasing"), m_cep_list, "antialias", antialiasing -> isChecked()); +} + /// Update color with undo command -void StyleEditor::updatePartColor() { addChangePartCommand(tr("style couleur"), part, "color", outline_color->itemData(outline_color -> currentIndex()));} +void StyleEditor::updatePartColor() +{ + if (part) + addChangePartCommand(tr("style couleur"), part, "color", outline_color->itemData(outline_color -> currentIndex())); + else if (!m_part_list.isEmpty()) + addChangePartCommand(tr("style couleur"), m_cep_list, "color", outline_color->itemData(outline_color -> currentIndex())); +} + /// Update style with undo command -void StyleEditor::updatePartLineStyle() { addChangePartCommand(tr("style ligne"), part, "line_style", line_style->itemData(line_style -> currentIndex()));} +void StyleEditor::updatePartLineStyle() +{ + if (part) + addChangePartCommand(tr("style ligne"), part, "line_style", line_style->itemData(line_style -> currentIndex())); + else if (!m_part_list.isEmpty()) + addChangePartCommand(tr("style ligne"), m_cep_list, "line_style", line_style->itemData(line_style -> currentIndex())); +} + /// Update weight with undo command -void StyleEditor::updatePartLineWeight() { addChangePartCommand(tr("style epaisseur"), part, "line_weight", size_weight->itemData(size_weight -> currentIndex()));} +void StyleEditor::updatePartLineWeight() +{ + if (part) + addChangePartCommand(tr("style epaisseur"), part, "line_weight", size_weight->itemData(size_weight -> currentIndex())); + else if (!m_part_list.isEmpty()) + addChangePartCommand(tr("style epaisseur"), m_cep_list, "line_weight", size_weight->itemData(size_weight -> currentIndex())); +} + /// Update color filling with undo command -void StyleEditor::updatePartFilling() { addChangePartCommand(tr("style remplissage"), part, "filling", filling_color->itemData(filling_color -> currentIndex()));} +void StyleEditor::updatePartFilling() +{ + if(part) + addChangePartCommand(tr("style remplissage"), part, "filling", filling_color->itemData(filling_color -> currentIndex())); + else if (!m_part_list.isEmpty()) + addChangePartCommand(tr("style remplissage"), m_cep_list, "filling", filling_color->itemData(filling_color -> currentIndex())); +} /** * @brief StyleEditor::updateForm - * Update the edition form + * Update the edition form according to the value of edited part(s) */ -void StyleEditor::updateForm() { - if (!part) return; +void StyleEditor::updateForm() +{ + if (!part && m_part_list.isEmpty()) return; activeConnections(false); - // lit l'antialiasing - antialiasing -> setChecked(part -> antialiased()); - - // lit la couleur - outline_color -> setCurrentIndex(part -> color()); - - // lit le style - line_style -> setCurrentIndex(part -> lineStyle()); - - // lit l'epaisseur - size_weight -> setCurrentIndex(part -> lineWeight()); - // lit le remplissage - filling_color -> setCurrentIndex(part -> filling()); + if (part) + { + antialiasing -> setChecked(part -> antialiased()); + outline_color -> setCurrentIndex(part -> color()); + line_style -> setCurrentIndex(part -> lineStyle()); + size_weight -> setCurrentIndex(part -> lineWeight()); + filling_color -> setCurrentIndex(part -> filling()); + } + else if (m_part_list.size()) + { + CustomElementGraphicPart *first_part = m_part_list.first(); + antialiasing -> setChecked(first_part -> antialiased()); + outline_color -> setCurrentIndex(first_part -> color()); + line_style -> setCurrentIndex(first_part -> lineStyle()); + size_weight -> setCurrentIndex(first_part -> lineWeight()); + filling_color -> setCurrentIndex(first_part -> filling()); + + foreach (CustomElementGraphicPart *cegp, m_part_list) + { + if (first_part -> antialiased() != cegp -> antialiased()) antialiasing -> setChecked(false); + if (first_part -> color() != cegp -> color()) outline_color -> setCurrentIndex(-1); + if (first_part -> lineStyle() != cegp -> lineStyle()) line_style -> setCurrentIndex(-1); + if (first_part -> lineWeight() != cegp -> lineWeight()) size_weight -> setCurrentIndex(-1); + if (first_part -> filling() != cegp -> filling()) filling_color -> setCurrentIndex(-1); + } + } + activeConnections(true); } /** - Permet de specifier a cet editeur quelle primitive il doit editer. A noter - qu'un editeur peut accepter ou refuser d'editer une primitive. - L'editeur de ligne acceptera d'editer la primitive new_part s'il s'agit d'un - objet de la classe CustomElementGraphicPart. - @param new_part Nouvelle primitive a editer - @return true si l'editeur a accepter d'editer la primitive, false sinon -*/ + * @brief StyleEditor::setPart + * Set the part to edit by this editor. + * Note : editor can accept or refuse to edit a part + * @param new_part : part to edit + * @return true if editor accept to edit this CustomElementPart otherwise false + */ bool StyleEditor::setPart(CustomElementPart *new_part) { - if (!new_part) { - part = 0; + m_part_list.clear(); + + if (!new_part) + { + part = nullptr; return(true); } - if (CustomElementGraphicPart *part_graphic = dynamic_cast(new_part)) { + + if (CustomElementGraphicPart *part_graphic = dynamic_cast(new_part)) + { part = part_graphic; updateForm(); return(true); - } else { - return(false); } + + return(false); +} + +/** + * @brief StyleEditor::setParts + * Set several parts to edit by this editor. + * Note : editor can accept or refuse to edit several parts. + * @param part_list + * @return true if every customeElementPart stored in part_list can + * be edited by this part editor, otherwise return false + * (see StyleEditor::isStyleEditable) + */ +bool StyleEditor::setParts(QList part_list) +{ + if (part_list.isEmpty()) return false; + if (part_list.size() == 1) return setPart(part_list.first()); + + part = nullptr; + m_part_list.clear(); + m_cep_list.clear(); + + if (!isStyleEditable(part_list)) return false; + + foreach (CustomElementPart *cep, part_list) + { + if (CustomElementGraphicPart *cegp = dynamic_cast(cep)) + m_part_list << cegp; + else + return false; + } + + foreach (CustomElementGraphicPart *cegp, m_part_list) + m_cep_list << cegp; + + updateForm(); + return true; } /** @@ -175,6 +263,23 @@ CustomElementPart *StyleEditor::currentPart() const { return(part); } +/** + * @brief StyleEditor::isStyleEditable + * @param cep_list + * @return true if all of the content of cep_list can be edited by style editor, else return false. + */ +bool StyleEditor::isStyleEditable(QList cep_list) +{ + QStringList str; + str << "arc" << "ellipse" << "line" << "polygon" << "rect"; + + foreach (CustomElementPart *cep, cep_list) + if (!str.contains(cep -> xmlName())) + return false; + + return true; +} + /** Active ou desactive les connexionx signaux/slots entre les widgets internes. @param active true pour activer les connexions, false pour les desactiver diff --git a/sources/editor/styleeditor.h b/sources/editor/styleeditor.h index 3bb4ee6d8..f0a24083d 100644 --- a/sources/editor/styleeditor.h +++ b/sources/editor/styleeditor.h @@ -26,41 +26,47 @@ class CustomElementGraphicPart; Its appendWidget() method makes the insertion of another widget below it easier. */ -class StyleEditor : public ElementItemEditor { - Q_OBJECT - // constructors, destructor +class StyleEditor : public ElementItemEditor +{ + Q_OBJECT + // constructors, destructor public: - StyleEditor(QETElementEditor *, CustomElementGraphicPart * = 0, QWidget * = 0); - virtual ~StyleEditor(); + StyleEditor(QETElementEditor *, CustomElementGraphicPart * = 0, QWidget * = 0); + virtual ~StyleEditor(); private: - StyleEditor(const StyleEditor &); + StyleEditor(const StyleEditor &); - // attributes + // attributes private: - CustomElementGraphicPart *part; - QVBoxLayout *main_layout; - QRadioButton *black_color, *white_color, *normal_style, *dashed_style, *dashdotted_style, *dotted_style, *green_color, *red_color, *blue_color; - QRadioButton *none_weight, *thin_weight, *normal_weight, *no_filling; - QRadioButton *black_filling, *white_filling, *green_filling, *red_filling, *blue_filling; - QCheckBox *antialiasing; - QComboBox *filling_color, *outline_color, *size_weight, *line_style; + CustomElementGraphicPart *part; + QList m_part_list; + QList m_cep_list; + QVBoxLayout *main_layout; + QRadioButton *black_color, *white_color, *normal_style, *dashed_style, *dashdotted_style, *dotted_style, *green_color, *red_color, *blue_color; + QRadioButton *none_weight, *thin_weight, *normal_weight, *no_filling; + QRadioButton *black_filling, *white_filling, *green_filling, *red_filling, *blue_filling; + QCheckBox *antialiasing; + QComboBox *filling_color, *outline_color, *size_weight, *line_style; - // methods + // methods public: - virtual bool setPart(CustomElementPart *); - virtual CustomElementPart *currentPart() const; + virtual bool setPart(CustomElementPart *); + virtual bool setParts(QList); + virtual CustomElementPart *currentPart() const; + + static bool isStyleEditable (QList cep_list); public slots: - void updatePart(); - void updateForm(); - void updatePartAntialiasing(); - void updatePartColor(); - void updatePartLineStyle(); - void updatePartLineWeight(); - void updatePartFilling(); + void updatePart(); + void updateForm(); + void updatePartAntialiasing(); + void updatePartColor(); + void updatePartLineStyle(); + void updatePartLineWeight(); + void updatePartFilling(); private: - void activeConnections(bool); + void activeConnections(bool); }; #endif