288 lines
8.8 KiB
C++
Raw Normal View History

/*
2020-06-15 17:42:37 +02:00
Copyright 2006-2020 The QElectroTech Team
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
QElectroTech is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
*/
#include "linkelementcommand.h"
#include "element.h"
#include "diagram.h"
#include "conductorautonumerotation.h"
#include "conductor.h"
#include "potentialselectordialog.h"
/**
2020-08-16 11:19:36 +02:00
@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_first_redo (true)
{
m_linked_before = m_linked_after = m_element->linkedElements();
setText(QObject::tr("Éditer les référence croisé", "edite the cross reference"));
}
/**
2020-08-16 11:19:36 +02:00
@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() || other->childCount()) return false;
LinkElementCommand const *undo = static_cast<const LinkElementCommand *> (other);
if (m_element != undo->m_element) return false;
m_linked_after = undo->m_linked_after;
return true;
}
/**
2020-08-16 11:19:36 +02:00
@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;
}
}
/**
2020-08-16 11:19:36 +02:00
@brief LinkElementCommand::setLink
2020-08-18 21:28:52 +02:00
Replace all linked elements of edited element
by elements stored in element_list
2020-08-16 11:19:36 +02:00
This method do several check to know if element can be linked or not.
@param element_list
*/
void LinkElementCommand::setLink(const QList<Element *>& element_list)
{
m_linked_after.clear();
setUpNewLink(element_list, true);
}
/**
2020-08-16 11:19:36 +02:00
@brief LinkElementCommand::setLink
This is an overloaded function.
@param element_
*/
void LinkElementCommand::setLink(Element *element_)
{
QList<Element *> list;
list << element_;
setLink(list);
}
/**
2020-08-16 11:19:36 +02:00
@brief LinkElementCommand::unlink
Unlink all elements of element_list from the edited element.
@param element_list
*/
void LinkElementCommand::unlink(QList<Element *> element_list)
{
foreach(Element *elmt, element_list)
m_linked_after.removeAll(elmt);
}
/**
2020-08-16 11:19:36 +02:00
@brief LinkElementCommand::unlinkAll
Unlink all element of the edited element
*/
void LinkElementCommand::unlinkAll() {
m_linked_after.clear();
}
/**
2020-08-16 11:19:36 +02:00
@brief LinkElementCommand::undo
Undo this command
*/
void LinkElementCommand::undo()
{
if(m_element->diagram()) m_element->diagram()->showMe();
makeLink(m_linked_before);
QUndoCommand::undo();
}
/**
2020-08-16 11:19:36 +02:00
@brief LinkElementCommand::redo
Redo this command
*/
void LinkElementCommand::redo()
{
if(m_element->diagram()) m_element->diagram()->showMe();
makeLink(m_linked_after);
//If the action is to link two reports together, we check if the conductors
//of the new potential have the same text, function, and protocol.
//if not, a dialog ask what do to.
if (m_first_redo && (m_element->linkType() & Element::AllReport) \
&& m_element->conductors().size() \
&& m_linked_after.size() && m_linked_after.first()->conductors().size())
{
//fill list of potential
QSet <Conductor *> c_list = m_element->conductors().first()->relatedPotentialConductors();
c_list << m_element->conductors().first();
//fill list of text
QStringList str_txt;
QStringList str_funct;
QStringList str_tens;
for (const Conductor *c : c_list)
{
str_txt << c->properties().text;
str_funct << c->properties().m_function;
str_tens << c->properties().m_tension_protocol;
str_tens << c->properties().m_wire_color;
str_tens << c->properties().m_wire_section;
}
//check text list, isn't same in potential, ask user what to do
if (!QET::eachStrIsEqual(str_txt) || !QET::eachStrIsEqual(str_funct) || !QET::eachStrIsEqual(str_tens))
{
PotentialSelectorDialog psd(m_element, this);
psd.exec();
}
m_first_redo = false;
}
QUndoCommand::redo();
}
/**
2020-08-16 11:19:36 +02:00
@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 *> &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;
}
}
}
/**
2020-08-16 11:19:36 +02:00
@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 *> &element_list)
{
2020-08-18 21:28:52 +02:00
//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);
2020-08-18 21:28:52 +02:00
/* 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<Element *> to_unlink = m_element->linkedElements();
foreach(Element *elmt, element_list)
to_unlink.removeAll(elmt);
2020-08-18 21:28:52 +02:00
//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);
}