Fix signal handling during graph rebuild

- Add _rebuilding flag to ignore signals during rebuild
- Prevents cascade of port_disconnected signals when clearing graph
- Fixes KeyError in NodeGraphQt undo stack
- Fixes false dependency warnings on view switch

The port_disconnected and nodes_deleted signals were firing during
clear_session(), causing recursive rebuilds and errors.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
This commit is contained in:
rob
2026-01-15 23:54:48 -04:00
co-authored by Claude Opus 4.5
parent d1f0c2f893
commit 683a8a6d8f
+23 -2
View File
@@ -135,6 +135,7 @@ class FlowGraphWidget(QWidget):
self._input_node = None self._input_node = None
self._output_node = None self._output_node = None
self._step_nodes: List[CmdForgeBaseNode] = [] self._step_nodes: List[CmdForgeBaseNode] = []
self._rebuilding = False # Flag to ignore signals during rebuild
self._setup_ui() self._setup_ui()
@@ -215,13 +216,21 @@ class FlowGraphWidget(QWidget):
if not self._graph: if not self._graph:
return return
# Clear existing nodes # Set flag to ignore signals during rebuild
self._graph.clear_session() self._rebuilding = True
try:
# Clear existing nodes
self._graph.clear_session()
except Exception:
pass # Ignore errors during clear
self._input_node = None self._input_node = None
self._output_node = None self._output_node = None
self._step_nodes = [] self._step_nodes = []
if not self._tool: if not self._tool:
self._rebuilding = False
return return
# Create input node # Create input node
@@ -294,6 +303,7 @@ class FlowGraphWidget(QWidget):
node.set_selected(True) node.set_selected(True)
# Use a timer to fit after the widget is fully rendered # Use a timer to fit after the widget is fully rendered
# Also clears the rebuilding flag after everything settles
QTimer.singleShot(50, self._fit_and_clear_selection) QTimer.singleShot(50, self._fit_and_clear_selection)
def _fit_and_clear_selection(self): def _fit_and_clear_selection(self):
@@ -303,6 +313,9 @@ class FlowGraphWidget(QWidget):
# Clear selection # Clear selection
self._graph.clear_selection() self._graph.clear_selection()
# Clear rebuilding flag - now safe to handle user interactions
self._rebuilding = False
def select_all_nodes(self): def select_all_nodes(self):
"""Select all nodes in the graph.""" """Select all nodes in the graph."""
if not self._graph: if not self._graph:
@@ -419,6 +432,10 @@ class FlowGraphWidget(QWidget):
def _on_nodes_deleted(self, nodes): def _on_nodes_deleted(self, nodes):
"""Handle node deletion from the graph.""" """Handle node deletion from the graph."""
# Ignore during rebuild
if self._rebuilding:
return
# Collect step indices of deleted step nodes (not Input/Output nodes) # Collect step indices of deleted step nodes (not Input/Output nodes)
deleted_indices = [] deleted_indices = []
for node in nodes: for node in nodes:
@@ -439,6 +456,10 @@ class FlowGraphWidget(QWidget):
2. The chain reconnects (previous node → next node) 2. The chain reconnects (previous node → next node)
3. Disconnected node attaches at the end before Output 3. Disconnected node attaches at the end before Output
""" """
# Ignore during rebuild
if self._rebuilding:
return
if not self._tool or not self._tool.steps: if not self._tool or not self._tool.steps:
return return