diff --git a/dev_doc/ID_of_QUndoCommand.txt b/dev_doc/ID_of_QUndoCommand.txt index 1b01037e7..5ae0d08d3 100755 --- a/dev_doc/ID_of_QUndoCommand.txt +++ b/dev_doc/ID_of_QUndoCommand.txt @@ -1 +1,2 @@ ChangeElementInformationCommand = 1 +LinkElementCommand = 2 diff --git a/sources/diagramcommands.cpp b/sources/diagramcommands.cpp index 7c94335ab..5478f927a 100644 --- a/sources/diagramcommands.cpp +++ b/sources/diagramcommands.cpp @@ -1137,142 +1137,3 @@ void ChangeShapeStyleCommand::redo() { diagram -> showMe(); QUndoCommand::redo(); } - -/** - * @brief LinkElementsCommand::LinkElementsCommand - *Constructor - * @param elmt1 element to Link - * @param elmt2 element to link - * @param parent parent undo command - */ -LinkElementsCommand::LinkElementsCommand(Element *elmt1, Element *elmt2, QUndoCommand *parent) : - QUndoCommand(parent), - diagram_(elmt1->diagram()), - element_(elmt1), - first_redo(true) -{ - elmt_list << elmt2; - if (elmt1->linkType() & Element::AllReport && - elmt2->linkType() & Element::AllReport) { - setText(QObject::tr("Lier deux reports de folio", - "title for undo LinkElementsCommand if two elements are folio report")); - } - else if (element_->linkType() & (Element::Master|Element::Slave)) - setText(QObject::tr("Editer les référence croisé", "edite the cross reference")); - else setText(QObject::tr("Lier deux éléments")); - - previous_linked = elmt1->linkedElements(); -} - -LinkElementsCommand::LinkElementsCommand(Element *elmt1, QList &elmtList, QUndoCommand *parent) : - QUndoCommand(parent), - diagram_(elmt1->diagram()), - element_(elmt1), - elmt_list(elmtList), - first_redo(true) -{ - if (element_->linkType() & (Element::Master|Element::Slave)) - setText(QObject::tr("Editer les référence croisé")); - else setText(QObject::tr("Lier deux éléments")); - previous_linked = elmt1->linkedElements(); -} - -/** - * @brief LinkElementsCommand::~LinkElementsCommand - *destructor - */ -LinkElementsCommand::~LinkElementsCommand(){} - -/** - * @brief LinkElementsCommand::undo - *Undo command - */ -void LinkElementsCommand::undo() { - diagram_->showMe(); - - foreach (Element *elmt, elmt_list) - element_->unlinkElement(elmt); - - foreach (Element *elmt, previous_linked) - element_->linkToElement(elmt); - - QUndoCommand::undo(); -} - -/** - * @brief LinkElementsCommand::redo - *redo command - */ -void LinkElementsCommand::redo() { - diagram_->showMe(); - - foreach (Element *elmt, elmt_list) - element_->linkToElement(elmt); - - //If element are report, check if text of this potential is identical. - if ((element_->linkType() &Element::AllReport) && first_redo) { - if(element_->conductors().count() && elmt_list.first()->conductors().count()) { - ConductorAutoNumerotation::checkPotential(element_->conductors().first()); - } - first_redo = false; - } - QUndoCommand::redo(); -} - -/** - * @brief unlinkElementsCommand::unlinkElementsCommand - * Constructor, unlink elmt2 or all elements if elmt2 isn't specified - * @param elmt1 element to set undo command - * @param elmt2 element to be unlinked - * @param parent undo parent - */ -unlinkElementsCommand::unlinkElementsCommand(Element *elmt1, Element *elmt2, QUndoCommand *parent): - QUndoCommand(parent), - diagram_(elmt1->diagram()), - element_(elmt1) -{ - if (elmt2) elmt_list << elmt2; - else elmt_list << elmt1->linkedElements(); - setText(QObject::tr("Délier %n élément(s)", "", elmt_list.size())); -} - -/** - * @brief unlinkElementsCommand::unlinkElementsCommand - * @param elmt1 Element to set the link - * @param elmtList list of all element to be linked to elmt1 - * @param parent undo command - */ -unlinkElementsCommand::unlinkElementsCommand(Element *elmt1, QList &elmtList, QUndoCommand *parent): - QUndoCommand(parent), - diagram_(elmt1->diagram()), - element_(elmt1), - elmt_list(elmtList) -{ - setText(QObject::tr("Délier %n élément(s)", "", elmt_list.size())); -} - -/** - * @brief unlinkElementsCommand::~unlinkElementsCommand - * destructor - */ -unlinkElementsCommand::~unlinkElementsCommand(){} - -/** - * @brief unlinkElementsCommand::undo - *undo command - */ -void unlinkElementsCommand::undo() { - foreach (Element *elmt, elmt_list) - element_->linkToElement(elmt); - QUndoCommand::undo(); -} - -/** - * @brief unlinkElementsCommand::redo - *redo command - */ -void unlinkElementsCommand::redo() { - foreach (Element *elmt, elmt_list) - element_->unlinkElement(elmt); - QUndoCommand::redo(); -} diff --git a/sources/diagramcommands.h b/sources/diagramcommands.h index c0b4e3009..0b87c549e 100644 --- a/sources/diagramcommands.h +++ b/sources/diagramcommands.h @@ -547,41 +547,4 @@ class ChangeShapeStyleCommand : public QUndoCommand { Qt::PenStyle old_style, new_style; Diagram *diagram; }; - -class LinkElementsCommand : public QUndoCommand { - public: - // constructor destructor - LinkElementsCommand (Element *elmt1, Element *elmt2, QUndoCommand *parent = 0); - LinkElementsCommand (Element *elmt1, QList &elmtList, QUndoCommand *parent = 0); - virtual ~LinkElementsCommand(); - //methods - virtual void undo(); - virtual void redo(); - - private: - //attributes - Diagram *diagram_; - Element *element_; - QList elmt_list; - QList previous_linked; - bool first_redo; -}; - -class unlinkElementsCommand : public QUndoCommand { - public: - //constructor destructor - unlinkElementsCommand (Element *elmt1, Element *elmt2 = 0, QUndoCommand *parent = 0); - unlinkElementsCommand (Element *elmt1, QList &elmtList, QUndoCommand *parent = 0); - virtual ~unlinkElementsCommand(); - //methods - virtual void undo(); - virtual void redo(); - - private: - //attributes - Diagram *diagram_; - Element *element_; - QList elmt_list; -}; - #endif diff --git a/sources/ui/linksingleelementwidget.cpp b/sources/ui/linksingleelementwidget.cpp index b72e00fea..b6ff6da65 100644 --- a/sources/ui/linksingleelementwidget.cpp +++ b/sources/ui/linksingleelementwidget.cpp @@ -19,8 +19,8 @@ #include "ui_linksingleelementwidget.h" #include "diagram.h" #include "elementprovider.h" -#include "diagramcommands.h" #include "elementselectorwidget.h" +#include "linkelementcommand.h" /** * @brief LinkSingleElementWidget::LinkSingleElementWidget @@ -104,10 +104,17 @@ void LinkSingleElementWidget::apply() */ QUndoCommand *LinkSingleElementWidget::associatedUndo() const { - if (esw_->selectedElement()) - return new LinkElementsCommand(m_element, esw_->selectedElement()); - else if (unlink_) - return new unlinkElementsCommand(m_element); + if (esw_->selectedElement() || unlink_) + { + LinkElementCommand *undo = new LinkElementCommand(m_element); + + if (esw_->selectedElement()) + undo->setLink(esw_->selectedElement()); + else if (unlink_) + undo->unlinkAll(); + + return undo; + } return nullptr; } diff --git a/sources/ui/linksingleelementwidget.ui b/sources/ui/linksingleelementwidget.ui index 4eb0a5f59..22f15d2ec 100644 --- a/sources/ui/linksingleelementwidget.ui +++ b/sources/ui/linksingleelementwidget.ui @@ -6,8 +6,8 @@ 0 0 - 300 - 400 + 265 + 182 diff --git a/sources/ui/masterpropertieswidget.cpp b/sources/ui/masterpropertieswidget.cpp index cb1ecbcdc..8d6cf0d42 100644 --- a/sources/ui/masterpropertieswidget.cpp +++ b/sources/ui/masterpropertieswidget.cpp @@ -20,9 +20,9 @@ #include #include #include -#include #include #include +#include /** * @brief MasterPropertiesWidget::MasterPropertiesWidget @@ -109,43 +109,35 @@ void MasterPropertiesWidget::reset() { * If no change return nullptr. * @return */ -QUndoCommand* MasterPropertiesWidget::associatedUndo() const { +QUndoCommand* MasterPropertiesWidget::associatedUndo() const +{ QList to_link; QList linked_ = m_element->linkedElements(); - for (int i=0; ilinked_list->count(); i++) { + for (int i=0; ilinked_list->count(); i++) to_link << lwi_hash[ui->linked_list->item(i)]; + + //The two list contain the same element, there is no change + if (to_link.size() == linked_.size()) + { + bool equal = true; + + foreach(Element *elmt, to_link) + if (!linked_.contains(elmt)) + equal = false; + + if(equal) + return nullptr; } - //If same element are find in to_link and linked, that means - // element are already linked, so we remove element on the two list - //if linked_ contains element at the end of the operation, - //that means this element must be unlinked from @m_element - foreach (Element *elmt, to_link) { - if(linked_.contains(elmt)) { - to_link.removeAll(elmt); - linked_.removeAll(elmt); - } - } + LinkElementCommand *undo = new LinkElementCommand(m_element); - // if two list, contain element, we link and unlink @m_element with corresponding - //undo command, and add first command for parent of the second, user see only one - //undo command - if (linked_.count() && to_link.count()) { - LinkElementsCommand *lec = new LinkElementsCommand(m_element, to_link); - new unlinkElementsCommand(m_element, linked_, lec); - return lec; - } - //Else do the single undo command corresponding to the link. - else if (to_link.count()) { - return (new LinkElementsCommand(m_element, to_link)); - } - else if (linked_.count()) { - return (new unlinkElementsCommand(m_element, linked_)); - } - else { - return nullptr; - } + if (to_link.isEmpty()) + undo->unlinkAll(); + else + undo->setLink(to_link); + + return undo; } /** diff --git a/sources/undocommand/linkelementcommand.cpp b/sources/undocommand/linkelementcommand.cpp new file mode 100644 index 000000000..91504ddc5 --- /dev/null +++ b/sources/undocommand/linkelementcommand.cpp @@ -0,0 +1,270 @@ +/* + Copyright 2006-2015 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 "linkelementcommand.h" +#include "element.h" +#include "diagram.h" + +/** + * @brief LinkElementCommand::LinkElementCommand + * Constructor + * @param element_ : element where we work the link / unlink + * @param parent : parent undo + */ +LinkElementCommand::LinkElementCommand(Element *element_, QUndoCommand *parent): + QUndoCommand(parent), + m_element(element_) +{ + m_linked_before = m_linked_after = m_element->linkedElements(); + setText(QObject::tr("Éditer les référence croisé", "edite the cross reference")); +} + +/** + * @brief LinkElementCommand::mergeWith + * @param other try to merge this command with other + * @return true if merge with success else false + */ +bool LinkElementCommand::mergeWith(const QUndoCommand *other) +{ + if (id() != other->id()) return false; + LinkElementCommand const *undo = static_cast (other); + if (m_element != undo->m_element) return false; + m_linked_after = undo->m_linked_after; + return true; +} + +/** + * @brief LinkElementCommand::isLinkable + * @param element_a + * @param element_b + * @param already_linked + * @return true if element_a and element_b can be linked between them. + * There is few condition to be linked : + * 1- element_a and element_b must be linkable type. (Ex : A is master and B is slave 'OK', A and B is master 'KO') + * 2- For element type slave and report (no matter if element is 'A' or 'B'), the element must be free (not connected to an element) + * 3- we can override the section 2 by set already_linked to true. In this case, if slave or report is already + * linked to the other element ('A' or 'B') return true, but if linked to another element (not 'A' or 'B') return false + */ +bool LinkElementCommand::isLinkable(Element *element_a, Element *element_b, bool already_linked) +{ + switch(element_a->linkType()) + { + case Element::Simple: return false; + + case Element::NextReport: + { + //Type isn't good + if (element_b->linkType() != Element::PreviousReport) return false; + //two report is free + if (element_a->isFree() && element_b->isFree()) return true; + //Reports aren't free but are already linked between them and and already_linked is true + if (element_a->linkedElements().contains(element_b) && already_linked) return true; + + return false; + } + + case Element::PreviousReport: + { + //Type isn't good + if (element_b->linkType() != Element::NextReport) return false; + //two report is free + if (element_a->isFree() && element_b->isFree()) return true; + //Reports aren't free but are already linked between them and and already_linked is true + if (element_a->linkedElements().contains(element_b) && already_linked) return true; + + return false; + } + + case Element::Master: + { + //Type isn't good + if (element_b->linkType() != Element::Slave) return false; + //element_b is free + if (element_b->isFree()) return true; + //element_b isn't free but already linked to element_a and already_linked is true + if (element_a->linkedElements().contains(element_b) && already_linked) return true; + + return false; + } + + case Element::Slave: + { + //Type isn't good + if (element_b->linkType() != Element::Master) return false; + //Element_a is free + if (element_a->isFree()) return true; + //element_a isn't free but already linked to element_b and already_linked is true; + if (element_b->linkedElements().contains(element_a) && already_linked) return true; + + return false; + } + + case Element::Terminale: return false; + + default: return false; + } +} + +/** + * @brief LinkElementCommand::addLink + * Add elements from the list to the linked element of edited element + * This method do several check to know if element can be linked or not. + * @param element_list + */ +void LinkElementCommand::addLink(QList element_list) +{ + setUpNewLink(element_list, false); +} + +/** + * @brief LinkElementCommand::addLink + * This is an overloaded function + * @param element_ + */ +void LinkElementCommand::addLink(Element *element_) +{ + QList list; + list << element_; + addLink(list); +} + +/** + * @brief LinkElementCommand::setLink + * Replace all linked elements of edited element by elements stored in @element_list + * This method do several check to know if element can be linked or not. + * @param element_list + */ +void LinkElementCommand::setLink(QList element_list) +{ + m_linked_after.clear(); + setUpNewLink(element_list, true); +} + +/** + * @brief LinkElementCommand::setLink + * This is an overloaded function. + * @param element_ + */ +void LinkElementCommand::setLink(Element *element_) +{ + QList list; + list << element_; + setLink(list); +} + +/** + * @brief LinkElementCommand::unlink + * Unlink all elements of element_list from the edited element. + * @param element_list + */ +void LinkElementCommand::unlink(QList element_list) +{ + foreach(Element *elmt, element_list) + m_linked_after.removeAll(elmt); +} + +/** + * @brief LinkElementCommand::unlinkAll + * Unlink all element of the edited element + */ +void LinkElementCommand::unlinkAll() { + m_linked_after.clear(); +} + +/** + * @brief LinkElementCommand::undo + * Undo this command + */ +void LinkElementCommand::undo() +{ + if(m_element->diagram()) m_element->diagram()->showMe(); + makeLink(m_linked_before); + QUndoCommand::undo(); +} + +/** + * @brief LinkElementCommand::redo + * Redo this command + */ +void LinkElementCommand::redo() +{ + if(m_element->diagram()) m_element->diagram()->showMe(); + makeLink(m_linked_after); + QUndoCommand::redo(); +} + +/** + * @brief LinkElementCommand::setUpNewLink + * Update the content of m_link_after with the content of @element_list. + * Each linkable element (know via the static method isLinkable) is added to m_linked_after + * @already_link is used for the static method isLinkable. + * @param element_list + * @param already_link + */ +void LinkElementCommand::setUpNewLink(const QList &element_list, bool already_link) +{ + //m_element is a master we can connect several element to it + //if m_element isn't master (may be a report or slave) we can connect only one element + if (m_element->linkType() == Element::Master || element_list.size() == 1) + { + foreach(Element *elmt, element_list) + if (isLinkable(m_element, elmt, already_link)) + m_linked_after << elmt; + } + else + { + qDebug() << "LinkElementCommand::setUpNewLink : try to link several elements to a report element or slave element," + " only the first element of the list will be taken to be linked"; + foreach(Element *elmt, element_list) + if (isLinkable(m_element, elmt, already_link)) + { + m_linked_after << elmt; + return; + } + } +} + +/** + * @brief LinkElementCommand::makeLink + * Make the link between m_element and element_list; + * This method unlink elements if needed. + * @param element_list + */ +void LinkElementCommand::makeLink(const QList &element_list) +{ + //List is empty, that mean m_element must be free, so we unlink all elements + if (element_list.isEmpty()) + { + m_element->unlinkAllElements(); + return; + } + + //We link all element from element_list + foreach(Element *elmt, element_list) + m_element->linkToElement(elmt); + + //At this point may be there are unwanted linked elements to m_element. We must to unlink it. + //Elements from @element_list are wanted so we compare @element_list to current linked element of @m_element + QList to_unlink = m_element->linkedElements(); + foreach(Element *elmt, element_list) + to_unlink.removeAll(elmt); + + //All elements stored in to_unlink is unwanted we unlink it from m_element + if (!to_unlink.isEmpty()) + foreach(Element *elmt, to_unlink) + m_element->unlinkElement(elmt); +} diff --git a/sources/undocommand/linkelementcommand.h b/sources/undocommand/linkelementcommand.h new file mode 100644 index 000000000..c8f307e02 --- /dev/null +++ b/sources/undocommand/linkelementcommand.h @@ -0,0 +1,61 @@ +/* + Copyright 2006-2015 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 LINKELEMENTCOMMAND_H +#define LINKELEMENTCOMMAND_H + +#include + +class Element; + +/** + * @brief The LinkElementCommand class + * This undo class manage link between elements. + * In the same instance of this class, we can link and unlink elements from an edited element + * This undo class support the merge. + */ +class LinkElementCommand : public QUndoCommand +{ + public: + LinkElementCommand(Element *element_, QUndoCommand *parent = 0); + + virtual int id() const {return 2;} + virtual bool mergeWith(const QUndoCommand *other); + + static bool isLinkable (Element *element_a, Element *element_b, bool already_linked = false); + + void addLink (QList element_list); + void addLink (Element *element_); + void setLink (QList element_list); + void setLink (Element *element_); + void unlink (QList element_list); + void unlinkAll (); + + void undo(); + void redo(); + + private: + void setUpNewLink (const QList &element_list, bool already_link); + void makeLink (const QList &element_list); + + private: + Element *m_element; + QList m_linked_before; // m_linked_after; //