From 2f6fb7808af1e8d3fd3e74ffd2b71fa1c8583ad8 Mon Sep 17 00:00:00 2001 From: Kellermorph Date: Sat, 22 Aug 2026 09:52:01 +0200 Subject: [PATCH] fix --- sources/properties/elementdata.h | 13 +++ sources/qetgraphicsitem/element.cpp | 17 ++-- sources/qetgraphicsitem/terminal.cpp | 4 +- sources/ui/masterpropertieswidget.cpp | 18 ++-- sources/undocommand/linkelementcommand.cpp | 110 ++++++++++----------- 5 files changed, 86 insertions(+), 76 deletions(-) diff --git a/sources/properties/elementdata.h b/sources/properties/elementdata.h index 952d9d484..51b9c9678 100644 --- a/sources/properties/elementdata.h +++ b/sources/properties/elementdata.h @@ -99,6 +99,19 @@ class ElementData : public PropertiesInterface int terminalCount = 1; ///< Number of terminals for this IO (1-4) QStringList terminals; ///< Terminal values T1, T2, ... (size = terminalCount) + /** + * @brief Return terminal labels, generating defaults (T1, T2...) if empty + */ + QStringList effectiveTerminals() const { + if (!terminals.isEmpty()) + return terminals; + int count = qMax(terminalCount, 1); + QStringList defaults; + for (int i = 0; i < count && i < 4; ++i) + defaults << QStringLiteral("T%1").arg(i + 1); + return defaults; + } + bool operator==(const PlcIO &other) const { return type == other.type && address == other.address diff --git a/sources/qetgraphicsitem/element.cpp b/sources/qetgraphicsitem/element.cpp index 4e65370d9..23c9eda42 100644 --- a/sources/qetgraphicsitem/element.cpp +++ b/sources/qetgraphicsitem/element.cpp @@ -38,6 +38,15 @@ #include "dynamicelementtextitem.h" #include "elementtextitemgroup.h" #include "iostream" + +#include + +static const QString plcTerminalKeys[] = { + QETInformation::ELMT_PLC_T1, + QETInformation::ELMT_PLC_T2, + QETInformation::ELMT_PLC_T3, + QETInformation::ELMT_PLC_T4 +}; #include "../qetxml.h" #include "../qetversion.h" #include "qgraphicsitemutility.h" @@ -1511,13 +1520,7 @@ void Element::setElementData(ElementData data) { 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); + ctx.addValue(plcTerminalKeys[t], val); } slave->setElementInformations(ctx); diff --git a/sources/qetgraphicsitem/terminal.cpp b/sources/qetgraphicsitem/terminal.cpp index b838eb1ce..9247af102 100644 --- a/sources/qetgraphicsitem/terminal.cpp +++ b/sources/qetgraphicsitem/terminal.cpp @@ -823,17 +823,15 @@ QUuid Terminal::uuid() const QString Terminal::name() const { if (d->m_use_master_label && parent_element_) { - // Find the master element in the slave's linked elements for (Element *elmt : parent_element_->linkedElements()) { if (elmt->linkType() == Element::Master) { int group_idx = elmt->groupIndexForElement(parent_element_); if (group_idx >= 0) { - // 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; + const QStringList labels = plc_data.ios.at(group_idx).effectiveTerminals(); if (label_idx >= 0 && label_idx < labels.size()) { return labels.at(label_idx); } diff --git a/sources/ui/masterpropertieswidget.cpp b/sources/ui/masterpropertieswidget.cpp index 4f5891f5b..d828a9344 100644 --- a/sources/ui/masterpropertieswidget.cpp +++ b/sources/ui/masterpropertieswidget.cpp @@ -979,14 +979,7 @@ void MasterPropertiesWidget::plcUpdateDisplaySettings() ElementData::PlcMasterData plc_data = ed.plcMasterData(); plc_data.ios.clear(); - // Build address -> original IO lookup to correctly reattach terminal data - // after row reorder (move up/down) or row removal - QHash addr_to_orig_idx; - for (int i = 0; i < ed.plcMasterData().ios.size(); ++i) { - addr_to_orig_idx[ed.plcMasterData().ios.at(i).address] = i; - } - - // Read IOs from table, preserving terminal data from original IOs + // Read IOs from table, preserving terminal data from original IOs by row index for (int row = 0; row < m_plc_table->rowCount(); ++row) { ElementData::PlcIO io; @@ -1010,9 +1003,12 @@ void MasterPropertiesWidget::plcUpdateDisplaySettings() if (crossref_item) io.crossRef = crossref_item->text(); - // Preserve terminal data by looking up original IO via address - if (addr_to_orig_idx.contains(io.address)) { - const auto orig_io = ed.plcMasterData().ios.at(addr_to_orig_idx.value(io.address)); + // Preserve terminal data by matching row index directly. + // This avoids address-based lookup which fails when all addresses + // are empty (common in PLC masters) — a hash collision would cause + // only the last IO's terminals to be used for all rows. + 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; } diff --git a/sources/undocommand/linkelementcommand.cpp b/sources/undocommand/linkelementcommand.cpp index a785420af..51860a944 100644 --- a/sources/undocommand/linkelementcommand.cpp +++ b/sources/undocommand/linkelementcommand.cpp @@ -31,6 +31,16 @@ #include "../autoNum/assignvariables.h" #include "../autoNum/numerotationcontextcommands.h" +#include +#include + +static const QString plcTerminalKeys[] = { + QETInformation::ELMT_PLC_T1, + QETInformation::ELMT_PLC_T2, + QETInformation::ELMT_PLC_T3, + QETInformation::ELMT_PLC_T4 +}; + /** @brief Get the cross-ref text for a slave element using XRefProperties formula @param master the PLC master element @@ -408,15 +418,16 @@ void LinkElementCommand::makeLink(const QList &element_list) // Set master labels on slave terminals if (elmt->elementData().m_master_type == ElementData::PLC) { - // For PLC masters, use io.terminals as labels const auto &plc_data = elmt->elementData().plcMasterData(); if (group_idx < plc_data.ios.size()) { - const QStringList &labels = plc_data.ios.at(group_idx).terminals; + const QStringList labels = plc_data.ios.at(group_idx).effectiveTerminals(); QList slave_terms = m_element->terminals(); + QCollator collator; + collator.setNumericMode(true); std::sort(slave_terms.begin(), slave_terms.end(), - [](Terminal *a, Terminal *b) { - return a->baseName() < b->baseName(); + [&collator](Terminal *a, Terminal *b) { + return collator.compare(a->baseName(), b->baseName()) < 0; }); for (int i = 0; i < slave_terms.size(); ++i) { @@ -426,6 +437,29 @@ void LinkElementCommand::makeLink(const QList &element_list) slave_terms.at(i)->setMasterLabelIndex(i); } } + + // Populate PLC variables on the slave + const auto &io = plc_data.ios.at(group_idx); + DiagramContext ctx = m_element->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, + plcCrossRefText(elmt, m_element)); + ctx.addValue(QETInformation::ELMT_LABEL, + elmt->actualLabel()); + ctx.addValue(QETInformation::ELMT_PLC_TC, + QString::number(io.terminalCount)); + const QStringList eff_terms = io.effectiveTerminals(); + for (int t = 0; t < io.terminalCount && t < 4; ++t) + { + QString val = (t < eff_terms.size()) + ? eff_terms.at(t) : QString(); + ctx.addValue(plcTerminalKeys[t], val); + } + m_element->setElementInformations(ctx); } } else @@ -435,9 +469,11 @@ void LinkElementCommand::makeLink(const QList &element_list) { const QStringList &labels = groups.at(group_idx).labels; QList slave_terms = m_element->terminals(); + QCollator collator; + collator.setNumericMode(true); std::sort(slave_terms.begin(), slave_terms.end(), - [](Terminal *a, Terminal *b) { - return a->baseName() < b->baseName(); + [&collator](Terminal *a, Terminal *b) { + return collator.compare(a->baseName(), b->baseName()) < 0; }); for (int i = 0; i < slave_terms.size(); ++i) { @@ -450,41 +486,6 @@ void LinkElementCommand::makeLink(const QList &element_list) } } - // Populate PLC variables on the slave if master is PLC type - if (elmt->elementData().m_master_type == ElementData::PLC) - { - const auto &plc_data = elmt->elementData().plcMasterData(); - if (group_idx < plc_data.ios.size()) - { - const auto &io = plc_data.ios.at(group_idx); - DiagramContext ctx = m_element->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, - 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); - } - } - break; } } @@ -507,11 +508,13 @@ void LinkElementCommand::makeLink(const QList &element_list) const auto &plc_data = m_element->elementData().plcMasterData(); if (group_idx < plc_data.ios.size()) { - const QStringList &labels = plc_data.ios.at(group_idx).terminals; + const QStringList labels = plc_data.ios.at(group_idx).effectiveTerminals(); QList slave_terms = slave->terminals(); + QCollator collator; + collator.setNumericMode(true); std::sort(slave_terms.begin(), slave_terms.end(), - [](Terminal *a, Terminal *b) { - return a->baseName() < b->baseName(); + [&collator](Terminal *a, Terminal *b) { + return collator.compare(a->baseName(), b->baseName()) < 0; }); for (int i = 0; i < slave_terms.size(); ++i) { @@ -530,9 +533,11 @@ void LinkElementCommand::makeLink(const QList &element_list) { const QStringList &labels = groups.at(group_idx).labels; QList slave_terms = slave->terminals(); + QCollator collator; + collator.setNumericMode(true); std::sort(slave_terms.begin(), slave_terms.end(), - [](Terminal *a, Terminal *b) { - return a->name() < b->name(); + [&collator](Terminal *a, Terminal *b) { + return collator.compare(a->baseName(), b->baseName()) < 0; }); for (int i = 0; i < slave_terms.size(); ++i) { @@ -564,17 +569,12 @@ void LinkElementCommand::makeLink(const QList &element_list) m_element->actualLabel()); ctx.addValue(QETInformation::ELMT_PLC_TC, QString::number(io.terminalCount)); + const QStringList eff_terms = io.effectiveTerminals(); 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); + QString val = (t < eff_terms.size()) + ? eff_terms.at(t) : QString(); + ctx.addValue(plcTerminalKeys[t], val); } slave->setElementInformations(ctx); }