qelectrotech-source-mirror/sources/undocommand/deleteqgraphicsitemcommand.cpp

318 lines
11 KiB
C++
Raw Normal View History

/*
Copyright 2006-2019 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 "deleteqgraphicsitemcommand.h"
#include "dynamicelementtextitem.h"
#include "diagram.h"
#include "element.h"
#include "conductor.h"
#include "conductortextitem.h"
#include "elementtextitemgroup.h"
#include "addelementtextcommand.h"
#include "terminal.h"
#include "diagramcommands.h"
#include "qetgraphicstableitem.h"
#include "qetdiagrameditor.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<DynamicElementTextItem *> 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);
}
//When remove a deti we must to know his parent item, for re-add deti as child of the parent
//when undo this command
for(DynamicElementTextItem *deti : m_removed_contents.m_element_texts)
{
if(deti->parentGroup())
m_grp_texts_hash.insert(deti, deti->parentGroup());
else
m_elmt_text_hash.insert(deti, deti->parentElement());
}
//If parent element of ElementTextItemGroup 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<ElementTextItemGroup *> group_set = m_removed_contents.m_texts_groups;
for(ElementTextItemGroup *group : group_set)
{
if(m_removed_contents.m_elements.contains(group->parentElement()))
m_removed_contents.m_texts_groups.remove(group);
}
//The deletion of the groups is not managed by this undo, but by a RemoveTextsGroupCommand
for(ElementTextItemGroup *group : m_removed_contents.m_texts_groups) {
new RemoveTextsGroupCommand(group->parentElement(), group, this);
}
m_removed_contents.m_texts_groups.clear();
setPotentialsOfRemovedElements();
//Get all linkeds table of removed table.
for (auto table : m_removed_contents.m_tables)
{
//Table is already managed, jump to next loop
if (m_table_scene_hash.keys().contains(table))
continue;
auto first_table = table; //The first table if the table is linked to another
while(first_table->previousTable())
first_table = first_table->previousTable();
auto current_table = first_table;
m_table_scene_hash.insert(first_table, first_table->scene());
while (current_table->nextTable())
{
current_table = current_table->nextTable();
m_table_scene_hash.insert(current_table, current_table->scene());
}
}
setText(QString(QObject::tr("supprimer %1", "undo caption - %1 is a sentence listing the removed content")).arg(m_removed_contents.sentence(DiagramContent::All)));
//Table is now managed by @m_table_scene_hash, we clear the tables of m_removed_content
m_removed_contents.m_tables.clear();
m_diagram->qgiManager().manage(m_removed_contents.items(DiagramContent::All));
}
DeleteQGraphicsItemCommand::~DeleteQGraphicsItemCommand() {
m_diagram->qgiManager().release(m_removed_contents.items(DiagramContent::All));
}
/**
* @brief DeleteQGraphicsItemCommand::setPotentialsOfRemovedElements
* This function creates new conductors (if needed) for conserve the electrical potentials
* present at the terminals of each removed elements.
*/
void DeleteQGraphicsItemCommand::setPotentialsOfRemovedElements()
{
for (Element *elmt : m_removed_contents.m_elements)
{
//a list of terminals who have at least two conductors docked in.
QList<Terminal *> terminals_list;
for (Terminal *t : elmt->terminals()) {
if (t->conductors().size() >= 2) {
terminals_list.append(t);
}
}
if (terminals_list.isEmpty()) {
continue;
}
for (Terminal *t : terminals_list)
{
//All new created conductors will be docked to hub_terminal
Terminal *hub_terminal = nullptr;
QList<Terminal *> terminals_to_connect_list;
for (Conductor *c : t->conductors())
{
Terminal *other_terminal = c->terminal1 == t ? c->terminal2 : c->terminal1;
if (m_removed_contents.items(DiagramContent::Elements).contains(other_terminal->parentElement()))
{
other_terminal = terminalInSamePotential(other_terminal, c);
if (other_terminal == nullptr) {
continue;
}
}
terminals_to_connect_list.append(other_terminal);
if (hub_terminal == nullptr) {
hub_terminal = other_terminal;
}
//hub_terminal must be the terminal the more at top left of the diagram.
else if (other_terminal->scenePos().x() < hub_terminal->scenePos().x()) {
hub_terminal = other_terminal;
}
else if (other_terminal->scenePos().x() == hub_terminal->scenePos().x()) {
if (other_terminal->scenePos().y() < hub_terminal->scenePos().y()) {
hub_terminal = other_terminal;
}
}
}
terminals_to_connect_list.removeAll(hub_terminal);
if (hub_terminal == nullptr || terminals_to_connect_list.isEmpty()) {
continue;
}
ConductorProperties properties = hub_terminal->conductors().first()->properties();
for (Terminal *t : terminals_to_connect_list)
{
//If a conductor was already created between these two terminals
//in this undo command, from another removed element, we do nothing
bool exist_ = false;
for (QPair<Terminal *, Terminal *> pair : m_connected_terminals)
{
if (pair.first == hub_terminal && pair.second == t) {
exist_ = true;
continue;
} else if (pair.first == t && pair.second == hub_terminal) {
exist_ = true;
continue;
}
}
if (exist_ == false)
{
m_connected_terminals.append(qMakePair<Terminal *, Terminal *>(hub_terminal, t));
Conductor *new_cond = new Conductor(hub_terminal, t);
new_cond->setProperties(properties);
new AddItemCommand<Conductor*>(new_cond, t->diagram(), QPointF(), this);
}
}
}
}
}
/**
* @brief DeleteQGraphicsItemCommand::terminalInSamePotential
* Return a terminal at the same potential of @terminal, by traveling through the conductors connected to @terminal
* only if the owner element of the terminal is not delete by this undo command.
* Return nullptr if a terminal can't be found.
* @param terminal - terminal from search
* @param conductor_to_exclude - a conductor to exlcude from search.
* @return
*/
Terminal *DeleteQGraphicsItemCommand::terminalInSamePotential(Terminal *terminal, Conductor *conductor_to_exclude)
{
QList<Conductor *> conductor_list = terminal->conductors();
conductor_list.removeAll(conductor_to_exclude);
for(Conductor *c : conductor_list)
{
Terminal *other_terminal = c->terminal1 == terminal ? c->terminal2 : c->terminal1;
if(!m_removed_contents.items(DiagramContent::Elements).contains(other_terminal->parentElement())) {
return other_terminal;
}
}
//No one of direct conductor of terminal are docked to an element which is not removed
for(Conductor *c : conductor_list)
{
Terminal *other_terminal = c->terminal1 == terminal ? c->terminal2 : c->terminal1;
Terminal *terminal_to_return = terminalInSamePotential(other_terminal, c);
if (terminal_to_return != nullptr) {
return terminal_to_return;
}
}
return nullptr;
}
/**
* @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)
{
if(m_elmt_text_hash.keys().contains(deti))
m_elmt_text_hash.value(deti)->addDynamicTextItem(deti);
else if (m_grp_texts_hash.keys().contains(deti))
{
Element *elmt = m_grp_texts_hash.value(deti)->parentElement();
elmt->addDynamicTextItem(deti);
elmt->addTextToGroup(deti, m_grp_texts_hash.value(deti));
}
}
for (auto table : m_table_scene_hash.keys())
{
if (!m_table_scene_hash.value(table).isNull()) {
m_table_scene_hash.value(table)->addItem(table);
}
}
QUndoCommand::undo();
}
/**
* @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 *> conductor_list;
conductor_list << c -> relatedPotentialConductors(false).values();
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)
{
if(deti->parentGroup() && deti->parentGroup()->parentElement())
deti->parentGroup()->parentElement()->removeTextFromGroup(deti, deti->parentGroup());
deti->parentElement()->removeDynamicTextItem(deti);
deti->setParentItem(nullptr);
}
for (auto table : m_table_scene_hash.keys())
{
if (!m_table_scene_hash.value(table).isNull()) {
m_table_scene_hash.value(table)->removeItem(table);
}
}
for(QGraphicsItem *item : m_removed_contents.items())
m_diagram->removeItem(item);
QUndoCommand::redo();
}