diff --git a/sources/TerminalStrip/UndoCommand/bridgeterminalscommand.cpp b/sources/TerminalStrip/UndoCommand/bridgeterminalscommand.cpp new file mode 100644 index 000000000..663683a7e --- /dev/null +++ b/sources/TerminalStrip/UndoCommand/bridgeterminalscommand.cpp @@ -0,0 +1,77 @@ +/* + 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" +#include "../terminalstrip.h" + +BridgeTerminalsCommand::BridgeTerminalsCommand(TerminalStrip *strip, + QVector real_terminal_uuid, + QUndoCommand *parent): + QUndoCommand(parent), + m_strip(strip), + m_uuid_vector(real_terminal_uuid) +{ + setText(QObject::tr("Ponter des bornes entre-elles")); +} + +void BridgeTerminalsCommand::undo() +{ + if (m_strip) { + m_strip->unBridge(m_uuid_vector); + } +} + +void BridgeTerminalsCommand::redo() +{ + if (m_strip) { + m_strip->setBridge(m_uuid_vector); + } +} + +UnBridgeTerminalsCommand::UnBridgeTerminalsCommand(TerminalStrip *strip, + QVector real_terminal_uuid, + QUndoCommand *parent): + QUndoCommand(parent), + m_strip(strip) +{ + setText(QObject::tr("Supprimer des ponts de bornes")); + + for (const auto &t_uuid : real_terminal_uuid) + { + auto bridge = m_strip->bridgeFor(t_uuid); + if (bridge) { + m_bridge_terminal_map.insert(bridge->uuid_, t_uuid); + } + } +} + +void UnBridgeTerminalsCommand::undo() +{ + if (m_strip) { + for (const auto &bridge_uuid : m_bridge_terminal_map.uniqueKeys()) { + auto terminal_list = m_bridge_terminal_map.values(bridge_uuid); + m_strip->setBridge(bridge_uuid, terminal_list.toVector()); + } + } +} + +void UnBridgeTerminalsCommand::redo() +{ + if (m_strip) { + m_strip->unBridge(m_bridge_terminal_map.values().toVector()); + } +} diff --git a/sources/TerminalStrip/UndoCommand/bridgeterminalscommand.h b/sources/TerminalStrip/UndoCommand/bridgeterminalscommand.h new file mode 100644 index 000000000..03a6e8b17 --- /dev/null +++ b/sources/TerminalStrip/UndoCommand/bridgeterminalscommand.h @@ -0,0 +1,69 @@ +/* + 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 + +class TerminalStrip; + +/** + * @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_uuid, QUndoCommand *parent = nullptr); + ~BridgeTerminalsCommand() override {} + + void undo() override; + void redo() override; + + private: + QPointer m_strip; + QVector m_uuid_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_uuid, QUndoCommand *parent = nullptr); + ~UnBridgeTerminalsCommand() override{} + + void undo() override; + void redo() override; + + private: + QPointer m_strip; + QMultiMap m_bridge_terminal_map; ///Key is bridge uuid, value is real terminal uuid + +}; + +#endif // BRIDGETERMINALSCOMMAND_H diff --git a/sources/TerminalStrip/terminalstrip.cpp b/sources/TerminalStrip/terminalstrip.cpp index 02fac72e9..657f0c013 100644 --- a/sources/TerminalStrip/terminalstrip.cpp +++ b/sources/TerminalStrip/terminalstrip.cpp @@ -39,6 +39,7 @@ using shared_physical_terminal = QSharedPointer; * 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). + * @sa RealTerminalData */ class RealTerminal { @@ -79,7 +80,7 @@ class RealTerminal if (!m_element.isNull()) { return m_element->actualLabel(); } else { - return QStringLiteral(""); + return QLatin1String(); } } @@ -198,11 +199,11 @@ class RealTerminal /** * @brief The PhysicalTerminal class * Represent a physical terminal. - * A physical terminal is composed a least by one real 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 terminals returned by the function terminals() - * is the same as the real level of the physical terminal, the index are from back to front. + * 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) @@ -224,6 +225,8 @@ class RealTerminal * t |_| * e * + * @sa PhysicalTerminalData + * */ class PhysicalTerminal { @@ -243,9 +246,9 @@ class PhysicalTerminal /** * @brief setTerminals - * Set the real terminal of this physical terminal - * the order of the terminal in \p terminals represent - * the level index. + * 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 setTerminals(QVector terminals) { @@ -254,7 +257,7 @@ class PhysicalTerminal /** * @brief addTerminals - * Append the real terminal \p terminal + * Append the real terminal @a terminal * to this physical terminal. * @param terminal */ @@ -264,7 +267,7 @@ class PhysicalTerminal /** * @brief removeTerminal - * Remove \p terminal from the list of real terminal + * Remove @a terminal from the list of real terminal * @param terminal * @return true if sucessfully removed */ @@ -314,7 +317,7 @@ class PhysicalTerminal /** * @brief terminals - * @return A vector of real terminal who compose this physical terminal + * @return A vector of RealTerminal who compose this PhysicalTerminal */ QVector terminals() const { return m_real_terminal; @@ -415,7 +418,7 @@ 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 @@ -726,6 +729,192 @@ bool TerminalStrip::setLevel(const RealTerminalData &real_terminal_data, int lev return false; } +/** + * @brief TerminalStrip::isBridgeable + * Check if all realTerminal represented by the uuid of @a real_terminals_uuid 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_uuid : a vector of RealTerminal uuid + * @sa member real_terminal_uuid of struct RealTerminalData + * @return + */ +bool TerminalStrip::isBridgeable(const QVector &real_terminals_uuid) const +{ + if (real_terminals_uuid.size() < 2) { + return false; + } + + // Check if first terminal belong to this strip + auto first_real_terminal = realTerminalForUuid(real_terminals_uuid.first()); + if (!first_real_terminal) { + return false; + } + // Get the level of the first terminal + int level_ = realTerminalData(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 ; i &real_terminals_uuid) +{ + if (!isBridgeable(real_terminals_uuid)) { + return false; + } + QVector real_terminals_vector; + + for (const auto & uuid_ : real_terminals_uuid) { + auto real_t = realTerminalForUuid(uuid_); + if (real_t) + real_terminals_vector << real_t; + } + + auto bridge = bridgeFor(real_terminals_vector); + if (bridge.isNull()) { + bridge = QSharedPointer::create(); + m_bridge.append(bridge); + } + + for (const auto &real_t : qAsConst(real_terminals_vector)) + { + if (!bridge->real_terminals.contains(real_t)) + bridge->real_terminals.append(real_t); + } + + emit bridgeChanged(); + return true; +} + +/** + * @brief TerminalStrip::setBridge + * Bridge the RealTerminal with uuid in @a real_terminals_uuid to + * the bridge with uuid @a bridge_uuid. + * @param bridge_uuid + * @param real_terminals_uuid + * @return true if all RealTerminal was successfully bridged + */ +bool TerminalStrip::setBridge(const QUuid &bridge_uuid, const QVector &real_terminals_uuid) +{ + auto bridge_ = bridgeForUuid(bridge_uuid); + if (bridge_) + { + if (!isBridgeable(real_terminals_uuid)) { + return false; + } + + bool b_ = false; + for (const auto & uuid_ : real_terminals_uuid) + { + auto real_t = realTerminalForUuid(uuid_); + if (real_t && + !bridge_->real_terminals.contains(real_t)) + { + bridge_->real_terminals.append(real_t); + b_ = true; + } + } + + if (b_) { + emit bridgeChanged(); + return true; + } + } + + return false; +} + +/** + * @brief TerminalStrip::unBridge + * Unbridge all real terminal represented by they uuid + * @param real_terminals_uuid + */ +void TerminalStrip::unBridge(const QVector &real_terminals_uuid) +{ + for (const auto & uuid_ : real_terminals_uuid) + { + auto real_t = realTerminalForUuid(uuid_); + if (real_t) + { + auto bridge_ = isBridged(real_t); + if (bridge_) + bridge_->real_terminals.removeOne(real_t); + } + } + + emit bridgeChanged(); +} + +/** + * @brief TerminalStrip::bridgeFor + * @param real_terminal_uuid + * @return + */ +QSharedPointer TerminalStrip::bridgeFor(const QUuid &real_terminal_uuid) const +{ + auto rt = realTerminalForUuid(real_terminal_uuid); + return bridgeFor(QVector{rt}); +} + /** * @brief TerminalStrip::terminalElement * @return A vector of all terminal element owned by this strip @@ -849,7 +1038,7 @@ QSharedPointer TerminalStrip::physicalTerminal(QSharedPointer< return pt; } -RealTerminalData TerminalStrip::realTerminalData(QSharedPointer real_terminal) const +RealTerminalData TerminalStrip::realTerminalData(const QSharedPointer real_terminal) const { RealTerminalData rtd; @@ -868,6 +1057,7 @@ RealTerminalData TerminalStrip::realTerminalData(QSharedPointer re rtd.function_ = real_terminal->function(); rtd.led_ = real_terminal->led(); rtd.is_element = real_terminal->isElement(); + rtd.is_bridged = isBridged(real_terminal); return rtd; } @@ -912,3 +1102,67 @@ QSharedPointer TerminalStrip::realTerminalForUuid(const QUuid &uui return return_rt; } + +/** + * @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_->real_terminals.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) + { + 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::bridgeForUuid + * @param bridge_uuid + * @return the bridge with uuid @a bridge_uuid or null QSharedPointer if not exist + */ +QSharedPointer TerminalStrip::bridgeForUuid(const QUuid &bridge_uuid) +{ + for (const auto &bridge : qAsConst(m_bridge)) { + if (bridge->uuid_ == bridge_uuid) { + return bridge; + } + } + + return QSharedPointer(); +} diff --git a/sources/TerminalStrip/terminalstrip.h b/sources/TerminalStrip/terminalstrip.h index dd24cd5cb..837a01dc0 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" @@ -31,7 +33,11 @@ class TerminalStripIndex; class TerminalElement; - +/** + * @brief The RealTerminalData struct + * Conveniant struct to quickly get some values + * of a RealTerminal + */ struct RealTerminalData { int level_ = -1; @@ -43,17 +49,24 @@ struct RealTerminalData conductor_; QUuid element_uuid, - real_terminal_uuid; + real_terminal_uuid, + bridge_uuid; ElementData::TerminalType type_; ElementData::TerminalFunction function_; bool led_ = false, - is_element = false; + is_element = false, + is_bridged = false; QPointer element_; }; +/** + * @brief The PhysicalTerminalData struct + * Conveniant struct to quickly get some values + * of a PhysicalTerminal + */ struct PhysicalTerminalData { QVector real_terminals_vector; @@ -70,12 +83,19 @@ inline uint qHash(const PhysicalTerminalData &key, uint seed) { return qHash(key.uuid_, seed); } +struct TerminalStripBridge +{ + QVector> real_terminals; + QColor color_ = Qt::gray; + QUuid uuid_ = QUuid::createUuid(); +}; + /** * @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 { @@ -86,6 +106,7 @@ class TerminalStrip : public QObject public: signals: void orderChanged(); //Emitted when the order of the physical terminal is changed + void bridgeChanged(); public: TerminalStrip(QETProject *project); @@ -121,6 +142,11 @@ class TerminalStrip : public QObject 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); + bool isBridgeable(const QVector &real_terminals_uuid) const; + bool setBridge(const QVector &real_terminals_uuid); + bool setBridge(const QUuid &bridge_uuid, const QVector &real_terminals_uuid); + void unBridge(const QVector &real_terminals_uuid); + QSharedPointer bridgeFor(const QUuid &real_terminal_uuid) const; QVector> terminalElement() const; @@ -131,9 +157,12 @@ class TerminalStrip : public QObject private: QSharedPointer realTerminal(Element *terminal); QSharedPointer physicalTerminal(QSharedPointer terminal) const; - RealTerminalData realTerminalData(QSharedPointer real_terminal) const; + RealTerminalData realTerminalData(const QSharedPointer real_terminal) const; QSharedPointer physicalTerminalForUuid (const QUuid &uuid) const; QSharedPointer realTerminalForUuid(const QUuid &uuid) const; + QSharedPointer isBridged(const QSharedPointer real_terminal) const; + QSharedPointer bridgeFor (const QVector> &terminal_vector) const; + QSharedPointer bridgeForUuid (const QUuid &bridge_uuid); private: TerminalStripData m_data; @@ -141,6 +170,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/ui/terminalstripeditor.cpp b/sources/TerminalStrip/ui/terminalstripeditor.cpp index 31aec27d5..fd9410a58 100644 --- a/sources/TerminalStrip/ui/terminalstripeditor.cpp +++ b/sources/TerminalStrip/ui/terminalstripeditor.cpp @@ -33,6 +33,7 @@ #include "../UndoCommand/sortterminalstripcommand.h" #include "../UndoCommand/groupterminalscommand.h" #include "../UndoCommand/changeterminallevel.h" +#include "../UndoCommand/bridgeterminalscommand.h" #include @@ -49,6 +50,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,13 +58,18 @@ TerminalStripEditor::TerminalStripEditor(QETProject *project, QWidget *parent) : #else ui->m_terminal_strip_tw->expandAll(); #endif + + //Setup the bridge color + QList bridge_color{Qt::red, Qt::blue, Qt::white, Qt::gray, Qt::black}; + ui->m_bridge_color_cb->setColors(bridge_color); + 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)) @@ -75,7 +82,7 @@ TerminalStripEditor::TerminalStripEditor(QETProject *project, QWidget *parent) : { auto fit_view = elmt->sceneBoundingRect(); fit_view.adjust(-200,-200,200,200); - diagram->views().first()->fitInView(fit_view, Qt::KeepAspectRatioByExpanding); + diagram->views().at(0)->fitInView(fit_view, Qt::KeepAspectRatioByExpanding); } } } @@ -91,8 +98,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 +112,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 +127,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); @@ -286,6 +293,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 +325,12 @@ void TerminalStripEditor::setCurrentStrip(TerminalStrip *strip_) m_model = new TerminalStripModel(strip_, this); ui->m_table_widget->setModel(m_model); + 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); } } @@ -361,6 +371,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,13 +392,14 @@ void TerminalStripEditor::selectionChanged() ui->m_led_cb ->setEnabled(true); } - const auto terminal_vector = m_model->physicalTerminalDataForIndex(index_list); + const auto physical_terminal_vector = m_model->physicalTerminalDataForIndex(index_list); + const auto real_terminal_vector = m_model->realTerminalDataForIndex(index_list); //Enable/disable group button - ui->m_group_terminals_pb->setEnabled(terminal_vector.size() > 1 ? true : false); + ui->m_group_terminals_pb->setEnabled(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(physical_terminal_vector.constBegin(), physical_terminal_vector.constEnd(), [](const PhysicalTerminalData &data) { if (data.real_terminals_vector.size() >= 2) { return true; @@ -392,11 +407,11 @@ void TerminalStripEditor::selectionChanged() return false; } }); - ui->m_ungroup_pb->setDisabled(it_ == terminal_vector.constEnd()); + ui->m_ungroup_pb->setDisabled(it_ == physical_terminal_vector.constEnd()); //Enable/disable level spinbox bool enable_ = false; - for (const auto &physical : terminal_vector) + for (const auto &physical : physical_terminal_vector) { if (physical.real_terminals_vector.size() > 1) { enable_ = true; @@ -404,6 +419,91 @@ void TerminalStripEditor::selectionChanged() } } ui->m_level_sb->setEnabled(enable_); + + //Enable/disable bridge and unbridge + bool enable_bridge = false; + bool enable_unbridge = false; + + //One column must be selected and the column must be a level column + int level_ = TerminalStripModel::levelForColumn(isSingleColumnSelected()); + if (level_ >= 0) + { + //Select only terminals of corresponding level cell selection + QVector real_terminal_level_vector; + for (const auto &rtd : real_terminal_vector) { + if (rtd.level_ == level_) { + real_terminal_level_vector.append(rtd); + } + } + + QVector uuid_v; + for (const auto &rtd : real_terminal_level_vector) { + uuid_v << rtd.real_terminal_uuid; + } + if (m_current_strip) { + enable_bridge = m_current_strip->isBridgeable(uuid_v); + } + + for (const auto &rtd : real_terminal_level_vector) + { + if (rtd.is_bridged && + rtd.level_ == level_) { + enable_unbridge = true; + break; + } + } + } + ui->m_bridge_terminals_pb->setEnabled(enable_bridge); + ui->m_unbridge_terminals_pb->setEnabled(enable_unbridge); +} + +void 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(); + + h_header->setSectionResizeMode(2, QHeaderView::Fixed); + h_header->resizeSection(2, section_size); + h_header->setSectionResizeMode(3, QHeaderView::Fixed); + h_header->resizeSection(3, section_size); + h_header->setSectionResizeMode(4, QHeaderView::Fixed); + h_header->resizeSection(4, section_size); + h_header->setSectionResizeMode(5, QHeaderView::Fixed); + h_header->resizeSection(5, section_size); + } +} + +/** + * @brief TerminalStripEditor::isSingleColumnSelected + * If all current QModelIndex are in the same column + * return the column type + * @sa TerminalStripModel::Column + * @return + */ +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; } /** @@ -617,7 +717,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 +734,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 +767,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 +796,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 +806,72 @@ 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 rtd_vector = m_model->realTerminalDataForIndex(index_list); + QVector uuid_vector; + for (const auto &rtd : rtd_vector) + { + if (rtd.level_ == level_) { + uuid_vector.append(rtd.real_terminal_uuid); + } + } + if (m_current_strip->isBridgeable(uuid_vector)) { + m_project->undoStack()->push(new BridgeTerminalsCommand(m_current_strip, uuid_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 rtd_vector = m_model->realTerminalDataForIndex(index_list); + QVector uuid_vector; + for (const auto &rtd : rtd_vector) + { + if (rtd.level_ == level_ + && rtd.is_bridged) { + uuid_vector.append(rtd.real_terminal_uuid); + } + } + m_project->undoStack()->push(new UnBridgeTerminalsCommand(m_current_strip, uuid_vector)); + } + } +} + + +void TerminalStripEditor::on_m_bridge_color_cb_activated(const QColor &col) +{ + +} + diff --git a/sources/TerminalStrip/ui/terminalstripeditor.h b/sources/TerminalStrip/ui/terminalstripeditor.h index 05f9eaa1e..df07b5acf 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,8 @@ class TerminalStripEditor : public QDialog void setCurrentStrip(TerminalStrip *strip_); void spanMultiLevelTerminals(); void selectionChanged(); + void setUpBridgeCellWidth(); + TerminalStripModel::Column isSingleColumnSelected() const; private slots: void on_m_add_terminal_strip_pb_clicked(); @@ -66,6 +69,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..5bed80079 100644 --- a/sources/TerminalStrip/ui/terminalstripmodel.cpp +++ b/sources/TerminalStrip/ui/terminalstripmodel.cpp @@ -23,25 +23,77 @@ #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 @@ -91,6 +143,18 @@ QVariant TerminalStripModel::data(const QModelIndex &index, int role) const switch (index.column()) { case POS_CELL : return physicalDataAtIndex(index.row()).pos_; case LEVEL_CELL : return rtd.level_; + case LEVEL_0_CELL : + if (rtd.level_ == 0 && rtd.is_bridged) return "0"; + break; + case LEVEL_1_CELL : + if (rtd.level_ == 1 && rtd.is_bridged) return "0"; + break; + case LEVEL_2_CELL : + if (rtd.level_ == 2 && rtd.is_bridged) return "0"; + break; + case LEVEL_3_CELL : + if (rtd.level_ == 3 && rtd.is_bridged) return "0"; + break; case LABEL_CELL : return rtd.label_; case XREF_CELL : return rtd.Xref_; case CABLE_CELL : return rtd.cable_; @@ -202,6 +266,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"); @@ -284,6 +352,40 @@ bool TerminalStripModel::isXrefCell(const QModelIndex &index, Element **element) return false; } +/** + * @brief TerminalStripModel::levelCellCount + * Check for each index of @a index_list if the cell represented by the index + * is a level cell (level 0 to level 3) and if the corresponding real terminal is in the same level + * + * The returned vector contain how many index has matched + * the vector have 4 int, + * the first int is the number of matched level 0 + * the second int is the number of matched level 1 + * the third int is the number of matched level 2 + * the fourth int is the number of matched level 4 + * @param index_list + * @return + */ +QVector TerminalStripModel::levelCellCount(const QModelIndexList &index_list) const +{ + QVector vector_(4,0); + + for (const auto &index : index_list) + { + if(index.isValid()) + { + const auto rtd_ = realDataAtIndex(index.row()); + const auto level_ = rtd_.level_; + const auto index_column = index.column(); + if (level_ + 2 == index_column) { + vector_.replace(level_, vector_.at(level_)+1); + } + } + } + + return vector_; +} + /** * @brief TerminalStripModel::terminalsForIndex * @param index_list diff --git a/sources/TerminalStrip/ui/terminalstripmodel.h b/sources/TerminalStrip/ui/terminalstripmodel.h index 25a06a057..4eb1d1f0c 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. @@ -30,6 +30,28 @@ class TerminalStrip; 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,10 +62,10 @@ 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> modifiedRealTerminalData() const; bool isXrefCell(const QModelIndex &index, Element **element = nullptr); + QVector levelCellCount(const QModelIndexList &index_list) const; QVector physicalTerminalDataForIndex(QModelIndexList index_list) const; QVector realTerminalDataForIndex(QModelIndexList index_list) const; @@ -58,6 +80,10 @@ class TerminalStripModel : public QAbstractTableModel QPointer m_terminal_strip; QVector m_edited_terminal_data, m_original_terminal_data; QHash> m_modified_cell; + QPixmap m_bridge_top, + m_bride_bottom, + m_bridge, + m_bride_both; }; class TerminalStripModelDelegate : public QStyledItemDelegate