diff --git a/sources/TerminalStrip/terminalstrip.cpp b/sources/TerminalStrip/terminalstrip.cpp index 657f0c013..adce9d1c0 100644 --- a/sources/TerminalStrip/terminalstrip.cpp +++ b/sources/TerminalStrip/terminalstrip.cpp @@ -618,6 +618,7 @@ bool TerminalStrip::setOrderTo(const QVector &sorted_vecto } m_physical_terminals = new_order; + rebuildRealVector(); emit orderChanged(); return true; } @@ -909,12 +910,94 @@ void TerminalStrip::unBridge(const QVector &real_terminals_uuid) * @param real_terminal_uuid * @return */ -QSharedPointer TerminalStrip::bridgeFor(const QUuid &real_terminal_uuid) const +const QSharedPointer TerminalStrip::bridgeFor(const QUuid &real_terminal_uuid) const { auto rt = realTerminalForUuid(real_terminal_uuid); return bridgeFor(QVector{rt}); } +/** + * @brief TerminalStrip::previousTerminalInLevel + * @param real_terminal_uuid + * @return The previous real terminal at the samne level + * as the real terminal with uuid @a real_terminal_uuid + * If there is not a previous terminal, return a null RealTerminalData + */ +RealTerminalData TerminalStrip::previousTerminalInLevel(const QUuid &real_terminal_uuid) const +{ + auto real_t = realTerminalForUuid(real_terminal_uuid); + if (real_t) + { + auto phy_t = physicalTerminal(real_t); + if (phy_t) + { + auto level_ = phy_t->levelOf(real_t); + auto index = m_physical_terminals.indexOf(phy_t); + if (index >= 1) + { + auto t_vector = m_physical_terminals.at(index-1)->terminals(); + if (t_vector.size() > level_) + { + return realTerminalData(t_vector.at(level_)); + } + } + } + } + + return RealTerminalData(); +} + +/** + * @brief TerminalStrip::nextTerminalInLevel + * @param real_terminal_uuid + * @return The next real terminal at the samne level + * as the real terminal with uuid @a real_terminal_uuid + * If there is not a next terminal, return a null RealTerminalData + */ +RealTerminalData TerminalStrip::nextTerminalInLevel(const QUuid &real_terminal_uuid) const +{ + auto real_t = realTerminalForUuid(real_terminal_uuid); + if (real_t) + { + auto phy_t = physicalTerminal(real_t); + if (phy_t) + { + auto level_ = phy_t->levelOf(real_t); + auto index = m_physical_terminals.indexOf(phy_t); + if (index < m_physical_terminals.size()-1) + { + auto t_vector = m_physical_terminals.at(index+1)->terminals(); + if (t_vector.size() > level_) + { + return realTerminalData(t_vector.at(level_)); + } + } + } + } + + return RealTerminalData(); +} + +RealTerminalData TerminalStrip::previousRealTerminal(const QUuid &real_terminal_uuid) const +{ + auto real = realTerminalForUuid(real_terminal_uuid); + auto index = m_real_terminals.indexOf(real); + if (index) { + return realTerminalData(m_real_terminals.at(index-1)); + } + return RealTerminalData(); +} + +RealTerminalData TerminalStrip::nextRealTerminal(const QUuid &real_terminal_uuid) const +{ + auto real = realTerminalForUuid(real_terminal_uuid); + auto index = m_real_terminals.indexOf(real); + if (index != m_real_terminals.size()-1) { + return realTerminalData(m_real_terminals.at(index+1)); + } + return RealTerminalData(); +} + /** * @brief TerminalStrip::terminalElement * @return A vector of all terminal element owned by this strip @@ -1058,6 +1141,14 @@ RealTerminalData TerminalStrip::realTerminalData(const QSharedPointerled(); rtd.is_element = real_terminal->isElement(); rtd.is_bridged = isBridged(real_terminal); + if (rtd.is_bridged) { + for (auto bridge : m_bridge) { + if (bridge->real_terminals.contains(real_terminal)) { + rtd.bridge_uuid = bridge->uuid_; + break; + } + } + } return rtd; } @@ -1166,3 +1257,17 @@ QSharedPointer TerminalStrip::bridgeForUuid(const QUuid &br return QSharedPointer(); } + +/** + * @brief TerminalStrip::rebuildRealVector + * Rebuild the real terminal vector + * to be ordered + */ +void TerminalStrip::rebuildRealVector() +{ + m_real_terminals.clear(); + for (const auto phy : m_physical_terminals) { + for (const auto &real : phy->terminals()) + m_real_terminals.append(real); + } +} diff --git a/sources/TerminalStrip/terminalstrip.h b/sources/TerminalStrip/terminalstrip.h index 837a01dc0..da16cca39 100644 --- a/sources/TerminalStrip/terminalstrip.h +++ b/sources/TerminalStrip/terminalstrip.h @@ -37,6 +37,8 @@ class TerminalElement; * @brief The RealTerminalData struct * Conveniant struct to quickly get some values * of a RealTerminal + * A RealTerminalData with level_ = -1 + * is considered as a null data */ struct RealTerminalData { @@ -86,7 +88,7 @@ inline uint qHash(const PhysicalTerminalData &key, uint seed) { struct TerminalStripBridge { QVector> real_terminals; - QColor color_ = Qt::gray; + QColor color_ = Qt::darkGray; QUuid uuid_ = QUuid::createUuid(); }; @@ -104,6 +106,8 @@ class TerminalStrip : public QObject Q_OBJECT public: + static QVector bridgeColor() {return QVector{Qt::red, Qt::blue, Qt::white, Qt::darkGray, Qt::black};} + signals: void orderChanged(); //Emitted when the order of the physical terminal is changed void bridgeChanged(); @@ -146,7 +150,12 @@ class TerminalStrip : public QObject 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; + const QSharedPointer bridgeFor(const QUuid &real_terminal_uuid) const; + + RealTerminalData previousTerminalInLevel(const QUuid &real_terminal_uuid) const; + RealTerminalData nextTerminalInLevel(const QUuid &real_terminal_uuid) const; + RealTerminalData previousRealTerminal(const QUuid &real_terminal_uuid) const; + RealTerminalData nextRealTerminal(const QUuid &real_terminal_uuid) const; QVector> terminalElement() const; @@ -163,6 +172,7 @@ class TerminalStrip : public QObject QSharedPointer isBridged(const QSharedPointer real_terminal) const; QSharedPointer bridgeFor (const QVector> &terminal_vector) const; QSharedPointer bridgeForUuid (const QUuid &bridge_uuid); + void rebuildRealVector(); private: TerminalStripData m_data; diff --git a/sources/TerminalStrip/ui/terminalstripeditor.cpp b/sources/TerminalStrip/ui/terminalstripeditor.cpp index 4706dc227..eb193c1ea 100644 --- a/sources/TerminalStrip/ui/terminalstripeditor.cpp +++ b/sources/TerminalStrip/ui/terminalstripeditor.cpp @@ -60,8 +60,7 @@ TerminalStripEditor::TerminalStripEditor(QETProject *project, QWidget *parent) : #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); + ui->m_bridge_color_cb->setColors(TerminalStrip::bridgeColor().toList()); setUpUndoConnections(); @@ -329,7 +328,7 @@ void TerminalStripEditor::setCurrentStrip(TerminalStrip *strip_) m_model = new TerminalStripModel(strip_, this); ui->m_table_widget->setModel(m_model); - setUpBridgeCellWidth(); + m_model->buildBridgePixmap(setUpBridgeCellWidth()); spanMultiLevelTerminals(); selectionChanged(); //Used to update child widgets @@ -461,7 +460,7 @@ void TerminalStripEditor::selectionChanged() ui->m_unbridge_terminals_pb->setEnabled(enable_unbridge); } -void TerminalStripEditor::setUpBridgeCellWidth() +QSize TerminalStripEditor::setUpBridgeCellWidth() { if (ui->m_table_widget->verticalHeader() && m_model) @@ -469,15 +468,15 @@ void TerminalStripEditor::setUpBridgeCellWidth() 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); + 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); } /** diff --git a/sources/TerminalStrip/ui/terminalstripeditor.h b/sources/TerminalStrip/ui/terminalstripeditor.h index df07b5acf..7f73e1f17 100644 --- a/sources/TerminalStrip/ui/terminalstripeditor.h +++ b/sources/TerminalStrip/ui/terminalstripeditor.h @@ -53,7 +53,7 @@ class TerminalStripEditor : public QDialog void setCurrentStrip(TerminalStrip *strip_); void spanMultiLevelTerminals(); void selectionChanged(); - void setUpBridgeCellWidth(); + QSize setUpBridgeCellWidth(); TerminalStripModel::Column isSingleColumnSelected() const; private slots: diff --git a/sources/TerminalStrip/ui/terminalstripmodel.cpp b/sources/TerminalStrip/ui/terminalstripmodel.cpp index e0035a487..a5dc20747 100644 --- a/sources/TerminalStrip/ui/terminalstripmodel.cpp +++ b/sources/TerminalStrip/ui/terminalstripmodel.cpp @@ -24,6 +24,7 @@ #include #include #include +#include /** * Some const int who describe what a column contain @@ -143,18 +144,6 @@ 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_; @@ -186,6 +175,18 @@ QVariant TerminalStripModel::data(const QModelIndex &index, int role) const 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(); } @@ -403,6 +404,78 @@ RealTerminalData TerminalStripModel::realTerminalDataForIndex(const QModelIndex } } +/** + * @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_ : TerminalStrip::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 @@ -537,6 +610,127 @@ RealTerminalData TerminalStripModel::realDataAtIndex(int index) const return RealTerminalData(); } +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 rtd = realTerminalDataForIndex(index); + + //Terminal level correspond to the column level of index + if (level_column == rtd.level_) + { + if (rtd.is_bridged) + { + auto bridge_uuid = rtd.bridge_uuid; + auto previous_bridge_uuid = m_terminal_strip->previousTerminalInLevel(rtd.real_terminal_uuid).bridge_uuid; + auto next_bridge_uuid = m_terminal_strip->nextTerminalInLevel(rtd.real_terminal_uuid).bridge_uuid; + + auto color_ = m_terminal_strip->bridgeFor(rtd.real_terminal_uuid)->color_; + auto pixmap_ = m_bridges_pixmaps.value(color_); + + //Current real terminal between two bridged terminal + if ((bridge_uuid == previous_bridge_uuid) && + (bridge_uuid == next_bridge_uuid)) { + return pixmap_.middle_; + } else if (bridge_uuid == previous_bridge_uuid) { + return pixmap_.bottom_; + } else if (bridge_uuid == next_bridge_uuid) { + 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 physical_data = m_terminal_strip->physicalTerminalData(rtd); + auto current_real_uuid = rtd.real_terminal_uuid; + auto current_phy_uuid = physical_data.uuid_; + bool already_jumped_to_previous = false; + RealTerminalData previous_data; + + do { + auto previous_rtd = m_terminal_strip->previousRealTerminal(current_real_uuid); + current_real_uuid = previous_rtd.real_terminal_uuid; + + if (previous_rtd.level_ == -1) { + break; + } + + //We are in the same physical terminal as previous loop + if (current_phy_uuid == m_terminal_strip->physicalTerminalData(previous_rtd).uuid_) + { + if (previous_rtd.is_bridged && + previous_rtd.level_ == level_column) { + previous_data = previous_rtd; + 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->physicalTerminalData(previous_rtd).uuid_; + if (previous_rtd.is_bridged && + previous_rtd.level_ == level_column) { + previous_data = previous_rtd; + break; + } + } + } while(true); + + //Check next + current_real_uuid = rtd.real_terminal_uuid; + current_phy_uuid = physical_data.uuid_; + bool already_jumped_to_next = false; + RealTerminalData next_data; + do { + auto next_rtd = m_terminal_strip->nextRealTerminal(current_real_uuid); + current_real_uuid = next_rtd.real_terminal_uuid; + + if (next_rtd.level_ == -1) { + break; + } + + //We are in the same physical terminal as previous loop + if (current_phy_uuid == m_terminal_strip->physicalTerminalData(next_rtd).uuid_) + { + if (next_rtd.is_bridged && + next_rtd.level_ == level_column) { + next_data = next_rtd; + 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->physicalTerminalData(next_rtd).uuid_; + if (next_rtd.is_bridged && + next_rtd.level_ == level_column) { + next_data = next_rtd; + break; + } + } + } while(true); + + if (previous_data.bridge_uuid == next_data.bridge_uuid) { + auto bridge_ = m_terminal_strip->bridgeFor(previous_data.real_terminal_uuid); + if (bridge_) { + return m_bridges_pixmaps.value(bridge_->color_).none_; + } + } + + return QPixmap(); +} + /*********************************************************** * Alittle delegate for add a combobox to edit type * and a spinbox to edit the level of a terminal @@ -593,3 +787,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 78e356739..7c8ea6d70 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,10 +22,16 @@ #include #include #include -#include +#include +#include #include "../terminalstrip.h" +//Code to use QColor as key for QHash +inline uint qHash(const QColor &key, uint seed) { + return qHash(key.name(), seed); +} + class TerminalStrip; class TerminalStripModel : public QAbstractTableModel @@ -68,21 +74,31 @@ class TerminalStripModel : public QAbstractTableModel QVector realTerminalDataForIndex(QModelIndexList index_list) const; RealTerminalData realTerminalDataForIndex(const QModelIndex &index) 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; + QPixmap bridgePixmapFor(const QModelIndex &index) const; private: 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; + + struct BridgePixmap + { + QPixmap top_, + middle_, + bottom_, + none_; + }; + + QHash m_bridges_pixmaps; + }; class TerminalStripModelDelegate : public QStyledItemDelegate @@ -100,6 +116,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