diff --git a/sources/TerminalStrip/UndoCommand/bridgeterminalscommand.cpp b/sources/TerminalStrip/UndoCommand/bridgeterminalscommand.cpp new file mode 100644 index 000000000..425adc29c --- /dev/null +++ b/sources/TerminalStrip/UndoCommand/bridgeterminalscommand.cpp @@ -0,0 +1,71 @@ +/* + Copyright 2006-2021 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 "bridgeterminalscommand.h" + +BridgeTerminalsCommand::BridgeTerminalsCommand(TerminalStrip *strip, + QVector> real_terminal, + QUndoCommand *parent): + QUndoCommand(parent), + m_strip(strip), + m_real_terminal_vector(real_terminal) +{ + setText(QObject::tr("Ponter des bornes entre-elles")); +} + +void BridgeTerminalsCommand::undo() +{ + if (m_strip) { + m_strip->unBridge(m_real_terminal_vector); + } +} + +void BridgeTerminalsCommand::redo() +{ + if (m_strip) { + m_strip->setBridge(m_real_terminal_vector); + } +} + +UnBridgeTerminalsCommand::UnBridgeTerminalsCommand(TerminalStrip *strip, + QVector> real_terminal, + QUndoCommand *parent): + QUndoCommand(parent), + m_strip(strip) +{ + setText(QObject::tr("Supprimer des ponts de bornes")); + + if (strip->canUnBridge(real_terminal)) + { + m_terminals = real_terminal; + m_bridge = strip->isBridged(real_terminal.first()); + } +} + +void UnBridgeTerminalsCommand::undo() +{ + if (m_strip && m_bridge) { + m_strip->setBridge(m_bridge, m_terminals); + } +} + +void UnBridgeTerminalsCommand::redo() +{ + if (m_strip) { + m_strip->unBridge(m_terminals); + } +} diff --git a/sources/TerminalStrip/UndoCommand/bridgeterminalscommand.h b/sources/TerminalStrip/UndoCommand/bridgeterminalscommand.h new file mode 100644 index 000000000..ec1fcfef4 --- /dev/null +++ b/sources/TerminalStrip/UndoCommand/bridgeterminalscommand.h @@ -0,0 +1,68 @@ +/* + Copyright 2006-2021 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 BRIDGETERMINALSCOMMAND_H +#define BRIDGETERMINALSCOMMAND_H + +#include +#include +#include +#include + +#include "../terminalstrip.h" + +/** + * @brief The BridgeTerminalsCommand class + * UndoCommand use to create bridge betwen terminals + * of a terminals strip + */ +class BridgeTerminalsCommand : public QUndoCommand +{ + public: + BridgeTerminalsCommand(TerminalStrip *strip, QVector> real_terminal, QUndoCommand *parent = nullptr); + ~BridgeTerminalsCommand() override {} + + void undo() override; + void redo() override; + + private: + QPointer m_strip; + QVector> m_real_terminal_vector; +}; + + +/** + * @brief The UnBridgeTerminalsCommand class + * UndoCommand use to remove bridge betwen terminals + * of a terminals strip + */ +class UnBridgeTerminalsCommand : public QUndoCommand +{ + public: + UnBridgeTerminalsCommand(TerminalStrip *strip, QVector> real_terminal, QUndoCommand *parent = nullptr); + ~UnBridgeTerminalsCommand() override{} + + void undo() override; + void redo() override; + + private: + QPointer m_strip; + QSharedPointer m_bridge; + QVector> m_terminals; +}; + +#endif // BRIDGETERMINALSCOMMAND_H diff --git a/sources/TerminalStrip/UndoCommand/changeterminallevel.cpp b/sources/TerminalStrip/UndoCommand/changeterminallevel.cpp index 42c5dceba..c00ba6d46 100644 --- a/sources/TerminalStrip/UndoCommand/changeterminallevel.cpp +++ b/sources/TerminalStrip/UndoCommand/changeterminallevel.cpp @@ -16,16 +16,17 @@ along with QElectroTech. If not, see . */ #include "changeterminallevel.h" +#include "../realterminal.h" ChangeTerminalLevel::ChangeTerminalLevel(TerminalStrip *strip, - const RealTerminalData &real_terminal, + const QWeakPointer &real_terminal, int level, QUndoCommand *parent) : QUndoCommand(parent), m_strip(strip), m_real_terminal(real_terminal), m_new_level(level), - m_old_level(real_terminal.level_) + m_old_level(real_terminal.toStrongRef()->level()) {} void ChangeTerminalLevel::undo() diff --git a/sources/TerminalStrip/UndoCommand/changeterminallevel.h b/sources/TerminalStrip/UndoCommand/changeterminallevel.h index 39b9a3c1a..248695161 100644 --- a/sources/TerminalStrip/UndoCommand/changeterminallevel.h +++ b/sources/TerminalStrip/UndoCommand/changeterminallevel.h @@ -26,7 +26,7 @@ class ChangeTerminalLevel : public QUndoCommand { public: ChangeTerminalLevel(TerminalStrip *strip, - const RealTerminalData &real_terminal, + const QWeakPointer &real_terminal, int level, QUndoCommand *parent = nullptr); @@ -35,7 +35,7 @@ class ChangeTerminalLevel : public QUndoCommand private: QPointer m_strip; - RealTerminalData m_real_terminal; + QWeakPointer m_real_terminal; int m_new_level, m_old_level; }; diff --git a/sources/TerminalStrip/UndoCommand/changeterminalstripcolor.cpp b/sources/TerminalStrip/UndoCommand/changeterminalstripcolor.cpp new file mode 100644 index 000000000..17507f159 --- /dev/null +++ b/sources/TerminalStrip/UndoCommand/changeterminalstripcolor.cpp @@ -0,0 +1,51 @@ +/* + Copyright 2006-2021 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 "changeterminalstripcolor.h" +#include "../terminalstripbridge.h" + +/** + * @brief ChangeTerminalStripColor::ChangeTerminalStripColor + * @param bridge + * @param color + * @param parent + */ +ChangeTerminalStripColor::ChangeTerminalStripColor(QSharedPointer bridge, + const QColor &color, + QUndoCommand *parent): + QUndoCommand(parent), + m_bridge(bridge), + m_new_color(color) +{ + if (m_bridge) { + m_old_color = m_bridge->color(); + } +} + +void ChangeTerminalStripColor::redo() +{ + if (m_bridge) { + m_bridge->setColor(m_new_color); + } +} + +void ChangeTerminalStripColor::undo() +{ + if (m_bridge) { + m_bridge->setColor(m_old_color); + } +} diff --git a/sources/TerminalStrip/UndoCommand/changeterminalstripcolor.h b/sources/TerminalStrip/UndoCommand/changeterminalstripcolor.h new file mode 100644 index 000000000..bb7b372a5 --- /dev/null +++ b/sources/TerminalStrip/UndoCommand/changeterminalstripcolor.h @@ -0,0 +1,45 @@ +/* + Copyright 2006-2021 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 CHANGETERMINALSTRIPCOLOR_H +#define CHANGETERMINALSTRIPCOLOR_H + +#include +#include +#include + +class TerminalStripBridge; + +/** + * @brief The ChangeTerminalStripColor class + */ +class ChangeTerminalStripColor : public QUndoCommand +{ + public: + ChangeTerminalStripColor(QSharedPointer bridge, + const QColor &color, + QUndoCommand *parent = nullptr); + + void redo() override; + void undo() override; + + private: + QSharedPointer m_bridge; + QColor m_old_color, m_new_color; +}; + +#endif // CHANGETERMINALSTRIPCOLOR_H diff --git a/sources/TerminalStrip/UndoCommand/groupterminalscommand.cpp b/sources/TerminalStrip/UndoCommand/groupterminalscommand.cpp index 1ded81741..e3a74d0bf 100644 --- a/sources/TerminalStrip/UndoCommand/groupterminalscommand.cpp +++ b/sources/TerminalStrip/UndoCommand/groupterminalscommand.cpp @@ -16,6 +16,7 @@ along with QElectroTech. If not, see . */ #include "groupterminalscommand.h" +#include "../physicalterminal.h" /** * @brief GroupTerminalsCommand::GroupTerminalsCommand @@ -24,8 +25,8 @@ * @param to_group : Terminals to group */ GroupTerminalsCommand::GroupTerminalsCommand(TerminalStrip *strip, - const PhysicalTerminalData &receiver_, - const QVector &to_group, + const QSharedPointer &receiver_, + const QVector> &to_group, QUndoCommand *parent): QUndoCommand(parent), m_terminal_strip(strip), @@ -43,12 +44,12 @@ void GroupTerminalsCommand::undo() { void GroupTerminalsCommand::redo() { if (m_terminal_strip) { - m_terminal_strip->groupTerminals(m_receiver, m_to_group); + m_terminal_strip->groupTerminals(m_receiver,m_to_group); } } UnGroupTerminalsCommand::UnGroupTerminalsCommand(TerminalStrip *strip, - const QVector &to_ungroup, + const QVector> &to_ungroup, QUndoCommand *parent) : QUndoCommand(parent), m_terminal_strip(strip) @@ -77,19 +78,21 @@ void UnGroupTerminalsCommand::redo() } } -void UnGroupTerminalsCommand::setUp(const QVector &to_ungroup) +void UnGroupTerminalsCommand::setUp(const QVector> &to_ungroup) { - for (auto rtd_ : to_ungroup) + for (const auto &rt_ : to_ungroup) { - auto ptd_ = m_terminal_strip->physicalTerminalData(rtd_); + auto phy_t = m_terminal_strip->physicalTerminal(rt_.toWeakRef()); + if (phy_t) + { + //Physical have only one real terminal, no need to ungroup it + if (phy_t->realTerminalCount() <= 1) { + continue; + } - //Physical have only one real terminal, no need to ungroup it - if (ptd_.real_terminals_vector.size() <= 1) { - continue; + auto vector_ = m_physical_real_H.value(phy_t); + vector_.append(rt_); + m_physical_real_H.insert(phy_t, vector_); } - - auto vector_ = m_physical_real_H.value(ptd_); - vector_.append(rtd_); - m_physical_real_H.insert(ptd_, vector_); } } diff --git a/sources/TerminalStrip/UndoCommand/groupterminalscommand.h b/sources/TerminalStrip/UndoCommand/groupterminalscommand.h index 9ef37b19d..6267d3db6 100644 --- a/sources/TerminalStrip/UndoCommand/groupterminalscommand.h +++ b/sources/TerminalStrip/UndoCommand/groupterminalscommand.h @@ -31,8 +31,8 @@ class GroupTerminalsCommand : public QUndoCommand { public: GroupTerminalsCommand(TerminalStrip *strip, - const PhysicalTerminalData &receiver_, - const QVector &to_group, + const QSharedPointer &receiver_, + const QVector> &to_group, QUndoCommand *parent = nullptr); void undo() override; @@ -40,8 +40,8 @@ class GroupTerminalsCommand : public QUndoCommand private: QPointer m_terminal_strip; - PhysicalTerminalData m_receiver; - QVector m_to_group; + QSharedPointer m_receiver; + QVector> m_to_group; }; /** @@ -52,18 +52,18 @@ class UnGroupTerminalsCommand : public QUndoCommand { public: UnGroupTerminalsCommand(TerminalStrip *strip, - const QVector &to_ungroup, + const QVector> &to_ungroup, QUndoCommand *parent = nullptr); void undo() override; void redo() override; private: - void setUp(const QVector &to_ungroup); + void setUp(const QVector> &to_ungroup); private: QPointer m_terminal_strip; - QHash > m_physical_real_H; + QHash , QVector>> m_physical_real_H; }; #endif // GROUPTERMINALSCOMMAND_H diff --git a/sources/TerminalStrip/UndoCommand/sortterminalstripcommand.cpp b/sources/TerminalStrip/UndoCommand/sortterminalstripcommand.cpp index 538a5e516..50eb4ff45 100644 --- a/sources/TerminalStrip/UndoCommand/sortterminalstripcommand.cpp +++ b/sources/TerminalStrip/UndoCommand/sortterminalstripcommand.cpp @@ -17,13 +17,16 @@ */ #include "sortterminalstripcommand.h" #include "../terminalstrip.h" +#include "../physicalterminal.h" +#include "../realterminal.h" SortTerminalStripCommand::SortTerminalStripCommand(TerminalStrip *strip, QUndoCommand *parent) : QUndoCommand(parent), m_strip(strip) { setText(QObject::tr("Trier le bornier %1").arg(m_strip->name())); - m_old_order = m_new_order = m_strip->physicalTerminalData(); + m_old_order = m_strip->physicalTerminal(); + m_new_order = m_strip->physicalTerminal(); sort(); } @@ -43,7 +46,7 @@ void SortTerminalStripCommand::redo() void SortTerminalStripCommand::sort() { - std::sort(m_new_order.begin(), m_new_order.end(), [](PhysicalTerminalData arg1, PhysicalTerminalData arg2) + std::sort(m_new_order.begin(), m_new_order.end(), [](QSharedPointer arg1, QSharedPointer arg2) { const QRegularExpression rx(QStringLiteral("^\\d+")); @@ -52,9 +55,9 @@ void SortTerminalStripCommand::sort() int int1 =-1; int int2 =-1; - if (arg1.real_terminals_vector.count()) + if (arg1->realTerminalCount()) { - str1 = arg1.real_terminals_vector.constLast().label_; + str1 = arg1->realTerminals().constLast()->label(); auto match = rx.match(str1); if (match.hasMatch()) { @@ -62,9 +65,9 @@ void SortTerminalStripCommand::sort() } } - if (arg2.real_terminals_vector.count()) + if (arg2->realTerminalCount()) { - str2 = arg2.real_terminals_vector.constLast().label_; + str2 = arg2->realTerminals().constLast()->label(); auto match = rx.match(str2); if (match.hasMatch()) { diff --git a/sources/TerminalStrip/UndoCommand/sortterminalstripcommand.h b/sources/TerminalStrip/UndoCommand/sortterminalstripcommand.h index fe14c2364..5c2fd6d65 100644 --- a/sources/TerminalStrip/UndoCommand/sortterminalstripcommand.h +++ b/sources/TerminalStrip/UndoCommand/sortterminalstripcommand.h @@ -23,7 +23,7 @@ #include class TerminalStrip; -struct PhysicalTerminalData; +class PhysicalTerminal; /** * @brief The SortTerminalStripCommand class @@ -43,8 +43,8 @@ class SortTerminalStripCommand : public QUndoCommand private: QPointer m_strip; - QVector m_old_order, - m_new_order; + QVector> m_old_order, + m_new_order; }; #endif // SORTTERMINALSTRIPCOMMAND_H diff --git a/sources/TerminalStrip/physicalterminal.cpp b/sources/TerminalStrip/physicalterminal.cpp new file mode 100644 index 000000000..f633d45f1 --- /dev/null +++ b/sources/TerminalStrip/physicalterminal.cpp @@ -0,0 +1,176 @@ +/* + Copyright 2006-2021 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 "physicalterminal.h" +#include "realterminal.h" +#include "terminalstrip.h" + +/** + * @brief PhysicalTerminal + * @param parent_strip : Parent terminal strip + * @param terminals : A vector of real terminals + * who compose this physical terminal. + * \p terminals must have at least one terminal + */ +PhysicalTerminal::PhysicalTerminal(TerminalStrip *parent_strip, + QVector> terminals) : + m_parent_terminal_strip(parent_strip), + m_real_terminal(terminals) +{} + +/** + * @brief PhysicalTerminal::sharedRef + * @return a QSharedPointer of this + */ +QSharedPointer PhysicalTerminal::sharedRef() +{ + QSharedPointer this_shared(this->weakRef()); + if (this_shared.isNull()) + { + this_shared = QSharedPointer(this); + m_this_weak = this_shared.toWeakRef(); + } + + return this_shared; +} + +/** + * @brief PhysicalTerminal::weakRef + * @return a QWeakPointer of this, weak pointer can be null + */ +QWeakPointer PhysicalTerminal::weakRef() { + return m_this_weak; +} + +/** + * @brief toXml + * @param parent_document + * @return this physical terminal to xml + */ +QDomElement PhysicalTerminal::toXml(QDomDocument &parent_document) const +{ + auto root_elmt = parent_document.createElement(this->xmlTagName()); + for (auto &real_t : m_real_terminal) { + root_elmt.appendChild(real_t->toXml(parent_document)); + } + + return root_elmt; +} + +/** + * @brief setTerminals + * Set the RealTerminal who compose this physical terminal. + * The position of the RealTerminal in @a terminals + * represent the level of these in this physical terminal. + * @param terminals + */ +void PhysicalTerminal::setTerminals(const QVector> &terminals) { + m_real_terminal = terminals; +} + +/** + * @brief addTerminals + * Append the real terminal @a terminal + * to this physical terminal. + * @param terminal + */ +void PhysicalTerminal::addTerminal(const QSharedPointer &terminal) { + m_real_terminal.append(terminal); +} + +/** + * @brief removeTerminal + * Remove @a terminal from the list of real terminal + * @param terminal + * @return true if sucessfully removed + */ +bool PhysicalTerminal::removeTerminal(const QSharedPointer &terminal) { + return m_real_terminal.removeOne(terminal); +} + +/** + * @brief setLevelOf + * Change the level of \p terminal + * @param terminal + * @param level + */ +bool PhysicalTerminal::setLevelOf(const QSharedPointer &terminal, int level) +{ + const int i = m_real_terminal.indexOf(terminal); + if (i >= 0) + { +#if QT_VERSION >= QT_VERSION_CHECK(5,14,0) + m_real_terminal.swapItemsAt(i, std::min(level, m_real_terminal.size()-1)); +#else + auto j = std::min(level, m_real_terminal.size()-1); + std::swap(m_real_terminal.begin()[i], m_real_terminal.begin()[j]); +#endif + return true; + } + return false; +} + +/** + * @brief levelCount + * @return the number of level of this terminal + */ +int PhysicalTerminal::levelCount() const { + return m_real_terminal.size(); +} + +/** + * @brief levelOf + * @param terminal + * @return the level of real terminal \p terminal or + * -1 if \terminal is not a part of this physicalTerminal + */ +int PhysicalTerminal::levelOf(const QSharedPointer &terminal) const { + return m_real_terminal.indexOf(terminal); +} + +/** + * @brief terminals + * @return A vector of RealTerminal who compose this PhysicalTerminal + */ +QVector> PhysicalTerminal::realTerminals() const { + return m_real_terminal; +} + +/** + * @brief uuid + * @return the uuid of this physical terminal + */ +QUuid PhysicalTerminal::uuid() const { + return m_uuid; +} + +int PhysicalTerminal::pos() const +{ + if (m_parent_terminal_strip) { + return m_parent_terminal_strip->pos(m_this_weak); + } else { + return -1; + } +} + +int PhysicalTerminal::realTerminalCount() const { + return m_real_terminal.size(); +} + +QString PhysicalTerminal::xmlTagName() { + return QStringLiteral("physical_terminal"); +} diff --git a/sources/TerminalStrip/physicalterminal.h b/sources/TerminalStrip/physicalterminal.h new file mode 100644 index 000000000..44e800dae --- /dev/null +++ b/sources/TerminalStrip/physicalterminal.h @@ -0,0 +1,96 @@ +/* + Copyright 2006-2021 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 PHYSICALTERMINAL_H +#define PHYSICALTERMINAL_H + +#include +#include +#include +#include + +class RealTerminal; +class TerminalStrip; + +/** + * @brief The PhysicalTerminal class + * Represent a physical terminal. + * A physical terminal is composed a least by one RealTerminal. + * When a physical terminal have more than one real terminal + * that mean the physical terminal have levels (one by real terminal). + * The index of real terminals returned by the function terminals() + * is the same as the real level of the real terminal, the index are from back to front. + * + * Example for a 3 levels terminal. + * index 0 = back (mounting plate) + * index 1 = middle + * index 2 = front (electrical cabinet door) + * + * m + * o _ + * u | | + * n | | _ + * t | || | + * i | || | _ + * n | || || | d + * g |0||1||2| o + * | || ||_| o + * p | || | r + * l | ||_| + * a | | + * t |_| + * e + * + * + */ +class PhysicalTerminal +{ + friend class TerminalStrip; + + private: + PhysicalTerminal(TerminalStrip *parent_strip, QVector> terminals); + QSharedPointer sharedRef(); + QWeakPointer weakRef(); + + QDomElement toXml(QDomDocument &parent_document) const; + + void setTerminals(const QVector> &terminals); + void addTerminal(const QSharedPointer &terminal); + bool removeTerminal(const QSharedPointer &terminal); + + bool setLevelOf(const QSharedPointer &terminal, int level); + + public: + PhysicalTerminal(){} + + int levelCount() const; + int levelOf(const QSharedPointer &terminal) const; + QVector> realTerminals() const; + QUuid uuid() const; + int pos() const; + int realTerminalCount() const; + + static QString xmlTagName(); + + private: + QPointer m_parent_terminal_strip; + QVector> m_real_terminal; + QUuid m_uuid = QUuid::createUuid(); + QWeakPointer m_this_weak; +}; + +#endif // PHYSICALTERMINAL_H diff --git a/sources/TerminalStrip/realterminal.cpp b/sources/TerminalStrip/realterminal.cpp new file mode 100644 index 000000000..7c3f06356 --- /dev/null +++ b/sources/TerminalStrip/realterminal.cpp @@ -0,0 +1,286 @@ +/* + Copyright 2006-2021 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 "realterminal.h" +#include "terminalstrip.h" +#include "../qetgraphicsitem/terminalelement.h" +#include "physicalterminal.h" + +/** + * @brief RealTerminal + * @param parent_strip : parent terminal strip + * @param terminal : terminal element (if any) in a folio + */ +RealTerminal::RealTerminal(TerminalStrip *parent_strip, + Element *terminal) : + m_element(terminal), + m_parent_terminal_strip(parent_strip) +{} + +/** + * @brief RealTerminal::sharedRef + * @return a QSharedPointer of this + */ +QSharedPointer RealTerminal::sharedRef() +{ + QSharedPointer this_shared(this->weakRef()); + if (this_shared.isNull()) + { + this_shared = QSharedPointer(this); + m_this_weak = this_shared.toWeakRef(); + } + + return this_shared; +} + +/** + * @brief RealTerminal::weakRef + * @return a QWeakPointer of this, weak pointer can be bull + */ +QWeakPointer RealTerminal::weakRef() { + return m_this_weak; +} + +/** + * @brief fromXml + * @param xml_element + * @return + */ +bool RealTerminal::fromXml(QDomElement xml_element, const QVector &terminal_vector) +{ + if (xml_element.tagName() != xmlTagName()) { + return true; + } + + auto is_draw = xml_element.attribute(QStringLiteral("is_draw")) == QLatin1String("true") + ? true : false; + + QUuid uuid_(xml_element.attribute(QStringLiteral("uuid"))); + + if (is_draw) { + for (auto terminal : terminal_vector) { + if (terminal->uuid() == uuid_) + { + m_element = terminal; + break; + } + } + } else { + m_uuid = uuid_; + } + + return true; +} + +/** + * @brief toXml + * @param parent_document + * @return this real terminal to xml + */ +QDomElement RealTerminal::toXml(QDomDocument &parent_document) const +{ + auto root_elmt = parent_document.createElement(this->xmlTagName()); + root_elmt.setAttribute("is_draw", m_element ? "true" : "false"); + root_elmt.setAttribute("uuid", m_element ? m_element->uuid().toString() : + m_uuid.toString()); + + return root_elmt; +} + +/** + * @brief parentStrip + * @return parent terminal strip + */ +TerminalStrip *RealTerminal::parentStrip() const { + return m_parent_terminal_strip.data(); +} + +/** + * @brief RealTerminal::level + * @return + */ +int RealTerminal::level() const +{ + if (m_parent_terminal_strip) { + const auto phy_t = m_parent_terminal_strip->physicalTerminal(m_this_weak); + if (phy_t) { + return phy_t->levelOf(m_this_weak); + } + } + + return -1; +} + +/** + * @brief label + * @return the label of this real terminal + */ +QString RealTerminal::label() const { + if (!m_element.isNull()) { + return m_element->actualLabel(); + } else { + return QLatin1String(); + } +} + +/** + * @brief RealTerminal::Xref + * @return Conveniant method to get the XRef + * formated to string + */ +QString RealTerminal::Xref() const +{ + if (!m_element.isNull()) { + return autonum::AssignVariables::genericXref(m_element.data()); + } else { + return QString(); + } +} + +/** + * @brief RealTerminal::cable + * @return + */ +QString RealTerminal::cable() const { + return QString(); +} + +/** + * @brief RealTerminal::cableWire + * @return + */ +QString RealTerminal::cableWire() const { + return QString(); +} + +/** + * @brief RealTerminal::conductor + * @return + */ +QString RealTerminal::conductor() const { + return QString(); +} + +/** + * @brief RealTerminal::type + * @return + */ +ElementData::TerminalType RealTerminal::type() const { + if (m_element) { + return m_element->elementData().terminalType(); + } else { + return ElementData::TTGeneric; + } +} + +/** + * @brief RealTerminal::function + * @return + */ +ElementData::TerminalFunction RealTerminal::function() const { + if (m_element) { + return m_element->elementData().terminalFunction(); + } else { + return ElementData::TFGeneric; + } +} + +/** + * @brief RealTerminal::isLed + * @return + */ +bool RealTerminal::isLed() const { + if (m_element) { + return m_element->elementData().terminalLed(); + } else { + return false; + } +} + +/** + * @brief isElement + * @return true if this real terminal is linked to a terminal element + */ +bool RealTerminal::isElement() const { + return m_element.isNull() ? false : true; +} + +/** + * @brief RealTerminal::isBridged + * @return true if is bridged. + * @sa TerminalStrip::isBridged + */ +bool RealTerminal::isBridged() const +{ + if (m_parent_terminal_strip) { + return !m_parent_terminal_strip->isBridged(m_this_weak.toStrongRef()).isNull(); + } else { + return false; + } +} + +/** + * @brief RealTerminal::bridge + * @return + */ +QSharedPointer RealTerminal::bridge() const +{ + if (m_parent_terminal_strip) { + return m_parent_terminal_strip->isBridged(m_this_weak.toStrongRef()); + } else { + return QSharedPointer(); + } +} + +/** + * @brief element + * @return the element linked to this real terminal + * or nullptr if not linked to an Element. + */ +Element *RealTerminal::element() const { + return m_element.data(); +} + +/** + * @brief elementUuid + * @return if this real terminal is an element + * in a folio, return the uuid of the element + * else return a null uuid. + */ +QUuid RealTerminal::elementUuid() const { + if (!m_element.isNull()) { + return m_element->uuid(); + } else { + return QUuid(); + } +} + +/** + * @brief uuid + * @return the uuid of this real terminal + */ +QUuid RealTerminal::uuid() const { + return m_uuid; +} + +/** + * @brief RealTerminal::RealTerminal::xmlTagName + * @return + */ +QString RealTerminal::RealTerminal::xmlTagName() { + return QStringLiteral("real_terminal"); +} diff --git a/sources/TerminalStrip/realterminal.h b/sources/TerminalStrip/realterminal.h new file mode 100644 index 000000000..36f0cc924 --- /dev/null +++ b/sources/TerminalStrip/realterminal.h @@ -0,0 +1,86 @@ +/* + Copyright 2006-2021 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 REALTERMINAL_H +#define REALTERMINAL_H + +#include +#include +#include "../properties/elementdata.h" + +class TerminalStrip; +class Element; +class TerminalElement; +class PhysicalTerminal; +class TerminalStripBridge; + +/** + * @brief The RealTerminal class + * Represent a real terminal. + * A real terminal can be a drawed terminal in a folio + * or a terminal set by user but not present + * on any folio (for example a reserved terminal). + * + * When create a new instance of RealTerminal you must + * call sharedRef() and only use the returned QSharedPointer + * instead of the raw pointer + */ +class RealTerminal +{ + friend class TerminalStrip; + friend class PhysicalTerminal; + + private: + RealTerminal(TerminalStrip *strip, Element *element = nullptr); + QSharedPointer sharedRef(); + QWeakPointer weakRef(); + + bool fromXml(QDomElement xml_element, const QVector &terminal_vector); + QDomElement toXml(QDomDocument &parent_document) const; + + public: + TerminalStrip *parentStrip() const; + int level() const; + QString label() const; + QString Xref() const; + QString cable() const; + QString cableWire() const; + QString conductor() const; + + ElementData::TerminalType type() const; + ElementData::TerminalFunction function() const; + + bool isLed() const; + bool isElement() const; + bool isBridged() const; + + QSharedPointer bridge() const; + + Element* element() const; + QUuid elementUuid() const; + QUuid uuid() const; + + static QString xmlTagName(); + + private : + QPointer m_element; + QPointer m_parent_terminal_strip; + QUuid m_uuid = QUuid::createUuid(); + QWeakPointer m_this_weak; +}; + +#endif // REALTERMINAL_H diff --git a/sources/TerminalStrip/terminalstrip.cpp b/sources/TerminalStrip/terminalstrip.cpp index 02fac72e9..04898f92f 100644 --- a/sources/TerminalStrip/terminalstrip.cpp +++ b/sources/TerminalStrip/terminalstrip.cpp @@ -1,4 +1,4 @@ -/* +/* Copyright 2006-2021 The QElectroTech Team This file is part of QElectroTech. @@ -22,344 +22,13 @@ #include "../elementprovider.h" #include "../qetxml.h" #include "../autoNum/assignvariables.h" +#include "physicalterminal.h" +#include "realterminal.h" +#include "terminalstripbridge.h" using shared_real_terminal = QSharedPointer; using shared_physical_terminal = QSharedPointer; - -/************************************************************************************/ -/************************************************************************************/ -/************************************************************************************/ -/************************************************************************************/ -/************************************************************************************/ - -/** - * @brief The RealTerminal class - * Represent a real terminal. - * A real terminal can be a drawed terminal in a folio - * or a terminal set by user but not present - * on any folio (for example a reserved terminal). - */ -class RealTerminal -{ - public : - - /** - * @brief RealTerminal - * @param parent_strip : parent terminal strip - * @param terminal : terminal element (if any) in a folio - */ - RealTerminal(TerminalStrip *parent_strip, Element *terminal = nullptr) : - m_element(terminal), - m_parent_terminal_strip(parent_strip) - {} - - /** - * @brief isElement - * @return true if this real terminal is linked to a terminal element - */ - bool isElement() const { - return m_element.isNull() ? false : true; - } - - /** - * @brief element - * @return the element linked to this real terminal - * or nullptr if not linked to an Element. - */ - Element *element() const { - return m_element.data(); - } - - /** - * @brief label - * @return the label of this real terminal - */ - QString label() const { - if (!m_element.isNull()) { - return m_element->actualLabel(); - } else { - return QStringLiteral(""); - } - } - - ElementData::TerminalType type() const { - if (m_element) { - return m_element->elementData().terminalType(); - } else { - return ElementData::TTGeneric; - } - } - - ElementData::TerminalFunction function() const { - if (m_element) { - return m_element->elementData().terminalFunction(); - } else { - return ElementData::TFGeneric; - } - } - - bool led() const { - if (m_element) { - return m_element->elementData().terminalLed(); - } else { - return false; - } - } - - /** - * @brief elementUuid - * @return if this real terminal is an element - * in a folio, return the uuid of the element - * else return a null uuid. - */ - QUuid elementUuid() const { - if (!m_element.isNull()) { - return m_element->uuid(); - } else { - return QUuid(); - } - } - - /** - * @brief uuid - * @return the uuid of this real terminal - */ - QUuid uuid() const { - return m_uuid; - } - - static QString xmlTagName() { - return QStringLiteral("real_terminal"); - } - - /** - * @brief toXml - * @param parent_document - * @return this real terminal to xml - */ - QDomElement toXml(QDomDocument &parent_document) const - { - auto root_elmt = parent_document.createElement(this->xmlTagName()); - root_elmt.setAttribute("is_draw", m_element ? "true" : "false"); - root_elmt.setAttribute("uuid", m_element ? m_element->uuid().toString() : - m_uuid.toString()); - - return root_elmt; - } - - /** - * @brief fromXml - * @param xml_element - * @return - */ - bool fromXml(QDomElement xml_element, const QVector &terminal_vector) - { - if (xml_element.tagName() != xmlTagName()) { - return true; - } - - auto is_draw = xml_element.attribute(QStringLiteral("is_draw")) == QLatin1String("true") - ? true : false; - - QUuid uuid_(xml_element.attribute(QStringLiteral("uuid"))); - - if (is_draw) { - for (auto terminal : terminal_vector) { - if (terminal->uuid() == uuid_) - { - m_element = terminal; - break; - } - } - } else { - m_uuid = uuid_; - } - - return true; - } - - private : - QPointer m_element; - QPointer m_parent_terminal_strip; - QUuid m_uuid = QUuid::createUuid(); -}; - - -/************************************************************************************/ -/************************************************************************************/ -/************************************************************************************/ -/************************************************************************************/ -/************************************************************************************/ - - - - -/** - * @brief The PhysicalTerminal class - * Represent a physical terminal. - * A physical terminal is composed a least by one real terminal. - * When a physical terminal have more than one real terminal - * that mean the physical terminal have levels (one by real terminal). - * The index of terminals returned by the function terminals() - * is the same as the real level of the physical terminal, the index are from back to front. - * - * Example for a 3 levels terminal. - * index 0 = back (mounting plate) - * index 1 = middle - * index 2 = front (electrical cabinet door) - * - * m - * o _ - * u | | - * n | | _ - * t | || | - * i | || | _ - * n | || || | d - * g |0||1||2| o - * | || ||_| o - * p | || | r - * l | ||_| - * a | | - * t |_| - * e - * - */ -class PhysicalTerminal -{ - public: - /** - * @brief PhysicalTerminal - * @param parent_strip : Parent terminal strip - * @param terminals : A vector of real terminals - * who compose this physical terminal. - * \p terminals must have at least one terminal - */ - PhysicalTerminal(TerminalStrip *parent_strip, - QVector terminals) : - m_parent_terminal_strip(parent_strip), - m_real_terminal(terminals) - {} - - /** - * @brief setTerminals - * Set the real terminal of this physical terminal - * the order of the terminal in \p terminals represent - * the level index. - * @param terminals - */ - void setTerminals(QVector terminals) { - m_real_terminal = terminals; - } - - /** - * @brief addTerminals - * Append the real terminal \p terminal - * to this physical terminal. - * @param terminal - */ - void addTerminal(shared_real_terminal terminal) { - m_real_terminal.append(terminal); - } - - /** - * @brief removeTerminal - * Remove \p terminal from the list of real terminal - * @param terminal - * @return true if sucessfully removed - */ - bool removeTerminal(shared_real_terminal terminal) { - return m_real_terminal.removeOne(terminal); - } - - /** - * @brief levelCount - * @return the number of level of this terminal - */ - int levelCount() const { - return m_real_terminal.size(); - } - - /** - * @brief levelOf - * @param terminal - * @return the level of real terminal \p terminal or - * -1 if \terminal is not a part of this physicalTerminal - */ - int levelOf(shared_real_terminal terminal) const { - return m_real_terminal.indexOf(terminal); - } - - /** - * @brief setLevelOf - * Change the level of \p terminal - * @param terminal - * @param level - */ - bool setLevelOf(shared_real_terminal terminal, int level) - { - const int i = m_real_terminal.indexOf(terminal); - if (i >= 0) - { -#if QT_VERSION >= QT_VERSION_CHECK(5,14,0) - m_real_terminal.swapItemsAt(i, std::min(level, m_real_terminal.size()-1)); -#else - auto j = std::min(level, m_real_terminal.size()-1); - std::swap(m_real_terminal.begin()[i], m_real_terminal.begin()[j]); -#endif - return true; - } - return false; - } - - /** - * @brief terminals - * @return A vector of real terminal who compose this physical terminal - */ - QVector terminals() const { - return m_real_terminal; - } - - /** - * @brief uuid - * @return the uuid of this physical terminal - */ - QUuid uuid() const { - return m_uuid; - } - - static QString xmlTagName() { - return QStringLiteral("physical_terminal"); - } - - /** - * @brief toXml - * @param parent_document - * @return this physical terminal to xml - */ - QDomElement toXml(QDomDocument &parent_document) const - { - auto root_elmt = parent_document.createElement(this->xmlTagName()); - for (auto &real_t : m_real_terminal) { - root_elmt.appendChild(real_t->toXml(parent_document)); - } - - return root_elmt; - } - - private: - QPointer m_parent_terminal_strip; - QVector m_real_terminal; - const QUuid m_uuid = QUuid::createUuid(); -}; - - -/************************************************************************************/ -/************************************************************************************/ -/************************************************************************************/ -/************************************************************************************/ -/************************************************************************************/ - /** * @brief TerminalStrip::TerminalStrip * @param project @@ -415,17 +84,14 @@ TerminalStripData TerminalStrip::data() const { /** * @brief TerminalStrip::setData - * The internal data of this strip to data. + * Set the internal data of this strip to @a data. * the uuid of the new data is set to the uuid * of the previous data to keep the uuid * of the terminal strip unchanged * @param data */ -void TerminalStrip::setData(const TerminalStripData &data) -{ - auto uuid_ = m_data.m_uuid; +void TerminalStrip::setData(const TerminalStripData &data) { m_data = data; - m_data.m_uuid = uuid_; } /** @@ -448,15 +114,13 @@ bool TerminalStrip::addTerminal(Element *terminal) m_terminal_elements_vector.append(terminal); //Create the real terminal - shared_real_terminal real_terminal(new RealTerminal(this, terminal)); + auto raw_real_ptr = new RealTerminal(this, terminal); + auto real_terminal = raw_real_ptr->sharedRef(); m_real_terminals.append(real_terminal); //Create a new single level physical terminal - shared_physical_terminal physical_terminal( - new PhysicalTerminal(this, - QVector{real_terminal})); - - m_physical_terminals.append(physical_terminal); + auto raw_phy_ptr = new PhysicalTerminal(this, QVector>{real_terminal}); + m_physical_terminals.append(raw_phy_ptr->sharedRef()); static_cast(terminal)->setParentTerminalStrip(this); @@ -474,7 +138,6 @@ bool TerminalStrip::removeTerminal(Element *terminal) if (m_terminal_elements_vector.contains(terminal)) { m_terminal_elements_vector.removeOne(terminal); - //Get the real and physical terminal associated to @terminal if (auto real_terminal = realTerminal(terminal)) { @@ -483,7 +146,7 @@ bool TerminalStrip::removeTerminal(Element *terminal) if (physical_terminal->levelCount() == 1) { m_physical_terminals.removeOne(physical_terminal); } else { - auto v = physical_terminal->terminals(); + auto v = physical_terminal->realTerminals(); v.removeOne(real_terminal); physical_terminal->setTerminals(v); } @@ -501,6 +164,16 @@ bool TerminalStrip::removeTerminal(Element *terminal) return false; } +/** + * @brief TerminalStrip::pos + * @param terminal + * @return the position of the physical terminal + * or -1 if not found + */ +int TerminalStrip::pos(const QSharedPointer &terminal) const { + return m_physical_terminals.indexOf(terminal); +} + /** * @brief TerminalStrip::physicalTerminalCount * @return the number of physical terminal. @@ -515,70 +188,65 @@ int TerminalStrip::physicalTerminalCount() const { * @brief TerminalStrip::physicalTerminalData * @param index * @return The data of the physical terminal at index \p index + * returned QSharedPointer can be null */ -PhysicalTerminalData TerminalStrip::physicalTerminalData(int index) const +QSharedPointer TerminalStrip::physicalTerminal(int index) const { - PhysicalTerminalData ptd; + if (index < m_physical_terminals.size()) { + return m_physical_terminals.at(index); + } else { + return QSharedPointer(); + } +} - if (index < m_physical_terminals.size()) - { - auto physical_terminal = m_physical_terminals.at(index); - ptd.pos_ = index; - for (auto real_terminal : physical_terminal->terminals()) { - auto rtd = realTerminalData(real_terminal); - ptd.real_terminals_vector.append(rtd); +/** + * @brief TerminalStrip::physicalTerminalData + * @param real_terminal + * @return the parent PhysicalTerminal of \p real_terminal. + * the PhysicalTerminal can be null if \p real_terminal don't belong to this strip + */ +QSharedPointer TerminalStrip::physicalTerminal (const QSharedPointer &real_terminal) const +{ + if (real_terminal.isNull()) { + return QSharedPointer(); + } + + for (auto &physical : qAsConst(m_physical_terminals)) { + if (physical->realTerminals().contains(real_terminal)) { + return physical; } - ptd.uuid_ = physical_terminal->uuid(); } - return ptd; + return QSharedPointer(); } /** - * @brief TerminalStrip::physicalTerminalData - * @param real_data - * @return the parent PhysicalTerminalData of \p real_data. - * the PhysicalTerminalData can be invalid if \p real_data don't belong to this strip - */ -PhysicalTerminalData TerminalStrip::physicalTerminalData(const RealTerminalData &real_data) const -{ - PhysicalTerminalData ptd_; - - const auto real_t = realTerminalForUuid(real_data.real_terminal_uuid); - if (real_t.isNull()) { - return ptd_; - } - - const auto phy_t = physicalTerminal(real_t); - if (phy_t.isNull()) { - return ptd_; - } - - ptd_.pos_ = m_physical_terminals.indexOf(phy_t); - for (auto real_terminal : phy_t->terminals()) { - auto rtd = realTerminalData(real_terminal); - ptd_.real_terminals_vector.append(rtd); - } - ptd_.uuid_ = phy_t->uuid(); - - return ptd_; -} - -/** - * @brief TerminalStrip::physicalTerminalData - * @return A vector of all physical terminal data owned by this terminal strip. + * @brief TerminalStrip::physicalTerminal + * @return A vector of all physical terminal owned by this terminal strip. * The order of the vector is the same as the order of the terminal in the strip */ -QVector TerminalStrip::physicalTerminalData() const +QVector> TerminalStrip::physicalTerminal() const { + return m_physical_terminals; +} + +/** + * @brief TerminalStrip::realTerminal + * @param terminal + * @return the real terminal linked to \p terminal + * the returned QSharedPointer can be null. + */ +QSharedPointer TerminalStrip::realTerminal(Element *terminal) const { - QVector v_; - for (auto i = 0 ; ielement() == terminal) { + return real; + } } - return v_; + return shared_real_terminal(); } + /** * @brief TerminalStrip::setSortedTo * Sort the physical terminal owned by this strip in the same order @@ -586,23 +254,22 @@ QVector TerminalStrip::physicalTerminalData() const * \p sorted_vector must contain exaclty the same physical terminal as this strip * else this function do nothing. * - * To avoid any mistake, you should call TerminalStrip::physicalTerminalData() + * To avoid any mistake, you should call TerminalStrip::physicalTerminal() * sort the returned vector and call this function with sorted vector, then you are sure * the vector contain the same values, no more no less. * * @param sorted_vector * @return true is successfully sorted. */ -bool TerminalStrip::setOrderTo(const QVector &sorted_vector) +bool TerminalStrip::setOrderTo(const QVector> &sorted_vector) { if (sorted_vector.size() != m_physical_terminals.size()) { return false; } QVector> new_order; - for (const auto &ptd : sorted_vector) + for (const auto &physical_t : sorted_vector) { - const auto physical_t = physicalTerminalForUuid(ptd.uuid_); if (physical_t.isNull()) { continue; } @@ -615,6 +282,7 @@ bool TerminalStrip::setOrderTo(const QVector &sorted_vecto } m_physical_terminals = new_order; + rebuildRealVector(); emit orderChanged(); return true; } @@ -630,19 +298,16 @@ bool TerminalStrip::setOrderTo(const QVector &sorted_vecto * @param receiver_terminal * @return true if success */ -bool TerminalStrip::groupTerminals(const PhysicalTerminalData &receiver_terminal, const QVector &added_terminals) +bool TerminalStrip::groupTerminals(const QSharedPointer &receiver_terminal, const QVector> &added_terminals) { - const auto receiver_ = physicalTerminalForUuid(receiver_terminal.uuid_); - if (receiver_.isNull()) { + if (receiver_terminal.isNull()) { qDebug() << "TerminalStrip::groupTerminal : Arguments terminals don't belong to this strip. Operation aborted."; return false; } bool have_grouped = false; - for (const auto &added : added_terminals) + for (const auto &added_terminal : added_terminals) { - const auto added_terminal = realTerminalForUuid(added.real_terminal_uuid); - if (added_terminal.isNull()) { continue; } @@ -650,7 +315,7 @@ bool TerminalStrip::groupTerminals(const PhysicalTerminalData &receiver_terminal auto physical_ = physicalTerminal(added_terminal); physical_->removeTerminal(added_terminal); - receiver_->addTerminal(added_terminal); + receiver_terminal->addTerminal(added_terminal); have_grouped = true; } @@ -658,7 +323,7 @@ bool TerminalStrip::groupTerminals(const PhysicalTerminalData &receiver_terminal { const auto vector_ = m_physical_terminals; for (const auto &phys : vector_) { - if (phys->terminals().isEmpty()) { + if (phys->realTerminals().isEmpty()) { m_physical_terminals.removeOne(phys); } } @@ -673,22 +338,20 @@ bool TerminalStrip::groupTerminals(const PhysicalTerminalData &receiver_terminal * Ungroup all real terminals of \p terminals_to_ungroup * @param terminals_to_ungroup */ -void TerminalStrip::unGroupTerminals(const QVector &terminals_to_ungroup) +void TerminalStrip::unGroupTerminals(const QVector> &terminals_to_ungroup) { bool ungrouped = false; - for (const auto &rtd_ : terminals_to_ungroup) + for (const auto &real_terminal : terminals_to_ungroup) { - if (auto real_terminal = realTerminalForUuid(rtd_.real_terminal_uuid)) //Get the shared real terminal + if (real_terminal) { if (auto physical_terminal = physicalTerminal(real_terminal)) //Get the physical terminal { - if (physical_terminal->terminals().size() > 1) //Check if physical have more than one real terminal + if (physical_terminal->realTerminals().size() > 1) //Check if physical have more than one real terminal { physical_terminal->removeTerminal(real_terminal); - shared_physical_terminal new_physical_terminal ( - new PhysicalTerminal(this, QVector{real_terminal})); - - m_physical_terminals.append(new_physical_terminal); + auto raw_ptr = new PhysicalTerminal(this, QVector>{real_terminal}); + m_physical_terminals.append(raw_ptr->sharedRef()); ungrouped = true; } } @@ -706,15 +369,14 @@ void TerminalStrip::unGroupTerminals(const QVector &terminals_ * @param level * @return */ -bool TerminalStrip::setLevel(const RealTerminalData &real_terminal_data, int level) +bool TerminalStrip::setLevel(const QSharedPointer &real_terminal, int level) { - auto real_terminal = realTerminalForUuid(real_terminal_data.real_terminal_uuid); if (real_terminal) { auto physical_terminal = physicalTerminal(real_terminal); if (physical_terminal) { - if (physical_terminal->terminals().size() > 1 && + if (physical_terminal->realTerminals().size() > 1 && physical_terminal->setLevelOf(real_terminal, level)) { emit orderChanged(); @@ -726,6 +388,336 @@ bool TerminalStrip::setLevel(const RealTerminalData &real_terminal_data, int lev return false; } +/** + * @brief TerminalStrip::isBridgeable + * Check if all realTerminal in @a real_terminals are bridgeable together. + * To be bridgeable, each real terminal must belong to this terminal strip + * be at the same level, be consecutive and not belong to the same physicalTerminal + * and at least one terminal must be not bridged + * @param real_terminals : a vector of realterminal + * @return + */ +bool TerminalStrip::isBridgeable(const QVector> &real_terminals) const +{ + if (real_terminals.size() < 2) { + return false; + } + + // Check if first terminal belong to this strip + const auto first_real_terminal = real_terminals.first(); + if (!first_real_terminal) { + return false; + } + + // Get the level of the first terminal + const int level_ = first_real_terminal->level(); + + // Get the physical terminal and pos + auto first_physical_terminal = physicalTerminal(first_real_terminal); + QVector physical_vector{first_physical_terminal}; + QVector pos_vector{m_physical_terminals.indexOf(first_physical_terminal)}; + + auto bridge_ = isBridged(first_real_terminal); + //bool to know at the end of this function if at least one terminal is not bridged + bool no_bridged = bridge_ ? false : true; + + // Check for each terminals + for (int i=1 ; ilevel()) { + return false; + } + + // Not to the same physical terminal of a previous checked real terminal + const auto physical_terminal = physicalTerminal(real_terminal); + if (physical_vector.contains(physical_terminal)) { + return false; + } else { + physical_vector.append(physical_terminal); + } + + // Not in another bridge of a previous checked real terminal + const auto checked_bridge = isBridged(real_terminal); + if (checked_bridge) + { + if (bridge_.isNull()) { + bridge_ = checked_bridge; + } else if (checked_bridge != bridge_) { + return false; + } + } else { + no_bridged = true; + } + + pos_vector.append(m_physical_terminals.indexOf(physical_terminal)); + } + + // Check if concecutive + const auto count_ = pos_vector.size(); + const auto min_max = std::minmax_element(pos_vector.constBegin(), pos_vector.constEnd()); + if ((*min_max.second - *min_max.first) + 1 != count_) { + return false; + } + + return no_bridged; +} + +/** + * @brief TerminalStrip::setBridge + * Set a bridge betwen all real terminal of @a real_terminals + * @sa TerminalStrip::isBridgeable + * @return true if bridge was successfully created + */ +bool TerminalStrip::setBridge(const QVector> &real_terminals) +{ + if (!isBridgeable(real_terminals)) { + return false; + } + + auto bridge = bridgeFor(real_terminals); + if (bridge.isNull()) + { + auto br_ = new TerminalStripBridge(this); + bridge = br_->sharedRef(); + m_bridge.append(bridge); + } + + if (bridge->addTerminals(real_terminals)) + { + emit bridgeChanged();; + return true; + } + return false; +} + +/** + * @brief TerminalStrip::setBridge + * Bridge the RealTerminal of @a real_terminals_data to @a bridge + * @param bridge + * @param real_terminals_data + * @return true if all RealTerminal was successfully bridged + */ +bool TerminalStrip::setBridge(const QSharedPointer &bridge, const QVector> &real_terminals) +{ + if (bridge) + { + if (!isBridgeable(real_terminals)) { + return false; + } + + if (bridge->addTerminals(real_terminals)) + { + emit bridgeChanged(); + return true; + } + } + + return false; +} + +/** + * @brief TerminalStrip::unBridge + * Unbridge all real terminals of @a real_terminals + * @sa TerminalStrip::canUnBridge + * @param real_terminals + */ +void TerminalStrip::unBridge(const QVector> &real_terminals) +{ + if (canUnBridge(real_terminals)) + { + auto bridge_ = isBridged(real_terminals.first()); + bridge_->removeTerminals(real_terminals); + emit bridgeChanged(); + } +} + +/** + * @brief TerminalStrip::canUnBridge + * @param m_real_terminals + * @return True if all terminals of @a real_terminals can be unbridged. + * For this method return True, all terminals must be bridged together, + * be consecutive and in one or the both extremities of the bridge. + */ +bool TerminalStrip::canUnBridge(const QVector > &real_terminals) const +{ + if (real_terminals.isEmpty()) { + return false; + } + + //Get the bridge of first terminal + const auto compar_bridge = isBridged(real_terminals.first()); + if (compar_bridge) + { + QMap> sorted_terminal; + + //Check if all terminals are bridged and if it's the same bridge. + //If true insert the terminal in sorted_terminal QMap + //with for key the position of the parent physical terminal + for (const auto &real_t : real_terminals) { + if (compar_bridge != isBridged(real_t)) { + return false; + } else { + sorted_terminal.insert(m_physical_terminals.indexOf(physicalTerminal(real_t)), + real_t); + } + } + + //Check if consecutive + const auto count_ = sorted_terminal.size(); + const auto min_max = std::minmax_element(sorted_terminal.keyBegin(), sorted_terminal.keyEnd()); + if ((*min_max.second - *min_max.first) + 1 != count_) { + return false; + } + + //Check if first terminal is the begin of bridge + const auto previous_real_t = previousTerminalInLevel(sorted_terminal.first()); + if (previous_real_t.isNull()) + return true; + else { + const auto previous_bridge = isBridged(previous_real_t); + if (compar_bridge != previous_bridge) { + return true; + } + } + + //Check if last terminal is the end of bridge + const auto next_real_t = nextTerminalInLevel(sorted_terminal.last()); + if (next_real_t.isNull()) { + return true; + } else { + const auto next_bridge = isBridged(next_real_t); + if (compar_bridge != next_bridge) { + return true; + } + } + } + + return false; +} + +/** + * @brief TerminalStrip::isBridged + * Check if @a real_terminal is bridged + * @param real_terminal + * @return a pointer of TerminalStripBridge if bridget or a null QSharedPointer. + */ +QSharedPointer TerminalStrip::isBridged(const QSharedPointer real_terminal) const +{ + if (real_terminal) + { + for (const auto &bridge_ : qAsConst(m_bridge)) { + if (bridge_->realTerminals().contains(real_terminal)) + return bridge_; + } + } + return QSharedPointer(); +} + +/** + * @brief TerminalStrip::bridgeFor + * Return the bridge where at least one terminal of @a terminal_vector belong. + * If several terminals are bridged but not to the same bridge return + * a TerminalStripBridge with 0 real_terminals_uuid_vector + * @sa TerminalStripBridge + * @param terminal_vector + * @return + */ +QSharedPointer TerminalStrip::bridgeFor(const QVector > &terminal_vector) const +{ + QSharedPointer return_bridge; + + for (const auto &terminal : terminal_vector) + { + const auto bridge_ = isBridged(terminal); + if (!bridge_.isNull()) + { + if (return_bridge.isNull()) { + return_bridge = bridge_; + } + else if (return_bridge != bridge_) { + return QSharedPointer(); + } + } + } + + return return_bridge; +} + +/** + * @brief TerminalStrip::previousTerminalInLevel + * @param real_terminal + * @return The previous real terminal at the samne level of @a real_t + * or a null RealTerminalData if there not a previous real terminal + */ +QSharedPointer TerminalStrip::previousTerminalInLevel(const QSharedPointer &real_terminal) const +{ + const auto phy_t = physicalTerminal(real_terminal); + if (real_terminal && phy_t) + { + const auto level_ = phy_t->levelOf(real_terminal); + const auto index = m_physical_terminals.indexOf(phy_t); + if (index >= 1) + { + const auto t_vector = m_physical_terminals.at(index-1)->realTerminals(); + if (t_vector.size() > level_) { + return t_vector.at(level_); + } + } + } + + return QSharedPointer(); +} + +/** + * @brief TerminalStrip::nextTerminalInLevel + * @param real_terminal + * @return The next real terminal at the same level of @a real_t + * or a null RealTerminalData if there not a next real terminal + */ +QSharedPointer TerminalStrip::nextTerminalInLevel(const QSharedPointer &real_terminal) const +{ + const auto phy_t = physicalTerminal(real_terminal); + if (real_terminal && phy_t) + { + const auto level_ = phy_t->levelOf(real_terminal); + const auto index = m_physical_terminals.indexOf(phy_t); + if (index < m_physical_terminals.size()-1) + { + const auto t_vector = m_physical_terminals.at(index+1)->realTerminals(); + if (t_vector.size() > level_) { + return t_vector.at(level_); + } + } + } + + return QSharedPointer(); +} + +QSharedPointer TerminalStrip::previousRealTerminal(const QSharedPointer &real_terminal) const +{ + const auto index = m_real_terminals.indexOf(real_terminal); + if (index) { + return m_real_terminals.at(index-1); + } + return QSharedPointer(); +} + +QSharedPointer TerminalStrip::nextRealTerminal(const QSharedPointer &real_terminal) const +{ + const auto index = m_real_terminals.indexOf(real_terminal); + if (index != m_real_terminals.size()-1) { + return m_real_terminals.at(index+1); + } + return QSharedPointer(); +} + /** * @brief TerminalStrip::terminalElement * @return A vector of all terminal element owned by this strip @@ -777,8 +769,8 @@ bool TerminalStrip::fromXml(QDomElement &xml_element) if (!xml_layout.isNull()) { //Get all free elements terminal of the project - ElementProvider ep(m_project); - auto free_terminals = ep.freeTerminal(); + const ElementProvider ep(m_project); + const auto free_terminals = ep.freeTerminal(); //Read each physical terminal for(auto &xml_physical : QETXML::findInDomElement(xml_layout, PhysicalTerminal::xmlTagName())) @@ -788,7 +780,8 @@ bool TerminalStrip::fromXml(QDomElement &xml_element) //Read each real terminal of the current physical terminal of the loop for (auto &xml_real : QETXML::findInDomElement(xml_physical, RealTerminal::xmlTagName())) { - shared_real_terminal real_t(new RealTerminal(this)); + auto raw_ptr = new RealTerminal(this); + auto real_t = raw_ptr->sharedRef(); real_t->fromXml(xml_real, free_terminals); if(real_t->isElement()) { @@ -798,8 +791,8 @@ bool TerminalStrip::fromXml(QDomElement &xml_element) real_t_vector.append(real_t); } - shared_physical_terminal phy_t(new PhysicalTerminal(this, real_t_vector)); - m_physical_terminals.append(phy_t); + auto raw_ptr = new PhysicalTerminal(this, real_t_vector); + m_physical_terminals.append(raw_ptr->sharedRef()); m_real_terminals.append(real_t_vector); } @@ -809,106 +802,14 @@ bool TerminalStrip::fromXml(QDomElement &xml_element) } /** - * @brief TerminalStrip::realTerminal - * @param terminal - * @return the real terminal linked to \p terminal - * the returned QSharedPointer can be null. + * @brief TerminalStrip::rebuildRealVector + * Rebuild the real terminal vector + * to be ordered */ -QSharedPointer TerminalStrip::realTerminal(Element *terminal) +void TerminalStrip::rebuildRealVector() { - shared_real_terminal rt; - - for (auto &real : qAsConst(m_real_terminals)) { - if (real->element() == terminal) { - return real; - } + m_real_terminals.clear(); + for (const auto &phy : qAsConst(m_physical_terminals)) { + m_real_terminals.append(phy->realTerminals()); } - - return rt; -} - -/** - * @brief TerminalStrip::physicalTerminal - * @param terminal - * @return the physical terminal linked to \p terminal. - * The returned QSharedPointer can be null. - */ -QSharedPointer TerminalStrip::physicalTerminal(QSharedPointer terminal) const -{ - shared_physical_terminal pt; - - for (auto &physical : qAsConst(m_physical_terminals)) - { - if (physical->terminals().contains(terminal)) - { - pt = physical; - break; - } - } - - return pt; -} - -RealTerminalData TerminalStrip::realTerminalData(QSharedPointer real_terminal) const -{ - RealTerminalData rtd; - - auto physical_terminal = physicalTerminal(real_terminal); - - rtd.real_terminal_uuid = real_terminal->uuid(); - rtd.level_ = physical_terminal->levelOf(real_terminal); - rtd.label_ = real_terminal->label(); - - if (real_terminal->isElement()) { - rtd.Xref_ = autonum::AssignVariables::genericXref(real_terminal->element()); - rtd.element_uuid = real_terminal->elementUuid(); - rtd.element_ = real_terminal->element(); - } - rtd.type_ = real_terminal->type(); - rtd.function_ = real_terminal->function(); - rtd.led_ = real_terminal->led(); - rtd.is_element = real_terminal->isElement(); - - return rtd; -} - -/** - * @brief TerminalStrip::physicalTerminalForUuid - * Return the PhysicalTerminal with uuid \p uuid or a null - * PhysicalTerminal if uuid don't match - * @param uuid - * @return - */ -QSharedPointer TerminalStrip::physicalTerminalForUuid(const QUuid &uuid) const -{ - shared_physical_terminal return_pt; - - for (const auto &pt_ : qAsConst(m_physical_terminals)) { - if (pt_->uuid() == uuid) { - return_pt = pt_; - break; - } - } - - return return_pt; -} - -/** - * @brief TerminalStrip::realTerminalForUuid - * @param uuid - * @return the RealTerminal with uuid \p uuid or a null - * RealTerminal if uuid don't match - */ -QSharedPointer TerminalStrip::realTerminalForUuid(const QUuid &uuid) const -{ - shared_real_terminal return_rt; - - for (const auto &rt_ : qAsConst(m_real_terminals)) { - if (rt_->uuid() == uuid) { - return_rt = rt_; - break; - } - } - - return return_rt; } diff --git a/sources/TerminalStrip/terminalstrip.h b/sources/TerminalStrip/terminalstrip.h index dd24cd5cb..eae42117f 100644 --- a/sources/TerminalStrip/terminalstrip.h +++ b/sources/TerminalStrip/terminalstrip.h @@ -1,4 +1,4 @@ -/* +/* Copyright 2006-2021 The QElectroTech Team This file is part of QElectroTech. @@ -20,6 +20,8 @@ #include #include +#include + #include "terminalstripdata.h" #include "../properties/elementdata.h" @@ -29,65 +31,30 @@ class QETProject; class PhysicalTerminal; class TerminalStripIndex; class TerminalElement; - - - -struct RealTerminalData -{ - int level_ = -1; - - QString label_, - Xref_, - cable_, - cable_wire_, - conductor_; - - QUuid element_uuid, - real_terminal_uuid; - - ElementData::TerminalType type_; - ElementData::TerminalFunction function_; - - bool led_ = false, - is_element = false; - - QPointer element_; -}; - -struct PhysicalTerminalData -{ - QVector real_terminals_vector; - int pos_ = -1; - QUuid uuid_; -}; - -//Code to use PhysicalTerminalData as key for QHash -inline bool operator == (const PhysicalTerminalData &phy_1, const PhysicalTerminalData &phy_2) { - return phy_1.uuid_ == phy_2.uuid_; -} - -inline uint qHash(const PhysicalTerminalData &key, uint seed) { - return qHash(key.uuid_, seed); -} +class TerminalStrip; +class TerminalStripBridge; /** * @brief The TerminalStrip class * This class hold all the datas and configurations * of a terminal strip (but the not the visual aspect). * A terminal strip have some informations (name comment etc...) - * and is composed by terminals (draw in a diagram or described in the terminal strip) + * and is composed by one or several PhysicalTerminal. */ class TerminalStrip : public QObject { friend class TerminalStripModel; + friend class RealTerminalData; Q_OBJECT public: signals: void orderChanged(); //Emitted when the order of the physical terminal is changed - + void bridgeChanged(); + void bridgeColorChanged(QSharedPointer bridge); public: + TerminalStrip(QETProject *project); TerminalStrip(const QString &installation, @@ -113,14 +80,30 @@ class TerminalStrip : public QObject bool addTerminal (Element *terminal); bool removeTerminal (Element *terminal); + int pos(const QSharedPointer &terminal) const; int physicalTerminalCount() const; - PhysicalTerminalData physicalTerminalData(int index) const; - PhysicalTerminalData physicalTerminalData (const RealTerminalData &real_data) const; - QVector physicalTerminalData() const; - bool setOrderTo(const QVector &sorted_vector); - bool groupTerminals(const PhysicalTerminalData &receiver_terminal, const QVector &added_terminals); - void unGroupTerminals(const QVector &terminals_to_ungroup); - bool setLevel(const RealTerminalData &real_terminal_data, int level); + QSharedPointer physicalTerminal(int index) const; + QSharedPointer physicalTerminal (const QSharedPointer &real_terminal) const; + QVector> physicalTerminal() const; + QSharedPointer realTerminal(Element *terminal) const; + + bool setOrderTo(const QVector> &sorted_vector); + bool groupTerminals(const QSharedPointer &receiver_terminal, const QVector> &added_terminals); + void unGroupTerminals(const QVector> &terminals_to_ungroup); + bool setLevel(const QSharedPointer &real_terminal, int level); + + bool isBridgeable(const QVector> &real_terminals) const; + bool setBridge(const QVector> &real_terminals); + bool setBridge(const QSharedPointer &bridge, const QVector> &real_terminals); + void unBridge(const QVector> &real_terminals); + bool canUnBridge(const QVector > &real_terminals) const; + QSharedPointer isBridged(const QSharedPointer real_terminal) const; + QSharedPointer bridgeFor (const QVector> &terminal_vector) const; + + QSharedPointer previousTerminalInLevel(const QSharedPointer &real_terminal) const; + QSharedPointer nextTerminalInLevel(const QSharedPointer &real_terminal) const; + QSharedPointer previousRealTerminal(const QSharedPointer &real_terminal) const; + QSharedPointer nextRealTerminal(const QSharedPointer &real_terminal) const; QVector> terminalElement() const; @@ -129,11 +112,7 @@ class TerminalStrip : public QObject bool fromXml(QDomElement &xml_element); private: - QSharedPointer realTerminal(Element *terminal); - QSharedPointer physicalTerminal(QSharedPointer terminal) const; - RealTerminalData realTerminalData(QSharedPointer real_terminal) const; - QSharedPointer physicalTerminalForUuid (const QUuid &uuid) const; - QSharedPointer realTerminalForUuid(const QUuid &uuid) const; + void rebuildRealVector(); private: TerminalStripData m_data; @@ -141,6 +120,7 @@ class TerminalStrip : public QObject QVector> m_terminal_elements_vector; QVector> m_real_terminals; QVector> m_physical_terminals; + QVector> m_bridge; }; #endif // TERMINALSTRIP_H diff --git a/sources/TerminalStrip/terminalstripbridge.cpp b/sources/TerminalStrip/terminalstripbridge.cpp new file mode 100644 index 000000000..d810ad85d --- /dev/null +++ b/sources/TerminalStrip/terminalstripbridge.cpp @@ -0,0 +1,115 @@ +/* + Copyright 2006-2021 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 "terminalstripbridge.h" +#include "realterminal.h" +#include "terminalstrip.h" + +TerminalStripBridge::TerminalStripBridge(TerminalStrip *parent_strip) : + m_strip(parent_strip) +{} + +/** + * @brief TerminalStripBridge::sharedRef + * @return a QSharedPointer of this + */ +QSharedPointer TerminalStripBridge::sharedRef() +{ + QSharedPointer this_shared(this->weakRef()); + if (this_shared.isNull()) + { + this_shared = QSharedPointer(this); + m_this_weak = this_shared.toWeakRef(); + } + + return this_shared; +} + +/** + * @brief TerminalStripBridge::weakRef + * @return a QWeakPointer of this, weak pointer can be null + */ +QWeakPointer TerminalStripBridge::weakRef() { + return m_this_weak; +} + +/** + * @brief TerminalStripBridge::color + * @return The color of this bridge + */ +QColor TerminalStripBridge::color() const { + return m_color; +} + +void TerminalStripBridge::setColor(const QColor &color) { + m_color = color; + if (m_strip) { + m_strip->bridgeColorChanged(sharedRef()); + } +} + +/** + * @brief TerminalStripBridge::realTerminals + * @return the real terminals who are bridged by this bridge + */ +QVector > TerminalStripBridge::realTerminals() const { + return m_real_terminals; +} + +/** + * @brief TerminalStripBridge::addTerminals + * @param real_terminals + * @return Add terminals of @a real_terminals to this bridge. + * If a terminal is already bridged by this bridge, the terminal is ignored. + * If at least one terminal doesn't belong to the same strip of this bridge + * this function do nothing and return false. + */ +bool TerminalStripBridge::addTerminals(const QVector > &real_terminals) +{ + QVector> to_append; + for (const auto &real_t : real_terminals) + { + if (!real_t.isNull()) + { + if (real_t->parentStrip() != m_strip) { + return false; + } + if (!m_real_terminals.contains(real_t)) { + to_append.append(real_t); + } + } else { + return false; + } + } + + m_real_terminals.append(to_append); + return true; +} + +/** + * @brief TerminalStripBridge::removeTerminals + * @param real_terminal + * Remove all real terminal of @real_terminals from this bridge. + * This function doesn't make any check, they just remove if exist. + * @sa TerminalStrip::canUnBridge + */ +void TerminalStripBridge::removeTerminals(const QVector> &real_terminals) +{ + for (const auto &real_t : real_terminals) { + m_real_terminals.removeOne(real_t); + } +} diff --git a/sources/TerminalStrip/terminalstripbridge.h b/sources/TerminalStrip/terminalstripbridge.h new file mode 100644 index 000000000..082e49fb0 --- /dev/null +++ b/sources/TerminalStrip/terminalstripbridge.h @@ -0,0 +1,59 @@ +/* + Copyright 2006-2021 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 TERMINALSTRIPBRIDGE_H +#define TERMINALSTRIPBRIDGE_H + +#include +#include +#include +#include + +class RealTerminal; +class TerminalStrip; + +class TerminalStripBridge +{ + friend class TerminalStrip; + + public: + static QVector bridgeColor() {return QVector{Qt::red, Qt::blue, Qt::white, Qt::darkGray, Qt::black};} + + TerminalStripBridge(TerminalStrip *parent_strip = nullptr); + QSharedPointer sharedRef(); + QWeakPointer weakRef(); + + QColor color() const; + void setColor(const QColor &color); + QVector> realTerminals() const; + + private: + bool addTerminals(const QVector> &real_terminals); + void removeTerminals(const QVector> &real_terminals); + + + private: + QPointer m_strip; + QVector> m_real_terminals; + QColor m_color = Qt::darkGray; + QUuid m_uuid = QUuid::createUuid(); + QWeakPointer m_this_weak; +}; + + + +#endif // TERMINALSTRIPBRIDGE_H diff --git a/sources/TerminalStrip/terminalstripdata.cpp b/sources/TerminalStrip/terminalstripdata.cpp index 1a44f2065..bd86b1a14 100644 --- a/sources/TerminalStrip/terminalstripdata.cpp +++ b/sources/TerminalStrip/terminalstripdata.cpp @@ -24,6 +24,10 @@ TerminalStripData::TerminalStripData() } +TerminalStripData::TerminalStripData(const TerminalStripData &other) { + *this = other; +} + QDomElement TerminalStripData::toXml(QDomDocument &xml_document) const { auto root_elmt = xml_document.createElement(this->xmlTagName()); diff --git a/sources/TerminalStrip/terminalstripdata.h b/sources/TerminalStrip/terminalstripdata.h index 2dfdc6216..2b59bff3f 100644 --- a/sources/TerminalStrip/terminalstripdata.h +++ b/sources/TerminalStrip/terminalstripdata.h @@ -29,6 +29,7 @@ class TerminalStripData : public PropertiesInterface public: TerminalStripData(); + TerminalStripData(const TerminalStripData &other); void toSettings(QSettings &/*settings*/, const QString = QString()) const override {} void fromSettings (const QSettings &/*settings*/, const QString = QString()) override {} diff --git a/sources/TerminalStrip/ui/terminalstripeditor.cpp b/sources/TerminalStrip/ui/terminalstripeditor.cpp index 31aec27d5..1b226c410 100644 --- a/sources/TerminalStrip/ui/terminalstripeditor.cpp +++ b/sources/TerminalStrip/ui/terminalstripeditor.cpp @@ -1,4 +1,4 @@ -/* +/* Copyright 2006-2021 The QElectroTech Team This file is part of QElectroTech. @@ -33,6 +33,11 @@ #include "../UndoCommand/sortterminalstripcommand.h" #include "../UndoCommand/groupterminalscommand.h" #include "../UndoCommand/changeterminallevel.h" +#include "../UndoCommand/bridgeterminalscommand.h" +#include "../UndoCommand/changeterminalstripcolor.h" +#include "../physicalterminal.h" +#include "../realterminal.h" +#include "../terminalstripbridge.h" #include @@ -49,6 +54,7 @@ TerminalStripEditor::TerminalStripEditor(QETProject *project, QWidget *parent) : ui->setupUi(this); ui->m_table_widget->setItemDelegate(new TerminalStripModelDelegate(ui->m_terminal_strip_tw)); + ui->m_remove_terminal_strip_pb->setDisabled(true); buildTree(); #if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0) @@ -56,26 +62,34 @@ TerminalStripEditor::TerminalStripEditor(QETProject *project, QWidget *parent) : #else ui->m_terminal_strip_tw->expandAll(); #endif + + //Setup the bridge color + ui->m_bridge_color_cb->setColors(TerminalStripBridge::bridgeColor().toList()); + setUpUndoConnections(); //Call for update the state of child widgets selectionChanged(); //Go the diagram of double clicked terminal - connect(ui->m_table_widget, &QAbstractItemView::doubleClicked, [this](const QModelIndex &index) + connect(ui->m_table_widget, &QAbstractItemView::doubleClicked, this, [=](const QModelIndex &index) { - Element *elmt = nullptr; - if (this->m_model->isXrefCell(index, &elmt)) + if (m_model->columnTypeForIndex(index) == TerminalStripModel::XRef) { - auto diagram = elmt->diagram(); - if (diagram) + auto mrtd = m_model->modelRealTerminalDataForIndex(index); + if (mrtd.element_) { - diagram->showMe(); - if (diagram->views().size()) + auto elmt = mrtd.element_; + auto diagram = elmt->diagram(); + if (diagram) { - auto fit_view = elmt->sceneBoundingRect(); - fit_view.adjust(-200,-200,200,200); - diagram->views().first()->fitInView(fit_view, Qt::KeepAspectRatioByExpanding); + diagram->showMe(); + if (diagram->views().size()) + { + auto fit_view = elmt->sceneBoundingRect(); + fit_view.adjust(-200,-200,200,200); + diagram->views().at(0)->fitInView(fit_view, Qt::KeepAspectRatioByExpanding); + } } } } @@ -91,8 +105,8 @@ TerminalStripEditor::~TerminalStripEditor() { void TerminalStripEditor::setUpUndoConnections() { - connect(ui->m_terminal_strip_tw, &TerminalStripTreeWidget::terminalAddedToStrip, - [this](QUuid terminal_uuid, QUuid strip_uuid) + connect(ui->m_terminal_strip_tw, &TerminalStripTreeWidget::terminalAddedToStrip, this, + [=](QUuid terminal_uuid, QUuid strip_uuid) { auto terminal = m_uuid_terminal_H.value(terminal_uuid); auto strip = m_uuid_strip_H.value(strip_uuid); @@ -105,8 +119,8 @@ void TerminalStripEditor::setUpUndoConnections() m_project->undoStack()->push(undo); }); - connect(ui->m_terminal_strip_tw, &TerminalStripTreeWidget::terminalMovedFromStripToStrip, - [this] (QUuid terminal_uuid, QUuid old_strip_uuid, QUuid new_strip_uuid) + connect(ui->m_terminal_strip_tw, &TerminalStripTreeWidget::terminalMovedFromStripToStrip, this, + [=] (QUuid terminal_uuid, QUuid old_strip_uuid, QUuid new_strip_uuid) { auto terminal = m_uuid_terminal_H.value(terminal_uuid); auto old_strip = m_uuid_strip_H.value(old_strip_uuid); @@ -120,8 +134,8 @@ void TerminalStripEditor::setUpUndoConnections() m_project->undoStack()->push(undo); }); - connect(ui->m_terminal_strip_tw, &TerminalStripTreeWidget::terminalRemovedFromStrip, - [this] (QUuid terminal_uuid, QUuid old_strip_uuid) + connect(ui->m_terminal_strip_tw, &TerminalStripTreeWidget::terminalRemovedFromStrip, this, + [=] (QUuid terminal_uuid, QUuid old_strip_uuid) { auto terminal_ = m_uuid_terminal_H.value(terminal_uuid); auto strip_ = m_uuid_strip_H.value(old_strip_uuid); @@ -221,16 +235,16 @@ QTreeWidgetItem* TerminalStripEditor::addTerminalStrip(TerminalStrip *terminal_s //Add child terminal of the strip for (auto i=0 ; iphysicalTerminalCount() ; ++i) { - auto ptd = terminal_strip->physicalTerminalData(i); - if (ptd.real_terminals_vector.size()) + auto phy_t = terminal_strip->physicalTerminal(i); + if (phy_t->realTerminalCount()) { - auto real_t = ptd.real_terminals_vector.first(); - auto terminal_item = new QTreeWidgetItem(strip_item, QStringList(real_t.label_), TerminalStripTreeWidget::Terminal); - terminal_item->setData(0, TerminalStripTreeWidget::UUID_USER_ROLE, real_t.element_uuid.toString()); + const auto real_t = phy_t->realTerminals().at(0); + auto terminal_item = new QTreeWidgetItem(strip_item, QStringList(real_t->label()), TerminalStripTreeWidget::Terminal); + terminal_item->setData(0, TerminalStripTreeWidget::UUID_USER_ROLE, real_t->elementUuid()); terminal_item->setIcon(0, QET::Icons::ElementTerminal); - if (real_t.element_) { - m_uuid_terminal_H.insert(real_t.element_uuid, qgraphicsitem_cast(real_t.element_)); + if (real_t->element()) { + m_uuid_terminal_H.insert(real_t->elementUuid(), qgraphicsitem_cast(real_t->element())); } } } @@ -286,6 +300,7 @@ void TerminalStripEditor::setCurrentStrip(TerminalStrip *strip_) if (m_current_strip) { disconnect(m_current_strip, &TerminalStrip::orderChanged, this, &TerminalStripEditor::on_m_reload_pb_clicked); + disconnect(m_current_strip, &TerminalStrip::bridgeChanged, this, &TerminalStripEditor::on_m_reload_pb_clicked); } if (!strip_) @@ -317,10 +332,12 @@ void TerminalStripEditor::setCurrentStrip(TerminalStrip *strip_) m_model = new TerminalStripModel(strip_, this); ui->m_table_widget->setModel(m_model); + m_model->buildBridgePixmap(setUpBridgeCellWidth()); spanMultiLevelTerminals(); selectionChanged(); //Used to update child widgets connect(m_current_strip, &TerminalStrip::orderChanged, this, &TerminalStripEditor::on_m_reload_pb_clicked); + connect(m_current_strip, &TerminalStrip::bridgeChanged, this, &TerminalStripEditor::on_m_reload_pb_clicked); connect(ui->m_table_widget->selectionModel(), &QItemSelectionModel::selectionChanged, this, &TerminalStripEditor::selectionChanged); } } @@ -339,7 +356,7 @@ void TerminalStripEditor::spanMultiLevelTerminals() auto current_row = 0; for (auto i = 0 ; i < m_current_strip->physicalTerminalCount() ; ++i) { - const auto level_count = m_current_strip->physicalTerminalData(i).real_terminals_vector.size(); + const auto level_count = m_current_strip->physicalTerminal(i)->realTerminalCount(); if (level_count > 1) { ui->m_table_widget->setSpan(current_row, 0, level_count, 1); } @@ -361,6 +378,10 @@ void TerminalStripEditor::selectionChanged() ui->m_type_cb ->setDisabled(true); ui->m_function_cb ->setDisabled(true); ui->m_led_cb ->setDisabled(true); + + ui->m_bridge_terminals_pb ->setDisabled(true); + ui->m_unbridge_terminals_pb->setDisabled(true); + ui->m_bridge_color_cb ->setDisabled(true); return; } @@ -378,32 +399,132 @@ void TerminalStripEditor::selectionChanged() ui->m_led_cb ->setEnabled(true); } - const auto terminal_vector = m_model->physicalTerminalDataForIndex(index_list); + const auto model_physical_terminal_vector = m_model->modelPhysicalTerminalDataForIndex(index_list); + const auto model_real_terminal_vector = m_model->modelRealTerminalDataForIndex(index_list); //Enable/disable group button - ui->m_group_terminals_pb->setEnabled(terminal_vector.size() > 1 ? true : false); + ui->m_group_terminals_pb->setEnabled(model_physical_terminal_vector.size() > 1 ? true : false); //Enable/disable ungroup button - auto it_= std::find_if(terminal_vector.constBegin(), terminal_vector.constEnd(), [](const PhysicalTerminalData &data) + auto it_= std::find_if(model_physical_terminal_vector.constBegin(), model_physical_terminal_vector.constEnd(), [](const modelPhysicalTerminalData &data) { - if (data.real_terminals_vector.size() >= 2) { + if (data.real_data.size() >= 2) { return true; } else { return false; } }); - ui->m_ungroup_pb->setDisabled(it_ == terminal_vector.constEnd()); + ui->m_ungroup_pb->setDisabled(it_ == model_physical_terminal_vector.constEnd()); //Enable/disable level spinbox bool enable_ = false; - for (const auto &physical : terminal_vector) + for (const auto &physical : model_physical_terminal_vector) { - if (physical.real_terminals_vector.size() > 1) { + if (physical.real_data.size() > 1) { enable_ = true; break; } } ui->m_level_sb->setEnabled(enable_); + + //Enable/disable bridge and unbridge + bool enable_bridge = false; + bool enable_unbridge = false; + bool enable_bridge_color = false; + + //One column must be selected and the column must be a level column + int level_ = TerminalStripModel::levelForColumn(isSingleColumnSelected()); + if (level_ >= 0 && m_current_strip) + { + //Select only terminals of corresponding level cell selection + QVector> real_terminal_in_level_vector; + for (const auto &mrtd : model_real_terminal_vector) + { + if (mrtd.level_ == level_) { + real_terminal_in_level_vector.append(mrtd.real_terminal.toStrongRef()); + if (!enable_bridge_color && mrtd.bridged_) { + enable_bridge_color = true; + } + } + } + enable_bridge = m_current_strip->isBridgeable(real_terminal_in_level_vector); + enable_unbridge = m_current_strip->canUnBridge(real_terminal_in_level_vector); + } + ui->m_bridge_terminals_pb->setEnabled(enable_bridge); + ui->m_unbridge_terminals_pb->setEnabled(enable_unbridge); + ui->m_bridge_color_cb->setEnabled(enable_bridge_color); +} + +QSize TerminalStripEditor::setUpBridgeCellWidth() +{ + if (ui->m_table_widget->verticalHeader() && + m_model) + { + auto section_size = ui->m_table_widget->verticalHeader()->defaultSectionSize(); + auto h_header = ui->m_table_widget->horizontalHeader(); + + for (int i = TerminalStripModel::Level0 ; i<(TerminalStripModel::Level3+1) ; ++i) { + ui->m_table_widget->setColumnWidth(i, section_size); + h_header->setSectionResizeMode(i, QHeaderView::Fixed); + } + + return QSize(section_size, section_size); + } + + return QSize(0,0); +} + +/** + * @brief TerminalStripEditor::isSingleColumnSelected + * If all current QModelIndex are in the same column + * return the column type + * @sa TerminalStripModel::Column + * @return the column or TerminalStripModel::Invalid if several column are selected + */ +TerminalStripModel::Column TerminalStripEditor::isSingleColumnSelected() const +{ + if (m_current_strip && + ui->m_table_widget->selectionModel()) + { + const auto index_list = ui->m_table_widget->selectionModel()->selectedIndexes(); + if (index_list.isEmpty()) { + return TerminalStripModel::Invalid; + } + + auto column_ = index_list.first().column(); + for (const auto &index : index_list) { + if (index.column() != column_) { + return TerminalStripModel::Invalid; + } + } + + return TerminalStripModel::columnTypeForIndex(index_list.first()); + } + + return TerminalStripModel::Invalid; +} + +/** + * @brief TerminalStripEditor::singleColumnData + * @return a QPair with for first value the column and for second value the data + * of selected cell of the table widget, only if the selected cells are + * in the same column. If selected cells are not in the same column the first value + * of the QPair is TerminalStripModel::Invalid. + */ +QPair > TerminalStripEditor::singleColumnData() const +{ + if (m_current_strip) + { + auto level_ = isSingleColumnSelected(); + if (level_ != TerminalStripModel::Invalid) + { + const auto index_list = ui->m_table_widget->selectionModel()->selectedIndexes(); + const auto mrtd_vector = m_model->modelRealTerminalDataForIndex(index_list); + return qMakePair(level_, mrtd_vector); + } + } + + return qMakePair(TerminalStripModel::Invalid, QVector()); } /** @@ -540,22 +661,20 @@ void TerminalStripEditor::on_m_dialog_button_box_clicked(QAbstractButton *button if (m_model) { - for (const auto &data_ : m_model->modifiedRealTerminalData()) + for (const auto &data_ : m_model->modifiedmodelRealTerminalData()) { - auto original_ = data_.first; - auto edited_ = data_.second; - auto element = original_.element_; - if (element) { + if (auto element = data_.element_) + { auto current_data = element->elementData(); - current_data.setTerminalType(edited_.type_); - current_data.setTerminalFunction(edited_.function_); - current_data.setTerminalLED(edited_.led_); - current_data.m_informations.addValue(QStringLiteral("label"), edited_.label_); + current_data.setTerminalType(data_.type_); + current_data.setTerminalFunction(data_.function_); + current_data.setTerminalLED(data_.led_); + current_data.m_informations.addValue(QStringLiteral("label"), data_.label_); if (element->elementData() != current_data) m_project->undoStack()->push(new ChangeElementDataCommand(element, current_data)); - if (edited_.level_) - m_project->undoStack()->push(new ChangeTerminalLevel(m_current_strip, original_, edited_.level_)); + if (data_.level_ != data_.real_terminal.toStrongRef()->level()) + m_project->undoStack()->push(new ChangeTerminalLevel(m_current_strip, data_.real_terminal, data_.level_)); } } } @@ -584,11 +703,18 @@ void TerminalStripEditor::on_m_group_terminals_pb_clicked() { if (m_model && m_current_strip && m_project) { - auto rtd_vector = m_model->realTerminalDataForIndex(ui->m_table_widget->selectionModel()->selectedIndexes()); - if (rtd_vector.size() >= 2) + auto mrtd_vector = m_model->modelRealTerminalDataForIndex(ui->m_table_widget->selectionModel()->selectedIndexes()); + if (mrtd_vector.size() >= 2) { - auto receiver_ = m_current_strip->physicalTerminalData(rtd_vector.takeFirst()); - m_project->undoStack()->push(new GroupTerminalsCommand(m_current_strip, receiver_, rtd_vector)); + auto receiver_ = m_current_strip->physicalTerminal(mrtd_vector.takeFirst().real_terminal); + + QVector> vector_; + for (const auto & mrtd : mrtd_vector) { + vector_.append(mrtd.real_terminal.toStrongRef()); + } + m_project->undoStack()->push(new GroupTerminalsCommand(m_current_strip, + receiver_, + vector_)); } } } @@ -600,8 +726,13 @@ void TerminalStripEditor::on_m_ungroup_pb_clicked() { if (m_model && m_current_strip) { - const auto rtd_vector = m_model->realTerminalDataForIndex(ui->m_table_widget->selectionModel()->selectedIndexes()); - m_project->undoStack()->push(new UnGroupTerminalsCommand(m_current_strip, rtd_vector)); + const auto mrtd_vector = m_model->modelRealTerminalDataForIndex(ui->m_table_widget->selectionModel()->selectedIndexes()); + + QVector> vector_; + for (const auto &mrtd : mrtd_vector) { + vector_.append(mrtd.real_terminal.toStrongRef()); + } + m_project->undoStack()->push(new UnGroupTerminalsCommand(m_current_strip,vector_)); } } @@ -617,7 +748,7 @@ void TerminalStripEditor::on_m_level_sb_valueChanged(int arg1) for (auto index : index_list) { - auto level_index = m_model->index(index.row(), 1, index.parent()); + auto level_index = m_model->index(index.row(), TerminalStripModel::Level, index.parent()); if (level_index.isValid()) { m_model->setData(level_index, arg1); @@ -634,7 +765,7 @@ void TerminalStripEditor::on_m_type_cb_activated(int index) for (auto model_index : index_list) { - auto type_index = m_model->index(model_index.row(), 6, model_index.parent()); + auto type_index = m_model->index(model_index.row(), TerminalStripModel::Type, model_index.parent()); if (type_index.isValid()) { ElementData::TerminalType override_type; @@ -667,7 +798,7 @@ void TerminalStripEditor::on_m_function_cb_activated(int index) for (auto model_index : index_list) { - auto function_index = m_model->index(model_index.row(), 7, model_index.parent()); + auto function_index = m_model->index(model_index.row(), TerminalStripModel::Function, model_index.parent()); if (function_index.isValid()) { ElementData::TerminalFunction override_function; @@ -696,7 +827,7 @@ void TerminalStripEditor::on_m_led_cb_activated(int index) for (auto model_index : index_list) { - auto led_index = m_model->index(model_index.row(), 8, model_index.parent()); + auto led_index = m_model->index(model_index.row(), TerminalStripModel::Led, model_index.parent()); if (led_index.isValid()) { m_model->setData(led_index, @@ -706,3 +837,89 @@ void TerminalStripEditor::on_m_led_cb_activated(int index) } } +/** + * @brief TerminalStripEditor::on_m_bridge_terminals_pb_clicked + */ +void TerminalStripEditor::on_m_bridge_terminals_pb_clicked() +{ + if (m_current_strip) + { + int level_ = isSingleColumnSelected(); + if (level_ >= TerminalStripModel::Level0 && + level_ <= TerminalStripModel::Level3) + { + if(level_ == TerminalStripModel::Level0){level_ = 0;} + else if(level_ == TerminalStripModel::Level1){level_ = 1;} + else if(level_ == TerminalStripModel::Level2){level_ = 2;} + else if(level_ == TerminalStripModel::Level3){level_ = 3;} + + const auto index_list = ui->m_table_widget->selectionModel()->selectedIndexes(); + const auto mrtd_vector = m_model->modelRealTerminalDataForIndex(index_list); + QVector > match_vector; + for (const auto &mrtd : mrtd_vector) + { + if (mrtd.level_ == level_) { + match_vector.append(mrtd.real_terminal.toStrongRef()); + } + } + + if (m_current_strip->isBridgeable(match_vector)) { + m_project->undoStack()->push(new BridgeTerminalsCommand(m_current_strip, match_vector)); + } + } + } +} + +/** + * @brief TerminalStripEditor::on_m_unbridge_terminals_pb_clicked + */ +void TerminalStripEditor::on_m_unbridge_terminals_pb_clicked() +{ + if (m_current_strip) + { + int level_ = isSingleColumnSelected(); + if (level_ >= TerminalStripModel::Level0 && + level_ <= TerminalStripModel::Level3) + { + if(level_ == TerminalStripModel::Level0){level_ = 0;} + else if(level_ == TerminalStripModel::Level1){level_ = 1;} + else if(level_ == TerminalStripModel::Level2){level_ = 2;} + else if(level_ == TerminalStripModel::Level3){level_ = 3;} + + const auto index_list = ui->m_table_widget->selectionModel()->selectedIndexes(); + const auto mrtd_vector = m_model->modelRealTerminalDataForIndex(index_list); + QVector> match_vector; + for (const auto &mrtd : mrtd_vector) + { + if (mrtd.level_ == level_ + && mrtd.bridged_) { + match_vector.append(mrtd.real_terminal.toStrongRef()); + } + } + m_project->undoStack()->push(new UnBridgeTerminalsCommand(m_current_strip, match_vector)); + } + } +} + + +void TerminalStripEditor::on_m_bridge_color_cb_activated(const QColor &col) +{ + const auto data_vector = singleColumnData(); + const auto column_ = data_vector.first; + if (column_ == TerminalStripModel::Level0 || + column_ == TerminalStripModel::Level1 || + column_ == TerminalStripModel::Level2 || + column_ == TerminalStripModel::Level3) + { + const auto level_ = TerminalStripModel::levelForColumn(column_); + for (const auto &mrtd : data_vector.second) + { + if (mrtd.level_ == level_ && mrtd.bridged_) { + auto bridge_ = mrtd.real_terminal.toStrongRef()->bridge(); + m_project->undoStack()->push(new ChangeTerminalStripColor(bridge_, col)); + break; + } + } + } +} + diff --git a/sources/TerminalStrip/ui/terminalstripeditor.h b/sources/TerminalStrip/ui/terminalstripeditor.h index 05f9eaa1e..ed7a21c7c 100644 --- a/sources/TerminalStrip/ui/terminalstripeditor.h +++ b/sources/TerminalStrip/ui/terminalstripeditor.h @@ -20,6 +20,8 @@ #include +#include "terminalstripmodel.h" + namespace Ui { class TerminalStripEditor; } @@ -29,7 +31,6 @@ class TerminalStrip; class QTreeWidgetItem; class TerminalElement; class QAbstractButton; -class TerminalStripModel; /** * @brief The TerminalStripEditor class @@ -52,6 +53,9 @@ class TerminalStripEditor : public QDialog void setCurrentStrip(TerminalStrip *strip_); void spanMultiLevelTerminals(); void selectionChanged(); + QSize setUpBridgeCellWidth(); + TerminalStripModel::Column isSingleColumnSelected() const; + QPair> singleColumnData() const; private slots: void on_m_add_terminal_strip_pb_clicked(); @@ -66,6 +70,9 @@ class TerminalStripEditor : public QDialog void on_m_type_cb_activated(int index); void on_m_function_cb_activated(int index); void on_m_led_cb_activated(int index); + void on_m_bridge_terminals_pb_clicked(); + void on_m_unbridge_terminals_pb_clicked(); + void on_m_bridge_color_cb_activated(const QColor &col); private: Ui::TerminalStripEditor *ui; diff --git a/sources/TerminalStrip/ui/terminalstripeditor.ui b/sources/TerminalStrip/ui/terminalstripeditor.ui index e31862a37..410adace0 100644 --- a/sources/TerminalStrip/ui/terminalstripeditor.ui +++ b/sources/TerminalStrip/ui/terminalstripeditor.ui @@ -178,34 +178,14 @@ - - + + - Type : + Étage : - - - - Degrouper les bornes - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - + @@ -234,10 +214,96 @@ - - + + + + LED : + + + + + + + + Qt::Horizontal + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Position automatique + + + + + + + Fonction : + + + + + + + Couleur pont : + + + + + + + Grouper les bornes + + + + + + + Degrouper les bornes + + + + + + + Type : + + + + + + + + Sans + + + + + Avec + + + + + + + + @@ -256,52 +322,17 @@ - - + + - Position automatique + Ponter les bornes - - + + - Étage : - - - - - - - Grouper les bornes - - - - - - - Fonction : - - - - - - - - Sans - - - - - Avec - - - - - - - - LED : + Déponter les bornes @@ -375,6 +406,11 @@ + + KColorCombo + QComboBox +
kcolorcombo.h
+
TerminalStripTreeWidget QTreeWidget diff --git a/sources/TerminalStrip/ui/terminalstripmodel.cpp b/sources/TerminalStrip/ui/terminalstripmodel.cpp index fb873db10..16085fd83 100644 --- a/sources/TerminalStrip/ui/terminalstripmodel.cpp +++ b/sources/TerminalStrip/ui/terminalstripmodel.cpp @@ -18,30 +18,86 @@ #include "terminalstripmodel.h" #include "../terminalstrip.h" #include "../../qetgraphicsitem/element.h" +#include "../physicalterminal.h" +#include "../realterminal.h" +#include "../terminalstripbridge.h" #include #include #include #include #include +#include +#include /** * Some const int who describe what a column contain */ const int POS_CELL = 0; const int LEVEL_CELL = 1; -const int LABEL_CELL = 2; -const int XREF_CELL = 3; -const int CABLE_CELL = 4; -const int CABLE_WIRE_CELL = 5; -const int TYPE_CELL = 6; -const int FUNCTION_CELL = 7; -const int LED_CELL = 8; -const int CONDUCTOR_CELL = 9; +const int LEVEL_0_CELL = 2; +const int LEVEL_1_CELL = 3; +const int LEVEL_2_CELL = 4; +const int LEVEL_3_CELL = 5; +const int LABEL_CELL = 6; +const int XREF_CELL = 7; +const int CABLE_CELL = 8; +const int CABLE_WIRE_CELL = 9; +const int TYPE_CELL = 10; +const int FUNCTION_CELL = 11; +const int LED_CELL = 12; +const int CONDUCTOR_CELL = 13; -const int ROW_COUNT = 9; +const int ROW_COUNT = 13; -static QVector UNMODIFIED_CELL_VECTOR{false, false, false, false, false, false, false, false, false, false}; +static QVector UNMODIFIED_CELL_VECTOR{false, false, false, false, false, false, false, false, false, false, false, false, false, false}; +/** + * @brief TerminalStripModel::levelForColumn + * Return the terminal level for column @a column + * or -1 if column is not a level column + * @param column + * @return + */ +int TerminalStripModel::levelForColumn(Column column) +{ + switch (column) { + case Level0: return 0; + case Level1: return 1; + case Level2: return 2; + case Level3: return 3; + default: return -1; + } +} + +/** + * @brief TerminalStripModel::columnTypeForIndex + * @param index + * @return the thing (pos, level, type, function etc...) for @a index + */ +TerminalStripModel::Column TerminalStripModel::columnTypeForIndex(const QModelIndex &index) +{ + if (index.isValid()) + { + switch (index.column()) { + case 0: return Pos; + case 1: return Level; + case 2 : return Level0; + case 3 : return Level1; + case 4 : return Level2; + case 5 : return Level3; + case 6 : return Label; + case 7 : return XRef; + case 8 : return Cable; + case 9 : return CableWire; + case 10 : return Type; + case 11 : return Function; + case 12 : return Led; + case 13 : return Conductor; + default : return Invalid; + } + } + return Invalid; +} /** * @brief TerminalStripModel::TerminalStripModel @@ -53,6 +109,11 @@ TerminalStripModel::TerminalStripModel(TerminalStrip *terminal_strip, QObject *p m_terminal_strip(terminal_strip) { fillPhysicalTerminalData(); + + connect(terminal_strip, &TerminalStrip::bridgeColorChanged, this, [=] { + emit dataChanged(index(0, LEVEL_0_CELL), + index(rowCount(), LEVEL_3_CELL)); + }); } int TerminalStripModel::rowCount(const QModelIndex &parent) const @@ -64,8 +125,8 @@ int TerminalStripModel::rowCount(const QModelIndex &parent) const } auto count = 0; - for (const auto &ptd : m_edited_terminal_data) { - count += ptd.real_terminals_vector.size(); + for (const auto &mptd : m_physical_data) { + count += mptd.real_data.size(); } return count; @@ -83,28 +144,28 @@ QVariant TerminalStripModel::data(const QModelIndex &index, int role) const return QVariant(); } - const auto rtd = dataAtRow(index.row()); + const auto mrtd = dataAtRow(index.row()); if (role == Qt::DisplayRole) { switch (index.column()) { case POS_CELL : return physicalDataAtIndex(index.row()).pos_; - case LEVEL_CELL : return rtd.level_; - case LABEL_CELL : return rtd.label_; - case XREF_CELL : return rtd.Xref_; - case CABLE_CELL : return rtd.cable_; - case CABLE_WIRE_CELL : return rtd.cable_wire_; - case TYPE_CELL : return ElementData::translatedTerminalType(rtd.type_); - case FUNCTION_CELL : return ElementData::translatedTerminalFunction(rtd.function_); - case CONDUCTOR_CELL : return rtd.conductor_; + case LEVEL_CELL : return mrtd.level_; + case LABEL_CELL : return mrtd.label_; + case XREF_CELL : return mrtd.Xref_; + case CABLE_CELL : return mrtd.cable_; + case CABLE_WIRE_CELL : return mrtd.cable_wire; + case TYPE_CELL : return ElementData::translatedTerminalType(mrtd.type_); + case FUNCTION_CELL : return ElementData::translatedTerminalFunction(mrtd.function_); + case CONDUCTOR_CELL : return mrtd.conductor_; default : return QVariant(); } } else if (role == Qt::EditRole) { switch (index.column()) { - case LABEL_CELL : return rtd.label_; + case LABEL_CELL : return mrtd.label_; default: return QVariant(); } @@ -112,23 +173,35 @@ QVariant TerminalStripModel::data(const QModelIndex &index, int role) const else if (role == Qt::CheckStateRole && index.column() == LED_CELL) { - return rtd.led_ ? Qt::Checked : Qt::Unchecked; + return mrtd.led_ ? Qt::Checked : Qt::Unchecked; } else if (role == Qt::BackgroundRole && index.column() <= CONDUCTOR_CELL ) { - if (m_modified_cell.contains(rtd.element_) && - m_modified_cell.value(rtd.element_).at(index.column())) + if (m_modified_cell.contains(mrtd.element_) && + m_modified_cell.value(mrtd.element_).at(index.column())) { return QBrush(Qt::yellow); } } + else if (role == Qt::DecorationRole && + (index.column() == LEVEL_0_CELL || + index.column() == LEVEL_1_CELL || + index.column() == LEVEL_2_CELL || + index.column() == LEVEL_3_CELL)) + { + return bridgePixmapFor(index); + auto pixmap_ = bridgePixmapFor(index); + if (!pixmap_.isNull()) { + return pixmap_; + } + } return QVariant(); } bool TerminalStripModel::setData(const QModelIndex &index, const QVariant &value, int role) { - auto rtd = dataAtRow(index.row()); + auto mrtd = dataAtRow(index.row()); bool modified_ = false; int modified_cell = -1; auto column_ = index.column(); @@ -136,35 +209,35 @@ bool TerminalStripModel::setData(const QModelIndex &index, const QVariant &value if (column_ == LEVEL_CELL && role == Qt::EditRole) { - rtd.level_ = value.toInt(); + mrtd.level_ = value.toInt(); modified_ = true; modified_cell = LEVEL_CELL; } else if (column_ == LED_CELL) { - rtd.led_ = value.toBool(); + mrtd.led_ = value.toBool(); modified_ = true; modified_cell = LED_CELL; } else if (column_ == TYPE_CELL && role == Qt::EditRole) { - rtd.type_ = value.value(); + mrtd.type_ = value.value(); modified_ = true; modified_cell = TYPE_CELL; } else if (column_ == FUNCTION_CELL && role == Qt::EditRole) { - rtd.function_ = value.value(); + mrtd.function_ = value.value(); modified_ = true; modified_cell = FUNCTION_CELL; } else if (column_ == LABEL_CELL && role == Qt::EditRole && - rtd.label_ != value.toString()) + mrtd.label_ != value.toString()) { - rtd.label_ = value.toString(); + mrtd.label_ = value.toString(); modified_ = true; modified_cell = LABEL_CELL; } @@ -172,19 +245,19 @@ bool TerminalStripModel::setData(const QModelIndex &index, const QVariant &value //Set the modification to the terminal data if (modified_) { - replaceDataAtRow(rtd, index.row()); + replaceDataAtRow(mrtd, index.row()); - if (rtd.element_) + if (mrtd.element_) { QVector vector_; - if (m_modified_cell.contains(rtd.element_)) { - vector_ = m_modified_cell.value(rtd.element_); + if (m_modified_cell.contains(mrtd.element_)) { + vector_ = m_modified_cell.value(mrtd.element_); } else { vector_ = UNMODIFIED_CELL_VECTOR; } vector_.replace(modified_cell, true); - m_modified_cell.insert(rtd.element_, vector_); + m_modified_cell.insert(mrtd.element_, vector_); } emit dataChanged(index, index); return true; @@ -202,6 +275,10 @@ QVariant TerminalStripModel::headerData(int section, Qt::Orientation orientation switch (section) { case POS_CELL: return tr("Position"); case LEVEL_CELL: return tr("Étage"); + case LEVEL_0_CELL: return QStringLiteral("0"); + case LEVEL_1_CELL: return QStringLiteral("1"); + case LEVEL_2_CELL: return QStringLiteral("2"); + case LEVEL_3_CELL: return QStringLiteral("3"); case LABEL_CELL: return tr("Label"); case XREF_CELL: return tr("Référence croisé"); case CABLE_CELL: return tr("Câble"); @@ -236,22 +313,21 @@ Qt::ItemFlags TerminalStripModel::flags(const QModelIndex &index) const * @return a vector of QPair of modified terminal. * the first value of the QPair is the original data, the second value is the edited data */ -QVector> TerminalStripModel::modifiedRealTerminalData() const +QVector TerminalStripModel::modifiedmodelRealTerminalData() const { - QVector> returned_vector; + QVector returned_vector; const auto modified_real_terminal = m_modified_cell.keys(); - for (auto i = 0 ; i> TerminalStripModel::modifiedR return returned_vector; } -/** - * @brief TerminalStripModel::isXrefCell - * @param index - * @param elmt : Pointer of a pointer element - * @return true if the index is the Xref cell, if true the pointer \p element - * will be set to the element associated to the cell. - */ -bool TerminalStripModel::isXrefCell(const QModelIndex &index, Element **element) -{ - if (index.model() == this - && index.isValid() - && index.column() == XREF_CELL) - { - if (index.row() < rowCount()) - { - if (auto data = dataAtRow(index.row()) ; data.element_) { - *element = data.element_.data(); - } - } - return true; - } - - return false; -} - /** * @brief TerminalStripModel::terminalsForIndex * @param index_list * @return A vector of PhysicalTerminalData represented by index_list. * If sereval index point to the same terminal the vector have only one PhysicalTerminalData */ -QVector TerminalStripModel::physicalTerminalDataForIndex(QModelIndexList index_list) const +QVector TerminalStripModel::modelPhysicalTerminalDataForIndex(QModelIndexList index_list) const { - QVector vector_; + QVector vector_; if (index_list.isEmpty()) { return vector_; } @@ -306,7 +357,8 @@ QVector TerminalStripModel::physicalTerminalDataForIndex(Q } } - for (auto i : set_) { + for (const auto i : set_) + { const auto phy = physicalDataAtIndex(i); if (!vector_.contains(phy)) { vector_.append(phy); @@ -321,9 +373,9 @@ QVector TerminalStripModel::physicalTerminalDataForIndex(Q * @param index_list * @return */ -QVector TerminalStripModel::realTerminalDataForIndex(QModelIndexList index_list) const +QVector TerminalStripModel::modelRealTerminalDataForIndex(QModelIndexList index_list) const { - QVector vector_; + QVector vector_; if (index_list.isEmpty()) { return vector_; } @@ -346,28 +398,127 @@ QVector TerminalStripModel::realTerminalDataForIndex(QModelInd return vector_; } -void TerminalStripModel::fillPhysicalTerminalData() +/** + * @brief TerminalStripModel::realTerminalDataForIndex + * @param index + * @return modelRealTerminalData at index @a index or null modelRealTerminalData if invalid + */ +modelRealTerminalData TerminalStripModel::modelRealTerminalDataForIndex(const QModelIndex &index) const { - //Get all physical terminal - if (m_terminal_strip) { - for (auto i=0 ; i < m_terminal_strip->physicalTerminalCount() ; ++i) { - m_original_terminal_data.append(m_terminal_strip->physicalTerminalData(i)); - } - m_edited_terminal_data = m_original_terminal_data; + if (index.isValid()) { + return realDataAtIndex(index.row()); + } else { + return modelRealTerminalData(); } } -RealTerminalData TerminalStripModel::dataAtRow(int row) const +/** + * @brief TerminalStripModel::buildBridgePixmap + * Build the pixmap of bridge. + * You should call this method when you know the + * size to use in the bridge cell of a QTableView. + * @param pixmap_size + */ +void TerminalStripModel::buildBridgePixmap(const QSize &pixmap_size) +{ + m_bridges_pixmaps.clear(); + for (auto color_ : TerminalStripBridge::bridgeColor()) + { + QPen pen; + pen.setColor(color_); + pen.setWidth(1); + + QBrush brush; + brush.setColor(color_); + brush.setStyle(Qt::SolidPattern); + + QPixmap top_(pixmap_size); + top_.fill(Qt::lightGray); + QPainter top_p(&top_); + top_p.setPen(pen); + top_p.setBrush(brush); + + QPixmap middle_(pixmap_size); + middle_.fill(Qt::lightGray); + QPainter middle_p(&middle_); + middle_p.setPen(pen); + middle_p.setBrush(brush); + + QPixmap bottom_(pixmap_size); + bottom_.fill(Qt::lightGray); + QPainter bottom_p(&bottom_); + bottom_p.setPen(pen); + bottom_p.setBrush(brush); + + QPixmap none_(pixmap_size); + none_.fill(Qt::lightGray); + QPainter none_p(&none_); + none_p.setPen(pen); + none_p.setBrush(brush); + + + auto w_ = pixmap_size.width(); + auto h_ = pixmap_size.height(); + + //Draw circle + top_p.drawEllipse(QPoint(w_/2, h_/2), w_/4, h_/4); + middle_p.drawEllipse(QPoint(w_/2, h_/2), w_/4, h_/4); + bottom_p.drawEllipse(QPoint(w_/2, h_/2), w_/4, h_/4); + + //Draw top line + middle_p.drawRect((w_/2)-(w_/8), 0, w_/4, h_/2); + bottom_p.drawRect((w_/2)-(w_/8), 0, w_/4, h_/2); + none_p.drawRect((w_/2)-(w_/8), 0, w_/4, h_/2); + + //Draw bottom line + top_p.drawRect((w_/2)-(w_/8), h_/2, w_/4, h_/2); + middle_p.drawRect((w_/2)-(w_/8), h_/2, w_/4, h_/2); + none_p.drawRect((w_/2)-(w_/8), h_/2, w_/4, h_/2); + + BridgePixmap bpxm; + bpxm.top_ = top_; + bpxm.middle_ = middle_; + bpxm.bottom_ = bottom_; + bpxm.none_ = none_; + m_bridges_pixmaps.insert(color_, bpxm); + } +} + +void TerminalStripModel::fillPhysicalTerminalData() +{ + //Get all physical terminal + if (m_terminal_strip) + { + for (const auto &phy_t : m_terminal_strip->physicalTerminal()) + { + modelPhysicalTerminalData mptd; + mptd.pos_ = phy_t->pos(); + mptd.uuid_ = phy_t->uuid(); + + for (const auto &real_t : phy_t->realTerminals()) + { + if (!real_t.isNull()) + { + mptd.real_data.append(modelRealData(real_t)); + } + } + + m_physical_data.append(mptd); + } + } +} + +modelRealTerminalData TerminalStripModel::dataAtRow(int row) const { if (row > rowCount(QModelIndex())) { - return RealTerminalData(); + return modelRealTerminalData(); } else { auto current_row = 0; - for (const auto &physical_data : m_edited_terminal_data) + for (const auto &physical_data : qAsConst(m_physical_data)) { - for (const auto &real_data : physical_data.real_terminals_vector) + for (const auto &real_data : physical_data.real_data) { if (current_row == row) { return real_data; @@ -378,7 +529,7 @@ RealTerminalData TerminalStripModel::dataAtRow(int row) const } } - return RealTerminalData(); + return modelRealTerminalData(); } /** @@ -387,7 +538,7 @@ RealTerminalData TerminalStripModel::dataAtRow(int row) const * @param data * @param row */ -void TerminalStripModel::replaceDataAtRow(RealTerminalData data, int row) +void TerminalStripModel::replaceDataAtRow(modelRealTerminalData data, int row) { if (row > rowCount(QModelIndex())) { return; @@ -397,15 +548,15 @@ void TerminalStripModel::replaceDataAtRow(RealTerminalData data, int row) auto current_row = 0; auto current_physical = 0; - for (const auto &physical_data : qAsConst(m_edited_terminal_data)) + for (const auto &physical_data : qAsConst(m_physical_data)) { auto current_real = 0; - for (int i=0 ; i= index) { @@ -448,9 +599,9 @@ PhysicalTerminalData TerminalStripModel::physicalDataAtIndex(int index) const } if (match_) { - return m_edited_terminal_data.at(current_phy); + return m_physical_data.at(current_phy); } else { - return PhysicalTerminalData(); + return modelPhysicalTerminalData(); } } @@ -459,17 +610,17 @@ PhysicalTerminalData TerminalStripModel::physicalDataAtIndex(int index) const * @param index * @return the realTerminalData at index \p index. */ -RealTerminalData TerminalStripModel::realDataAtIndex(int index) const +modelRealTerminalData TerminalStripModel::realDataAtIndex(int index) const { - if (m_edited_terminal_data.isEmpty()) { - return RealTerminalData(); + if (m_physical_data.isEmpty()) { + return modelRealTerminalData(); } int current_checked_index = -1; - for (const auto & ptd_ : qAsConst(m_edited_terminal_data)) + for (const auto & ptd_ : qAsConst(m_physical_data)) { - for (const auto & rtd_ : qAsConst(ptd_.real_terminals_vector)) { + for (const auto & rtd_ : qAsConst(ptd_.real_data)) { ++current_checked_index; if (current_checked_index == index) { return rtd_; @@ -477,11 +628,165 @@ RealTerminalData TerminalStripModel::realDataAtIndex(int index) const } } - return RealTerminalData(); + return modelRealTerminalData(); +} + +QPixmap TerminalStripModel::bridgePixmapFor(const QModelIndex &index) const +{ + if (!index.isValid() || m_terminal_strip.isNull()) { + return QPixmap(); + } + + auto level_column = levelForColumn(columnTypeForIndex(index)); + if (level_column == -1) { + return QPixmap(); + } + + auto mrtd = modelRealTerminalDataForIndex(index); + + //Terminal level correspond to the column level of index + if (level_column == mrtd.level_) + { + if (mrtd.bridged_) + { + auto bridge_ = m_terminal_strip->isBridged(mrtd.real_terminal); + if (bridge_) + { + const auto previous_t = m_terminal_strip->previousTerminalInLevel(mrtd.real_terminal); + QSharedPointer previous_bridge; + if (previous_t) + previous_bridge = previous_t->bridge(); + + const auto next_t = m_terminal_strip->nextTerminalInLevel(mrtd.real_terminal); + QSharedPointer next_bridge; + if (next_t) + next_bridge = next_t->bridge(); + + auto color_ = bridge_->color(); + auto pixmap_ = m_bridges_pixmaps.value(color_); + + //Current real terminal between two bridged terminal + if ((bridge_ == previous_bridge) && + (bridge_ == next_bridge)) { + return pixmap_.middle_; + } else if (bridge_ == previous_bridge) { + return pixmap_.bottom_; + } else if (bridge_ == next_bridge) { + return pixmap_.top_; + } + } + } + } + //Terminal level ins't in the same column level of index + //Check if we need to draw a none bridge pixmap + + //Check previous + auto phy_t = m_terminal_strip->physicalTerminal(mrtd.real_terminal); + auto current_real_terminal = mrtd; + auto current_phy_uuid = phy_t->uuid(); + bool already_jumped_to_previous = false; + modelRealTerminalData previous_data; + + do { + current_real_terminal = modelRealData(m_terminal_strip->previousRealTerminal(current_real_terminal.real_terminal)); + + if (current_real_terminal.level_ == -1) { + break; + } + + //We are in the same physical terminal as previous loop + if (current_phy_uuid == m_terminal_strip->physicalTerminal(current_real_terminal.real_terminal)->uuid()) + { + if (current_real_terminal.bridged_ && + current_real_terminal.level_ == level_column) { + previous_data = current_real_terminal; + break; + } + } + else if (already_jumped_to_previous) { //We are not in same physical terminal as previous loop + break; + } else { + already_jumped_to_previous = true; + current_phy_uuid = m_terminal_strip->physicalTerminal(current_real_terminal.real_terminal)->uuid(); + if (current_real_terminal.bridged_ && + current_real_terminal.level_ == level_column) { + previous_data = current_real_terminal; + break; + } + } + } while(true); + + //Check next + current_real_terminal = mrtd; + current_phy_uuid = phy_t->uuid(); + bool already_jumped_to_next = false; + modelRealTerminalData next_data; + + do { + current_real_terminal = modelRealData(m_terminal_strip->nextRealTerminal(current_real_terminal.real_terminal)); + + if (current_real_terminal.level_ == -1) { + break; + } + + //We are in the same physical terminal as previous loop + if (current_phy_uuid == m_terminal_strip->physicalTerminal(current_real_terminal.real_terminal)->uuid()) + { + if (current_real_terminal.bridged_ && + current_real_terminal.level_ == level_column) { + next_data = current_real_terminal; + break; + } + } + else if (already_jumped_to_next) { //We are not in same physical terminal as previous loop + break; + } else { + already_jumped_to_next = true; + current_phy_uuid = m_terminal_strip->physicalTerminal(current_real_terminal.real_terminal)->uuid(); + if (current_real_terminal.bridged_ && + current_real_terminal.level_ == level_column) { + next_data = current_real_terminal; + break; + } + } + } while(true); + + auto previous_bridge = m_terminal_strip->isBridged(previous_data.real_terminal); + if (previous_bridge == m_terminal_strip->isBridged(next_data.real_terminal)) + { + if (previous_bridge) { + return m_bridges_pixmaps.value(previous_bridge->color()).none_; + } + } + + return QPixmap(); +} + +modelRealTerminalData TerminalStripModel::modelRealData(const QWeakPointer &real_terminal) +{ + modelRealTerminalData mrtd; + const auto real_t = real_terminal.toStrongRef(); + if (!real_terminal.isNull()) + { + mrtd.level_ = real_t->level(); + mrtd.label_ = real_t->label(); + mrtd.Xref_ = real_t->Xref(); + mrtd.cable_ = real_t->cable(); + mrtd.cable_wire = real_t->cableWire(); + mrtd.conductor_ = real_t->conductor(); + mrtd.led_ = real_t->isLed(); + mrtd.type_ = real_t->type(); + mrtd.function_ = real_t->function(); + mrtd.element_ = real_t->element(); + mrtd.real_terminal = real_terminal; + mrtd.bridged_ = real_t->isBridged(); + } + + return mrtd; } /*********************************************************** - * Alittle delegate for add a combobox to edit type + * A little delegate for add a combobox to edit type * and a spinbox to edit the level of a terminal **********************************************************/ @@ -536,3 +841,43 @@ void TerminalStripModelDelegate::setModelData(QWidget *editor, QAbstractItemMode } } } + +/** + * @brief TerminalStripModelDelegate::paint + * By default on a QTableView, Qt draw pixmap in cell with a little margin at left. + * Override the function to draw the pixmap of bridge without the margin at left. + * @param painter + * @param option + * @param index + */ +void TerminalStripModelDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const +{ + auto column = index.column(); + if (column == LEVEL_0_CELL || + column == LEVEL_1_CELL || + column == LEVEL_2_CELL || + column == LEVEL_3_CELL) + { + auto variant = index.data(Qt::DecorationRole); + if (variant.isNull()) { + QStyledItemDelegate::paint(painter, option, index); + } + else + { + if (option.state & QStyle::State_Selected) + { + QStyleOptionViewItem opt_ = option; + initStyleOption(&opt_, index); + QStyle *style = QApplication::style(); + auto px = style->generatedIconPixmap(QIcon::Selected, variant.value(), &opt_); + style->drawItemPixmap(painter, option.rect, Qt::AlignLeft, px); + } + else { + painter->drawPixmap(option.rect, variant.value()); + } + } + } + else { + QStyledItemDelegate::paint(painter, option, index); + } +} diff --git a/sources/TerminalStrip/ui/terminalstripmodel.h b/sources/TerminalStrip/ui/terminalstripmodel.h index 25a06a057..d3fa6d40c 100644 --- a/sources/TerminalStrip/ui/terminalstripmodel.h +++ b/sources/TerminalStrip/ui/terminalstripmodel.h @@ -1,4 +1,4 @@ -/* +/* Copyright 2006-2021 The QElectroTech Team This file is part of QElectroTech. @@ -22,14 +22,82 @@ #include #include #include -#include +#include +#include #include "../terminalstrip.h" +#include "../../qetgraphicsitem/element.h" + +//Code to use QColor as key for QHash +inline uint qHash(const QColor &key, uint seed) { + return qHash(key.name(), seed); +} + +//needed to use QPointer as key of QHash +inline uint qHash(const QPointer &key, uint seed) { + if (key) + return qHash(key->uuid(), seed); + else + return qHash(nullptr, seed); +} class TerminalStrip; + +struct modelRealTerminalData +{ + int level_ = -1; + QString label_; + QString Xref_; + QString cable_; + QString cable_wire; + QString conductor_; + bool led_ = false; + bool bridged_ = false; + + ElementData::TerminalType type_ = ElementData::TerminalType::TTGeneric; + ElementData::TerminalFunction function_ = ElementData::TerminalFunction::TFGeneric; + QPointer element_; + + QWeakPointer real_terminal; + +}; + +struct modelPhysicalTerminalData +{ + QVector real_data; + int pos_ = -1; + QUuid uuid_; +}; + +inline bool operator == (const modelPhysicalTerminalData &data_1, const modelPhysicalTerminalData &data_2) { + return data_1.uuid_ == data_2.uuid_; +} + class TerminalStripModel : public QAbstractTableModel { + public: + enum Column { + Pos = 0, + Level = 1, + Level0 = 2, + Level1 = 3, + Level2 = 4, + Level3 = 5, + Label = 6, + XRef = 7, + Cable = 8, + CableWire = 9, + Type = 10, + Function = 11, + Led = 12, + Conductor = 13, + Invalid = 99 + }; + + static int levelForColumn(TerminalStripModel::Column column); + static TerminalStripModel::Column columnTypeForIndex(const QModelIndex &index); + Q_OBJECT public: TerminalStripModel(TerminalStrip *terminal_strip, QObject *parent = nullptr); @@ -40,24 +108,38 @@ class TerminalStripModel : public QAbstractTableModel virtual bool setData (const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; virtual QVariant headerData (int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; virtual Qt::ItemFlags flags (const QModelIndex &index) const override; + QVector modifiedmodelRealTerminalData() const; - QVector> modifiedRealTerminalData() const; + QVector modelPhysicalTerminalDataForIndex(QModelIndexList index_list) const; + QVector modelRealTerminalDataForIndex(QModelIndexList index_list) const; + modelRealTerminalData modelRealTerminalDataForIndex(const QModelIndex &index) const; - bool isXrefCell(const QModelIndex &index, Element **element = nullptr); - QVector physicalTerminalDataForIndex(QModelIndexList index_list) const; - QVector realTerminalDataForIndex(QModelIndexList index_list) const; + void buildBridgePixmap(const QSize &pixmap_size); private: void fillPhysicalTerminalData(); - RealTerminalData dataAtRow(int row) const; - void replaceDataAtRow(RealTerminalData data, int row); - PhysicalTerminalData physicalDataAtIndex(int index) const; - RealTerminalData realDataAtIndex(int index) const; + modelRealTerminalData dataAtRow(int row) const; + void replaceDataAtRow(modelRealTerminalData data, int row); + modelPhysicalTerminalData physicalDataAtIndex(int index) const; + modelRealTerminalData realDataAtIndex(int index) const; + QPixmap bridgePixmapFor(const QModelIndex &index) const; + + static modelRealTerminalData modelRealData(const QWeakPointer &real_terminal); private: QPointer m_terminal_strip; - QVector m_edited_terminal_data, m_original_terminal_data; - QHash> m_modified_cell; + QHash, QVector> m_modified_cell; + QVector m_physical_data; + struct BridgePixmap + { + QPixmap top_, + middle_, + bottom_, + none_; + }; + + QHash m_bridges_pixmaps; + }; class TerminalStripModelDelegate : public QStyledItemDelegate @@ -75,6 +157,8 @@ class TerminalStripModelDelegate : public QStyledItemDelegate QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override; + + void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; }; #endif // TERMINALSTRIPMODEL_H diff --git a/sources/utils/qetutils.h b/sources/utils/qetutils.h index 7ff299e23..dc6c76a6d 100644 --- a/sources/utils/qetutils.h +++ b/sources/utils/qetutils.h @@ -1,4 +1,4 @@ -/* +/* Copyright 2006-2021 The QElectroTech Team This file is part of QElectroTech. @@ -19,6 +19,7 @@ #define QETUTILS_H #include +#include class QGraphicsItem; @@ -30,6 +31,27 @@ namespace QETUtils QString marginsToString(const QMargins &margins); QMargins marginsFromString(const QString &string); qreal graphicsHandlerSize(QGraphicsItem *item); + + template + QVector> sharedVectorToWeak(const QVector> &vector) + { + QVector> return_vector; + for (const auto shared : vector) { + return_vector.append(shared.toWeakRef()); + } + return return_vector; + } + + + template + QVector> weakVectorToShared(const QVector> &vector) + { + QVector> return_vector; + for (const auto weak : vector) { + return_vector.append(weak.toStrongRef()); + } + return return_vector; + } } #endif // QETUTILS_H