You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Feature idea: preserve master/slave links when cutting/copying/pasting linked elements
#607
No — traced the full call chain from DiagramView::paste() down to where element links actually get resolved, and on-diagram paste never calls the function that does it. Details below.
Problem
Cutting/copying a linked group of elements (a relay coil with its contacts, a PLC master with its slave I/O elements, etc.) and pasting it back — even the whole group together in one paste — currently drops the master/slave link entirely. The pasted copies come in as ordinary, independent elements with no link and no error/warning; the user has to notice and manually re-link them afterward via the link dialog.
What exists today, traced end to end
Element::toXml() (element.cpp:958) writes each linked partner's uuid into a <link_uuid> entry, so the clipboard XML produced by copy genuinely does contain the link information.
Element::fromXml() reads that back — but only into a deferred, unresolved buffer: tmp_uuids_link << LinkInfo(uuid, group_index) (element.cpp:768). No linking happens at this point; it's explicitly left pending.
The only code that ever resolves tmp_uuids_link into a real, live link is Element::initLink(QETProject *prj) (element.cpp:1295-1317): it builds ElementProvider ep(prj), resolves the pending uuids against prj, and for each match calls elmt->linkToElement(this) plus populates m_group_index_map.
initLink() itself is only ever called from one place: Diagram::refreshContents() (diagram.cpp:1629-1644), which loops every element on the diagram and calls elmt->initLink(project()).
refreshContents() in turn is only called from two places in the whole codebase: full project load (qetproject.cpp:297) and macro-block insertion (diagrameventaddmacro.cpp:253).
DiagramView::paste() (diagramview.cpp:412-429) calls m_diagram->fromXml(document_xml, pos, false, &content_pasted) directly — and Diagram::fromXml() (diagram.cpp:1295-1583, the exact overload paste calls) never calls initLink() or refreshContents() anywhere in its body; it just populates content_ptr->m_elements with the newly created elements and returns. Checked the full function — no other code path resolves the pending links either.
Net result, confirmed by tracing every step of this chain rather than assuming it: pasted elements' tmp_uuids_link is populated correctly, but nothing ever calls the one function (initLink()) that turns it into an actual link. The link is silently dropped, whether you paste one half of a linked pair or the entire group together.
This is a different, narrower problem from the one already fixed in 20a7047b2 ("Renew element uuids when duplicating a folio"): that commit fixed a uuid collision (elements keeping their source uuid as the project database's primary key) on the folio-duplication path, not the paste-doesn't-relink issue described here — and it's a separate code path (ElementsPanelWidget::duplicateDiagram()) from DiagramView::paste().
Proposed scope
Have Diagram::fromXml() (or DiagramView::paste()/PasteDiagramCommand, right after the elements are added) call initLink(project()) on each newly added element — the same call refreshContents() already makes for full project loads — so pending tmp_uuids_link entries actually resolve for pasted content too.
Scope the resolution to the elements that were part of the same paste operation when both halves of a link are present, so pasting a complete linked group re-establishes the link between the new copies rather than reaching out to ElementProvider's project-wide uuid search and potentially matching against an original element that wasn't part of the paste at all (worth a close look during implementation, since ElementProvider(prj)'s default search scope is the entire project, not just the pasted batch).
When only one half of a linked group is pasted (its partner wasn't copied), leave the pasted copy unlinked — same as today — since there's nothing valid to link it to.
Happy to build this if the scope above sounds right.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Checked: is this already handled?
No — traced the full call chain from
DiagramView::paste()down to where element links actually get resolved, and on-diagram paste never calls the function that does it. Details below.Problem
Cutting/copying a linked group of elements (a relay coil with its contacts, a PLC master with its slave I/O elements, etc.) and pasting it back — even the whole group together in one paste — currently drops the master/slave link entirely. The pasted copies come in as ordinary, independent elements with no link and no error/warning; the user has to notice and manually re-link them afterward via the link dialog.
What exists today, traced end to end
Element::toXml()(element.cpp:958) writes each linked partner's uuid into a<link_uuid>entry, so the clipboard XML produced by copy genuinely does contain the link information.Element::fromXml()reads that back — but only into a deferred, unresolved buffer:tmp_uuids_link << LinkInfo(uuid, group_index)(element.cpp:768). No linking happens at this point; it's explicitly left pending.tmp_uuids_linkinto a real, live link isElement::initLink(QETProject *prj)(element.cpp:1295-1317): it buildsElementProvider ep(prj), resolves the pending uuids againstprj, and for each match callselmt->linkToElement(this)plus populatesm_group_index_map.initLink()itself is only ever called from one place:Diagram::refreshContents()(diagram.cpp:1629-1644), which loops every element on the diagram and callselmt->initLink(project()).refreshContents()in turn is only called from two places in the whole codebase: full project load (qetproject.cpp:297) and macro-block insertion (diagrameventaddmacro.cpp:253).DiagramView::paste()(diagramview.cpp:412-429) callsm_diagram->fromXml(document_xml, pos, false, &content_pasted)directly — andDiagram::fromXml()(diagram.cpp:1295-1583, the exact overload paste calls) never callsinitLink()orrefreshContents()anywhere in its body; it just populatescontent_ptr->m_elementswith the newly created elements and returns. Checked the full function — no other code path resolves the pending links either.tmp_uuids_linkis populated correctly, but nothing ever calls the one function (initLink()) that turns it into an actual link. The link is silently dropped, whether you paste one half of a linked pair or the entire group together.20a7047b2("Renew element uuids when duplicating a folio"): that commit fixed a uuid collision (elements keeping their source uuid as the project database's primary key) on the folio-duplication path, not the paste-doesn't-relink issue described here — and it's a separate code path (ElementsPanelWidget::duplicateDiagram()) fromDiagramView::paste().Proposed scope
Diagram::fromXml()(orDiagramView::paste()/PasteDiagramCommand, right after the elements are added) callinitLink(project())on each newly added element — the same callrefreshContents()already makes for full project loads — so pendingtmp_uuids_linkentries actually resolve for pasted content too.ElementProvider's project-wide uuid search and potentially matching against an original element that wasn't part of the paste at all (worth a close look during implementation, sinceElementProvider(prj)'s default search scope is the entire project, not just the pasted batch).Happy to build this if the scope above sounds right.
All reactions