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 <noreply@anthropic.com>
This commit is contained in:
DaTweety
2026-10-18 11:21:08 +02:00
parent fa498a3d20
commit a0e2193971
3 changed files with 71 additions and 15 deletions
+16
View File
@@ -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):
+53 -15
View File
@@ -128,7 +128,49 @@ bool ConductorCreator::needsPotentialChoice(const QList<Terminal *> &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<ConductorProperties> ConductorCreator::distinctProperties(const QList<Conductor *> &potentials)
{
QList<ConductorProperties> 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<ConductorProperties> cp_list = distinctProperties(potentials);
if (cp_list.size() >= 2)
{
QList <ConductorProperties> 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;
}
+2
View File
@@ -42,6 +42,8 @@ class ConductorCreator
private:
static QList<Conductor *> existingPotential(const QList<Terminal *> &terminals_list);
static ConductorProperties inheritedProperties(const Conductor *conductor);
static QList<ConductorProperties> distinctProperties(const QList<Conductor *> &potentials);
bool setUpPropertieToUse();
Terminal *hubTerminal();
QList<QPair<Terminal *, Terminal *>> terminalPairs(bool chain);