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 <noreply@anthropic.com>
This commit is contained in:
rob 2026-01-15 23:54:48 -04:00
parent d1f0c2f893
commit 683a8a6d8f
1 changed files with 23 additions and 2 deletions

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
# Set flag to ignore signals during rebuild
self._rebuilding = True
try:
# Clear existing nodes # Clear existing nodes
self._graph.clear_session() 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