From a0e2193971d3e465acde583677922fe8c699be8d Mon Sep 17 00:00:00 2001 From: DaTweety <129504390+DaTweety@users.noreply.github.com> Date: Sun, 18 Oct 2026 11:21:08 +0200 Subject: [PATCH] Joining potentials: agreeing ones leave nothing to choose ConductorCreator asked which potential's properties to keep whenever a new wire joined two potentials, even when they agreed in every property; headless (scripting, qet MCP) such a wire was refused. Only distinct properties are offered now, and with one left the wire takes it. A potential's properties seen through one of a cable's cores carried the core with them -- cable, cable uuid, core slot, and the core label CableManager writes as text -- so a new wire claimed to be that core. They are cleared; the text is left to the formula. Co-Authored-By: Claude Opus 5.5 --- misc/qet-mcp/test_qet_mcp.py | 16 +++++++ sources/utils/conductorcreator.cpp | 68 +++++++++++++++++++++++------- sources/utils/conductorcreator.h | 2 + 3 files changed, 71 insertions(+), 15 deletions(-) diff --git a/misc/qet-mcp/test_qet_mcp.py b/misc/qet-mcp/test_qet_mcp.py index 1174b1f5d..57af9cdf0 100644 --- a/misc/qet-mcp/test_qet_mcp.py +++ b/misc/qet-mcp/test_qet_mcp.py @@ -4534,12 +4534,28 @@ class Integration(unittest.TestCase): for i in range(4)], {"op": "add_conductor", "folio": "$f", "from": "$e0", "from_terminal": 0, "to": "$e1", "to_terminal": 0}, {"op": "add_conductor", "folio": "$f", "from": "$e2", "from_terminal": 0, "to": "$e3", "to_terminal": 0}, + {"op": "set_conductor", "folio": "$f", "element": "$e2", "terminal": 0, "property": "num", "value": "W2"}, {"op": "add_conductor", "folio": "$f", "from": "$e0", "from_terminal": 0, "to": "$e2", "to_terminal": 0}, ], self.sb.p("conflict.qet"), elements_dir=ELEMENTS, timeout=60) self.assertFalse(r.get("timed_out"), "the call hung on a modal dialog") self.assertFalse(r["ok"]) self.assertEqual(r["operations"][-1]["result"], False) + def test_joining_two_agreeing_potentials_asks_nothing(self): + """Two potentials with the same properties leave nothing to choose: + the wire joining them is drawn, headless as well.""" + base = self.sb.new() + r = self.ok(self.sb.edit(base, [ + {"op": "add_folio", "id": "f"}, + *[{"op": "add_element", "id": f"e{i}", "folio": "$f", "path": COIL, "x": 100 + i * 200, "y": 100} + for i in range(4)], + {"op": "add_conductor", "folio": "$f", "from": "$e0", "from_terminal": 0, "to": "$e1", "to_terminal": 0}, + {"op": "set_conductor", "folio": "$f", "element": "$e0", "terminal": 0, "property": "num", "value": "N"}, + {"op": "add_conductor", "folio": "$f", "from": "$e2", "from_terminal": 0, "to": "$e3", "to_terminal": 0}, + {"op": "set_conductor", "folio": "$f", "element": "$e2", "terminal": 0, "property": "num", "value": "N"}, + {"op": "add_conductor", "folio": "$f", "from": "$e0", "from_terminal": 0, "to": "$e2", "to_terminal": 0}])) + self.assertEqual([c["num"] for c in m.tool_conductors(r["output"])["conductors"]], ["N"] * 3) + # ---- edit: conductor properties, potentials ---- def test_conductor_property_applies_to_the_whole_potential(self): diff --git a/sources/utils/conductorcreator.cpp b/sources/utils/conductorcreator.cpp index f3c808b9b..fdfd593b2 100644 --- a/sources/utils/conductorcreator.cpp +++ b/sources/utils/conductorcreator.cpp @@ -128,7 +128,49 @@ bool ConductorCreator::needsPotentialChoice(const QList &terminals_l if (terminals_list.size() <= 1) { return false; } - return existingPotential(terminals_list).size() >= 2; + return distinctProperties(existingPotential(terminals_list)).size() >= 2; +} + +/** + @brief ConductorCreator::inheritedProperties + The properties a new wire takes from @p conductor's potential. A + cable's core names the cable and the core in m_cable, m_cable_uuid, + m_cable_slot and, written by CableManager, in its text (15W1:BN): none + of that belongs to a new wire, which is in no cable yet. The text is + then left to the formula. + @param conductor : a conductor of the potential + @return the properties for a new conductor of that potential +*/ +ConductorProperties ConductorCreator::inheritedProperties(const Conductor *conductor) +{ + ConductorProperties properties = conductor->properties(); + if (!properties.m_cable_uuid.isNull()) + { + properties.m_cable.clear(); + properties.m_cable_uuid = QUuid(); + properties.m_cable_slot = -1; + properties.text.clear(); + } + return properties; +} + +/** + @brief ConductorCreator::distinctProperties + @param potentials : one conductor of each potential (existingPotential()) + @return the properties a new wire could inherit from them, each once: + two potentials that agree leave nothing to choose +*/ +QList ConductorCreator::distinctProperties(const QList &potentials) +{ + QList list; + for (const Conductor *c : potentials) + { + const ConductorProperties properties = inheritedProperties(c); + if (!list.contains(properties)) { + list.append(properties); + } + } + return list; } /** @@ -146,28 +188,24 @@ bool ConductorCreator::setUpPropertieToUse() //we get one of them if (!potentials.isEmpty()) { - if (potentials.size() >= 2) + const QList cp_list = distinctProperties(potentials); + if (cp_list.size() >= 2) { - QList cp_list; - for(Conductor *c : potentials) { - cp_list.append(c->properties()); - } - bool cancelled = false; m_properties = PotentialSelectorDialog::chosenProperties(cp_list, nullptr, &cancelled); if (cancelled) { return false; } - for (Conductor *c : potentials) { - if (c->properties() == m_properties) { - m_sequential_number = c->sequenceNum(); - } - } } - else if (potentials.size() == 1) + else { - m_properties = potentials.first()->properties(); - m_sequential_number = potentials.first()->sequenceNum(); + m_properties = cp_list.first(); + } + for (Conductor *c : potentials) { + if (inheritedProperties(c) == m_properties) { + m_sequential_number = c->sequenceNum(); + break; + } } return true; } diff --git a/sources/utils/conductorcreator.h b/sources/utils/conductorcreator.h index a8c2c9a6a..3551d3eec 100644 --- a/sources/utils/conductorcreator.h +++ b/sources/utils/conductorcreator.h @@ -42,6 +42,8 @@ class ConductorCreator private: static QList existingPotential(const QList &terminals_list); + static ConductorProperties inheritedProperties(const Conductor *conductor); + static QList distinctProperties(const QList &potentials); bool setUpPropertieToUse(); Terminal *hubTerminal(); QList> terminalPairs(bool chain);