From 0fdcd1e1e8426b7eb6845bfa17018ff4994bd360 Mon Sep 17 00:00:00 2001 From: ispyisail Date: Fri, 21 Aug 2026 19:07:40 +1200 Subject: [PATCH] Regenerate conductor uuids when a folio is duplicated ElementsPanelWidget::duplicateDiagram() round-trips the folio through XML and then gives the copied *elements* fresh uuids, because element.uuid is the primary key of the project database and a duplicate silently fails to insert. Conductors now have the same problem and needed the same loop: conductor.uuid is likewise a primary key, its insert is a plain INSERT rather than INSERT OR IGNORE, and a failure only reaches qDebug(). Without this, every wire on a duplicated folio is missing from the wiring list and from the per-element wire count, with nothing shown to the user. Verified against the real schema: inserting the same conductor uuid for a second folio fails with "UNIQUE constraint failed: conductor.uuid", leaving one row where two were expected. Also harden the uuid read in Conductor::fromXml(). The default argument of QDomElement::attribute() is evaluated whether or not the attribute exists, so a uuid was minted for every conductor on every load and thrown away; and the default only applies when the attribute is *absent*, so a present but empty or malformed uuid="" parsed to a null QUuid rather than a fresh one -- and null uuids collide with each other exactly as duplicates do. Co-Authored-By: Claude Opus 5 --- sources/elementspanelwidget.cpp | 8 ++++++++ sources/qetgraphicsitem/conductor.cpp | 8 +++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/sources/elementspanelwidget.cpp b/sources/elementspanelwidget.cpp index 7baf0afbe..0fdc60edb 100644 --- a/sources/elementspanelwidget.cpp +++ b/sources/elementspanelwidget.cpp @@ -17,6 +17,7 @@ */ #include "elementspanelwidget.h" #include "diagram.h" +#include "qetgraphicsitem/conductor.h" #include "editor/ui/qetelementeditor.h" #include "elementscategoryeditor.h" #include "qetapp.h" @@ -652,6 +653,13 @@ void ElementsPanelWidget::duplicateDiagram() elmt->newUuid(); new_diagram->restoreText(elmt); } + else if (Conductor *cond = dynamic_cast(item)) { + // Same reasoning for conductors: conductor.uuid is the PRIMARY + // KEY of the conductor table, and its insert is a plain INSERT, + // so a duplicated uuid fails and the wire silently disappears + // from the wiring list and the per-element wire count. + cond->newUuid(); + } } } diff --git a/sources/qetgraphicsitem/conductor.cpp b/sources/qetgraphicsitem/conductor.cpp index 546f64b3e..e04288107 100644 --- a/sources/qetgraphicsitem/conductor.cpp +++ b/sources/qetgraphicsitem/conductor.cpp @@ -1010,7 +1010,13 @@ bool Conductor::fromXml(QDomElement &dom_element) //generate one on load, same treatment terminal uuids got when //that field was introduced (see terminal1/terminal2 handling in //toXml() below). - m_uuid = QUuid(dom_element.attribute("uuid", QUuid::createUuid().toString())); + m_uuid = QUuid(dom_element.attribute(QStringLiteral("uuid"))); + if (m_uuid.isNull()) { + //Absent, empty or malformed: mint one. A null uuid is not a usable + //identity -- every conductor carrying one would collide with every + //other on the conductor table's primary key. + m_uuid = QUuid::createUuid(); + } setPos(dom_element.attribute("x", nullptr).toDouble(), dom_element.attribute("y", nullptr).toDouble());