autoBreakConductors: share conductors_handled/used_terminals across batch

When multiple elements are pasted or moved in one batch, each call to
autoBreakConductors() now receives the shared state from the previous
call.  This prevents two elements in the same batch from independently
claiming the same conductor, which would result in a double-delete on
redo().

Requested by ispyisail in PR review.
This commit is contained in:
Kellermorph
2026-08-09 09:11:40 +02:00
parent 39b1e836bf
commit d95e744494
5 changed files with 30 additions and 13 deletions
+3 -4
View File
@@ -71,16 +71,15 @@ qreal distanceToSegment(const QPointF &point, const QLineF &segment)
QSet<Terminal *> autoBreakConductors( QSet<Terminal *> autoBreakConductors(
Diagram *diagram, Diagram *diagram,
Element *element, Element *element,
QUndoCommand *parent) QUndoCommand *parent,
QList<Conductor *> &conductors_handled,
QSet<Terminal *> &used_terminals)
{ {
QSet<Terminal *> broken_endpoints; QSet<Terminal *> broken_endpoints;
if (!diagram->project()->autoBreakConductor()) if (!diagram->project()->autoBreakConductor())
return broken_endpoints; return broken_endpoints;
QList<Conductor *> conductors_handled;
QSet<Terminal *> used_terminals;
foreach (Terminal *t, element->terminals()) foreach (Terminal *t, element->terminals())
{ {
if (used_terminals.contains(t)) if (used_terminals.contains(t))
+13 -4
View File
@@ -19,10 +19,12 @@
#define AUTOBREAKCONDUCTOR_H #define AUTOBREAKCONDUCTOR_H
#include <QSet> #include <QSet>
#include <QList>
class Diagram; class Diagram;
class Element; class Element;
class Terminal; class Terminal;
class Conductor;
class QUndoCommand; class QUndoCommand;
/** /**
@@ -34,15 +36,22 @@ class QUndoCommand;
conductors are left untouched. conductors are left untouched.
@param diagram the diagram containing the conductors @param diagram the diagram containing the conductors
@param element the element whose terminals trigger breaks @param element the element whose terminals trigger breaks
@param parent undo command under which break/reconnect sub-commands @param parent undo command under which break/reconnect
are created (may be nullptr, in which case no undo is sub-commands are created
recorded) @param conductors_handled shared list of conductors already claimed by
a previous call in the same batch (prevents
double-processing when multiple elements are
broken in one pass)
@param used_terminals shared set of terminals already used as
connect_to or other_terminal in the same batch
@return set of terminals that were connected to a broken conductor's @return set of terminals that were connected to a broken conductor's
far-end (useful for preventing duplicate auto-connect) far-end (useful for preventing duplicate auto-connect)
*/ */
QSet<Terminal *> autoBreakConductors( QSet<Terminal *> autoBreakConductors(
Diagram *diagram, Diagram *diagram,
Element *element, Element *element,
QUndoCommand *parent); QUndoCommand *parent,
QList<Conductor *> &conductors_handled,
QSet<Terminal *> &used_terminals);
#endif // AUTOBREAKCONDUCTOR_H #endif // AUTOBREAKCONDUCTOR_H
+4 -1
View File
@@ -115,8 +115,11 @@ void PasteDiagramCommand::redo()
if (diagram->project()->autoBreakConductor()) if (diagram->project()->autoBreakConductor())
{ {
m_break_cmd = new QUndoCommand(); m_break_cmd = new QUndoCommand();
QList<Conductor *> conductors_handled;
QSet<Terminal *> used_terminals;
for (Element *e : content.m_elements) { for (Element *e : content.m_elements) {
autoBreakConductors(diagram, e, m_break_cmd); autoBreakConductors(diagram, e, m_break_cmd,
conductors_handled, used_terminals);
} }
if (m_break_cmd->childCount() == 0) { if (m_break_cmd->childCount() == 0) {
delete m_break_cmd; delete m_break_cmd;
@@ -265,7 +265,10 @@ void DiagramEventAddElement::addElement()
//Auto break conductor: if a terminal of the new element lies on an existing //Auto break conductor: if a terminal of the new element lies on an existing
//conductor, break the conductor and reconnect through the new element's terminal. //conductor, break the conductor and reconnect through the new element's terminal.
//Track the endpoints of broken conductors so auto-connect doesn't create duplicates. //Track the endpoints of broken conductors so auto-connect doesn't create duplicates.
QSet<Terminal *> broken_endpoints = autoBreakConductors(m_diagram, element, undo_object); QList<Conductor *> conductors_handled;
QSet<Terminal *> used_terminals;
QSet<Terminal *> broken_endpoints = autoBreakConductors(m_diagram, element, undo_object,
conductors_handled, used_terminals);
//Auto-connect: collect all aligned pairs first, then filter and process. //Auto-connect: collect all aligned pairs first, then filter and process.
QList<QPair<Terminal *, Terminal *>> aligned_pairs; QList<QPair<Terminal *, Terminal *>> aligned_pairs;
+4 -1
View File
@@ -184,8 +184,11 @@ void ElementsMover::endMovement()
//the element. The element is already at its final position on screen. //the element. The element is already at its final position on screen.
if (m_diagram->project()->autoBreakConductor()) if (m_diagram->project()->autoBreakConductor())
{ {
QList<Conductor *> conductors_handled;
QSet<Terminal *> used_terminals;
for (Element *e : m_moved_content.m_elements) { for (Element *e : m_moved_content.m_elements) {
autoBreakConductors(m_diagram, e, undo_object); autoBreakConductors(m_diagram, e, undo_object,
conductors_handled, used_terminals);
} }
} }