From 4c1f82f81481ee37ed14cf3d0006ae95d37e2c18 Mon Sep 17 00:00:00 2001 From: Kellermorph Date: Fri, 31 Jul 2026 21:02:07 +0200 Subject: [PATCH] Fix-PLC-Manager --- sources/autoNum/assignvariables.cpp | 5 + sources/editor/ui/dynamictextfieldeditor.cpp | 12 ++- .../ui/elementpropertieseditorwidget.cpp | 2 +- sources/qetgraphicsitem/element.cpp | 98 +++++++++++++++---- sources/qetgraphicsitem/terminal.cpp | 49 ++++++++-- sources/qetgraphicsitem/terminal.h | 1 + sources/qetinformation.h | 5 + sources/ui/masterpropertieswidget.cpp | 9 +- sources/undocommand/linkelementcommand.cpp | 64 +++++++++--- 9 files changed, 200 insertions(+), 45 deletions(-) diff --git a/sources/autoNum/assignvariables.cpp b/sources/autoNum/assignvariables.cpp index 8f58adff1..4cf4017ae 100644 --- a/sources/autoNum/assignvariables.cpp +++ b/sources/autoNum/assignvariables.cpp @@ -280,6 +280,11 @@ namespace autonum str.replace("%{plc_function}", dc.value("plc_function").toString()); str.replace("%{plc_comment}", dc.value("plc_comment").toString()); str.replace("%{plc_crossref}", dc.value("plc_crossref").toString()); + str.replace("%{plc_tc}", dc.value("plc_tc").toString()); + str.replace("%{plc_t1}", dc.value("plc_t1").toString()); + str.replace("%{plc_t2}", dc.value("plc_t2").toString()); + str.replace("%{plc_t3}", dc.value("plc_t3").toString()); + str.replace("%{plc_t4}", dc.value("plc_t4").toString()); return str; } diff --git a/sources/editor/ui/dynamictextfieldeditor.cpp b/sources/editor/ui/dynamictextfieldeditor.cpp index 636fee3e3..fb23c8141 100644 --- a/sources/editor/ui/dynamictextfieldeditor.cpp +++ b/sources/editor/ui/dynamictextfieldeditor.cpp @@ -240,7 +240,12 @@ void DynamicTextFieldEditor::fillInfoComboBox() QETInformation::ELMT_PLC_ADDRESS, QETInformation::ELMT_PLC_FUNCTION, QETInformation::ELMT_PLC_COMMENT, - QETInformation::ELMT_PLC_CROSSREF + QETInformation::ELMT_PLC_CROSSREF, + QETInformation::ELMT_PLC_TC, + QETInformation::ELMT_PLC_T1, + QETInformation::ELMT_PLC_T2, + QETInformation::ELMT_PLC_T3, + QETInformation::ELMT_PLC_T4 }; strl = plc_keys + strl; } else { @@ -249,6 +254,11 @@ void DynamicTextFieldEditor::fillInfoComboBox() strl.removeAll(QETInformation::ELMT_PLC_FUNCTION); strl.removeAll(QETInformation::ELMT_PLC_COMMENT); strl.removeAll(QETInformation::ELMT_PLC_CROSSREF); + strl.removeAll(QETInformation::ELMT_PLC_TC); + strl.removeAll(QETInformation::ELMT_PLC_T1); + strl.removeAll(QETInformation::ELMT_PLC_T2); + strl.removeAll(QETInformation::ELMT_PLC_T3); + strl.removeAll(QETInformation::ELMT_PLC_T4); } } diff --git a/sources/editor/ui/elementpropertieseditorwidget.cpp b/sources/editor/ui/elementpropertieseditorwidget.cpp index b0cf07018..9c0407d21 100644 --- a/sources/editor/ui/elementpropertieseditorwidget.cpp +++ b/sources/editor/ui/elementpropertieseditorwidget.cpp @@ -780,7 +780,7 @@ void ElementPropertiesEditorWidget::createPlcConfigWidgets() auto *sb = new QSpinBox(m_plc_gb); sb->setMinimum(10); - sb->setMaximum(200); + sb->setMaximum(500); sb->setValue(40); sb->setSuffix(tr(" mm")); m_plc_col_width_spinboxes.append(sb); diff --git a/sources/qetgraphicsitem/element.cpp b/sources/qetgraphicsitem/element.cpp index e8eb71e66..58d00dcd2 100644 --- a/sources/qetgraphicsitem/element.cpp +++ b/sources/qetgraphicsitem/element.cpp @@ -1396,6 +1396,23 @@ void Element::setElementInformations(DiagramContext dc) m_data.m_informations.addValue(QStringLiteral("label"), actual_label); //Update the label if there is a formula } emit elementInfoChange(old_info, m_data.m_informations); + + // Propagate label change to linked PLC slaves + if (m_data.m_type == ElementData::Master && m_data.m_master_type == ElementData::PLC) + { + if (!m_group_index_map.isEmpty()) { + const QString new_label = actualLabel(); + for (auto it = m_group_index_map.constBegin(); it != m_group_index_map.constEnd(); ++it) + { + Element *slave = it.key(); + if (!slave) + continue; + DiagramContext ctx = slave->elementInformations(); + ctx.addValue(QETInformation::ELMT_LABEL, new_label); + slave->setElementInformations(ctx); + } + } + } } /** @@ -1433,7 +1450,9 @@ void Element::setElementData(ElementData data) { const auto &new_plc = m_data.plcMasterData(); bool plc_changed = (old_plc.ios != new_plc.ios); - if (plc_changed && !m_group_index_map.isEmpty()) + bool label_changed = (old_info.value(QStringLiteral("label")) != + m_data.m_informations.value(QStringLiteral("label"))); + if (!m_group_index_map.isEmpty() && (plc_changed || label_changed)) { for (auto it = m_group_index_map.constBegin(); it != m_group_index_map.constEnd(); ++it) { @@ -1442,24 +1461,63 @@ void Element::setElementData(ElementData data) if (!slave || io_idx < 0 || io_idx >= new_plc.ios.size()) continue; const auto &io = new_plc.ios.at(io_idx); - DiagramContext ctx = slave->elementInformations(); - ctx.addValue(QETInformation::ELMT_PLC_TYPE, - ElementData::translatedPlcIOType(io.type)); - ctx.addValue(QETInformation::ELMT_PLC_ADDRESS, io.address); - ctx.addValue(QETInformation::ELMT_PLC_FUNCTION, io.functionText); - ctx.addValue(QETInformation::ELMT_PLC_COMMENT, io.comment); - ctx.addValue(QETInformation::ELMT_PLC_CROSSREF, - [&]() -> QString { - if (!diagram() || !diagram()->project()) - return QString(); - XRefProperties xrp = diagram()->project() - ->defaultXRefProperties("plc"); - autonum::sequentialNumbers seq; - return autonum::AssignVariables::formulaToLabel( - xrp.slaveLabel(), seq, diagram(), this); - }()); - ctx.addValue(QETInformation::ELMT_LABEL, actualLabel()); - slave->setElementInformations(ctx); + + if (plc_changed) + { + DiagramContext ctx = slave->elementInformations(); + ctx.addValue(QETInformation::ELMT_PLC_TYPE, + ElementData::translatedPlcIOType(io.type)); + ctx.addValue(QETInformation::ELMT_PLC_ADDRESS, io.address); + ctx.addValue(QETInformation::ELMT_PLC_FUNCTION, io.functionText); + ctx.addValue(QETInformation::ELMT_PLC_COMMENT, io.comment); + ctx.addValue(QETInformation::ELMT_PLC_CROSSREF, + [&]() -> QString { + if (!diagram() || !diagram()->project()) + return QString(); + XRefProperties xrp = diagram()->project() + ->defaultXRefProperties("plc"); + autonum::sequentialNumbers seq; + return autonum::AssignVariables::formulaToLabel( + xrp.slaveLabel(), seq, diagram(), this); + }()); + ctx.addValue(QETInformation::ELMT_PLC_TC, + QString::number(io.terminalCount)); + for (int t = 0; t < io.terminalCount && t < 4; ++t) + { + QString val = (t < io.terminals.size()) + ? io.terminals.at(t) : QString(); + ctx.addValue( + QStringList({ + QETInformation::ELMT_PLC_T1, + QETInformation::ELMT_PLC_T2, + QETInformation::ELMT_PLC_T3, + QETInformation::ELMT_PLC_T4 + }).at(t), val); + } + slave->setElementInformations(ctx); + + // Update master labels on slave terminals + QList slave_terms = slave->terminals(); + for (int t = 0; t < slave_terms.size(); ++t) + { + if (t < io.terminals.size()) + { + slave_terms.at(t)->setUseMasterLabel(true); + slave_terms.at(t)->setMasterLabelIndex(t); + } + else + { + slave_terms.at(t)->setUseMasterLabel(false); + } + } + } + else if (label_changed) + { + // Only label changed, update the label on the slave + DiagramContext ctx = slave->elementInformations(); + ctx.addValue(QETInformation::ELMT_LABEL, actualLabel()); + slave->setElementInformations(ctx); + } } } } @@ -1900,7 +1958,7 @@ void Element::drawPlcTable(QPainter *painter) } QRectF text_rect = cr.adjusted(1, 0, -1, 0); - painter->drawText(text_rect, Qt::AlignLeft | Qt::AlignVCenter, cell_text); + painter->drawText(text_rect, Qt::AlignLeft | Qt::AlignVCenter | Qt::TextWordWrap, cell_text); cx += col_widths[col]; } diff --git a/sources/qetgraphicsitem/terminal.cpp b/sources/qetgraphicsitem/terminal.cpp index 32584aebb..ee041c632 100644 --- a/sources/qetgraphicsitem/terminal.cpp +++ b/sources/qetgraphicsitem/terminal.cpp @@ -289,8 +289,17 @@ void Terminal::paint( painter->save(); painter->translate(label_pos); painter->rotate(d->m_label_rotation); - QRectF text_rect(-text_size.width()/2.0, -text_size.height()/2.0, - text_size.width(), text_size.height()); + + qreal rx = 0, ry = 0; + if (d->m_label_halignment & Qt::AlignLeft) rx = 0; + else if (d->m_label_halignment & Qt::AlignHCenter) rx = -text_size.width() / 2.0; + else if (d->m_label_halignment & Qt::AlignRight) rx = -text_size.width(); + + if (d->m_label_valignment & Qt::AlignTop) ry = 0; + else if (d->m_label_valignment & Qt::AlignVCenter) ry = -text_size.height() / 2.0; + else if (d->m_label_valignment & Qt::AlignBottom) ry = -text_size.height(); + + QRectF text_rect(QPointF(rx, ry), text_size); painter->drawText(text_rect, static_cast(d->m_label_halignment | d->m_label_valignment), display_name); painter->restore(); } else { @@ -307,7 +316,7 @@ void Terminal::paint( if (d->m_label_frame) { painter->drawRect(text_rect.adjusted(-1, -1, 1, 1)); } - painter->drawText(text_rect, static_cast(Qt::AlignLeft | Qt::AlignTop), display_name); + painter->drawText(text_rect, static_cast(d->m_label_halignment | d->m_label_valignment), display_name); } } @@ -816,12 +825,24 @@ QString Terminal::name() const if (elmt->linkType() == Element::Master) { int group_idx = elmt->groupIndexForElement(parent_element_); if (group_idx >= 0) { - const auto &groups = elmt->elementData().m_slave_contact_groups; - if (group_idx < groups.size()) { - int label_idx = d->m_master_label_index; - const QStringList &labels = groups.at(group_idx).labels; - if (label_idx >= 0 && label_idx < labels.size()) { - return labels.at(label_idx); + // For PLC masters, use io.terminals as labels + if (elmt->elementData().m_master_type == ElementData::PLC) { + const auto &plc_data = elmt->elementData().plcMasterData(); + if (group_idx < plc_data.ios.size()) { + int label_idx = d->m_master_label_index; + const QStringList &labels = plc_data.ios.at(group_idx).terminals; + if (label_idx >= 0 && label_idx < labels.size()) { + return labels.at(label_idx); + } + } + } else { + const auto &groups = elmt->elementData().m_slave_contact_groups; + if (group_idx < groups.size()) { + int label_idx = d->m_master_label_index; + const QStringList &labels = groups.at(group_idx).labels; + if (label_idx >= 0 && label_idx < labels.size()) { + return labels.at(label_idx); + } } } } @@ -832,6 +853,16 @@ QString Terminal::name() const return d->m_name; } +/** + @brief Terminal::baseName + Return the original terminal name (T1, T2...) without master label override. + Used for sorting when linking. +*/ +QString Terminal::baseName() const +{ + return d->m_name; +} + /** @brief Terminal::terminalType @return the type of this terminal (Generic, Inner, Outer, No, Nc, Common) diff --git a/sources/qetgraphicsitem/terminal.h b/sources/qetgraphicsitem/terminal.h index eac284553..53606b698 100644 --- a/sources/qetgraphicsitem/terminal.h +++ b/sources/qetgraphicsitem/terminal.h @@ -76,6 +76,7 @@ class Terminal : public QGraphicsObject Element *parentElement () const; QUuid uuid () const; QString name () const; + QString baseName () const; TerminalData::Type terminalType() const; bool useMasterLabel() const { return d->m_use_master_label; } void setUseMasterLabel(bool use); diff --git a/sources/qetinformation.h b/sources/qetinformation.h index 2dd566ffd..2aab78e95 100644 --- a/sources/qetinformation.h +++ b/sources/qetinformation.h @@ -130,6 +130,11 @@ namespace QETInformation static QString ELMT_PLC_FUNCTION = "plc_function"; static QString ELMT_PLC_COMMENT = "plc_comment"; static QString ELMT_PLC_CROSSREF = "plc_crossref"; + static QString ELMT_PLC_TC = "plc_tc"; + static QString ELMT_PLC_T1 = "plc_t1"; + static QString ELMT_PLC_T2 = "plc_t2"; + static QString ELMT_PLC_T3 = "plc_t3"; + static QString ELMT_PLC_T4 = "plc_t4"; diff --git a/sources/ui/masterpropertieswidget.cpp b/sources/ui/masterpropertieswidget.cpp index 25aede52a..d7f4d1182 100644 --- a/sources/ui/masterpropertieswidget.cpp +++ b/sources/ui/masterpropertieswidget.cpp @@ -978,7 +978,7 @@ void MasterPropertiesWidget::plcUpdateDisplaySettings() ElementData::PlcMasterData plc_data = ed.plcMasterData(); plc_data.ios.clear(); - // Read IOs from table + // Read IOs from table, preserving terminal data from original IOs for (int row = 0; row < m_plc_table->rowCount(); ++row) { ElementData::PlcIO io; @@ -1002,6 +1002,13 @@ void MasterPropertiesWidget::plcUpdateDisplaySettings() if (crossref_item) io.crossRef = crossref_item->text(); + // Preserve terminal data from the original IO + if (row < ed.plcMasterData().ios.size()) { + const auto &orig_io = ed.plcMasterData().ios.at(row); + io.terminalCount = orig_io.terminalCount; + io.terminals = orig_io.terminals; + } + plc_data.ios.append(io); } diff --git a/sources/undocommand/linkelementcommand.cpp b/sources/undocommand/linkelementcommand.cpp index 924d11c56..6f52387ea 100644 --- a/sources/undocommand/linkelementcommand.cpp +++ b/sources/undocommand/linkelementcommand.cpp @@ -406,22 +406,46 @@ void LinkElementCommand::makeLink(const QList &element_list) elmt->setGroupIndexForElement(m_element, group_idx); // Set master labels on slave terminals - const auto &groups = elmt->elementData().m_slave_contact_groups; - if (group_idx < groups.size()) + if (elmt->elementData().m_master_type == ElementData::PLC) { - const QStringList &labels = groups.at(group_idx).labels; - QList slave_terms = m_element->terminals(); - // Sort terminals by name (T1, T2, T3...) to match label order - std::sort(slave_terms.begin(), slave_terms.end(), - [](Terminal *a, Terminal *b) { - return a->name() < b->name(); - }); - for (int i = 0; i < slave_terms.size(); ++i) + // For PLC masters, use io.terminals as labels + const auto &plc_data = elmt->elementData().plcMasterData(); + if (group_idx < plc_data.ios.size()) { - if (i < labels.size()) + const QStringList &labels = plc_data.ios.at(group_idx).terminals; + QList slave_terms = m_element->terminals(); + std::sort(slave_terms.begin(), slave_terms.end(), + [](Terminal *a, Terminal *b) { + return a->baseName() < b->baseName(); + }); + for (int i = 0; i < slave_terms.size(); ++i) { - slave_terms.at(i)->setUseMasterLabel(true); - slave_terms.at(i)->setMasterLabelIndex(i); + if (i < labels.size()) + { + slave_terms.at(i)->setUseMasterLabel(true); + slave_terms.at(i)->setMasterLabelIndex(i); + } + } + } + } + else + { + const auto &groups = elmt->elementData().m_slave_contact_groups; + if (group_idx < groups.size()) + { + const QStringList &labels = groups.at(group_idx).labels; + QList slave_terms = m_element->terminals(); + std::sort(slave_terms.begin(), slave_terms.end(), + [](Terminal *a, Terminal *b) { + return a->baseName() < b->baseName(); + }); + for (int i = 0; i < slave_terms.size(); ++i) + { + if (i < labels.size()) + { + slave_terms.at(i)->setUseMasterLabel(true); + slave_terms.at(i)->setMasterLabelIndex(i); + } } } } @@ -443,6 +467,20 @@ void LinkElementCommand::makeLink(const QList &element_list) plcCrossRefText(elmt, m_element)); ctx.addValue(QETInformation::ELMT_LABEL, elmt->actualLabel()); + ctx.addValue(QETInformation::ELMT_PLC_TC, + QString::number(io.terminalCount)); + for (int t = 0; t < io.terminalCount && t < 4; ++t) + { + QString val = (t < io.terminals.size()) + ? io.terminals.at(t) : QString(); + ctx.addValue( + QStringList({ + QETInformation::ELMT_PLC_T1, + QETInformation::ELMT_PLC_T2, + QETInformation::ELMT_PLC_T3, + QETInformation::ELMT_PLC_T4 + }).at(t), val); + } m_element->setElementInformations(ctx); } }