From 2e2801b617ec65e4d15875a7809bb62a715cf42a Mon Sep 17 00:00:00 2001 From: ispyisail Date: Sat, 3 Oct 2026 21:49:06 +1300 Subject: [PATCH] Fix qet.deleteElement() leaving the element's wires on the folio qet.deleteElement() built its DeleteQGraphicsItemCommand from the element alone. The Delete key's selection also carries the wires on the element's terminals (DiagramContent's conductors to update), and the command removes those with it. From a script they stayed: still listed by qet.conductorUuids(), still saved, attached to an element that was gone. The wires on the element's terminals now go into the command, as for the Delete key. tst_scriptconductoruuid checks that no wire is left with an end on the deleted element (it failed before this change: 1 left). Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_015FPuYPS4T7QuEwjNu22rXD --- sources/scripting/qetscriptapi.cpp | 10 ++++++++++ tests/qttest/tst_scriptconductoruuid.cpp | 22 ++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/sources/scripting/qetscriptapi.cpp b/sources/scripting/qetscriptapi.cpp index d61768793..854502c89 100644 --- a/sources/scripting/qetscriptapi.cpp +++ b/sources/scripting/qetscriptapi.cpp @@ -772,6 +772,16 @@ bool QetScriptApi::deleteElement(int folioIndex, const QString &elementUuid) DiagramContent content; content.m_elements << element; + // The wires on its terminals go with it, as when the Delete key + // removes a selected element (DiagramContent puts them in + // m_conductors_to_update); without them they stay on the folio, + // attached to an element that is no longer there. + for (Terminal *terminal : element->terminals()) { + for (Conductor *conductor : terminal->conductors()) { + if (!content.m_conductors_to_update.contains(conductor)) + content.m_conductors_to_update << conductor; + } + } if (DeleteQGraphicsItemCommand::hasNonDeletableTerminal(content)) { log(QStringLiteral("qet.deleteElement: %1 has a non-deletable terminal (linked master/slave?), refusing").arg(elementUuid)); return false; diff --git a/tests/qttest/tst_scriptconductoruuid.cpp b/tests/qttest/tst_scriptconductoruuid.cpp index 27792ab70..763f61f14 100644 --- a/tests/qttest/tst_scriptconductoruuid.cpp +++ b/tests/qttest/tst_scriptconductoruuid.cpp @@ -97,6 +97,28 @@ private slots: QVERIFY(r.value(QStringLiteral("junk")).toArray().isEmpty()); QVERIFY(r.value(QStringLiteral("badFolio")).toArray().isEmpty()); } + + // qet.deleteElement() takes the wires on the element's terminals with + // it, as the Delete key does; they used to stay on the folio, attached + // to an element that was gone. + void deleteElementTakesItsWires() + { + const QJsonObject r = run(QStringLiteral( + "var p = 'embed://import/probe/v2_fuse.elmt';\n" + "var a = qet.addElement(0, p, 400, 400);\n" + "var b = qet.addElement(0, p, 470, 490);\n" + "qet.addConductor(0, a, 0, b, 0);\n" + "var before = qet.conductorUuids(0).length;\n" + "var deleted = qet.deleteElement(0, a);\n" + "var dangling = qet.conductorUuids(0).filter(function (u) {\n" + " return qet.conductorEnds(0, u).some(function (e) { return e.indexOf(a) === 0; }); });\n" + "qet.log('PROBE ' + JSON.stringify({deleted: deleted, before: before,\n" + " after: qet.conductorUuids(0).length, dangling: dangling.length}));\n")); + QVERIFY2(!r.isEmpty(), "the script logged nothing"); + QVERIFY(r.value(QStringLiteral("deleted")).toBool()); + QCOMPARE(r.value(QStringLiteral("dangling")).toInt(), 0); + QCOMPARE(r.value(QStringLiteral("after")).toInt(), r.value(QStringLiteral("before")).toInt() - 1); + } }; QTEST_APPLESS_MAIN(tst_scriptconductoruuid)