44import os
55import re
66import copy
7-
7+ import gc
88from .. import QtCore , QtWidgets , QtGui
99from .commands import (NodeAddedCmd ,
1010 NodeRemovedCmd ,
@@ -142,6 +142,7 @@ def __init__(self, parent=None):
142142 self ._node_factory = NodeFactory ()
143143 self ._undo_stack = QtWidgets .QUndoStack (self )
144144 self ._current_node_space = None
145+ self ._editable = True
145146
146147 tab = QtWidgets .QShortcut (QtGui .QKeySequence (QtCore .Qt .Key_Tab ), self ._viewer )
147148 tab .activated .connect (self ._toggle_tab_search )
@@ -176,6 +177,8 @@ def _insert_node(self, pipe, node_id, prev_node_pos):
176177 node_id (str): selected node id to insert.
177178 prev_node_pos (dict): previous node position. {NodeItem: [prev_x, prev_y]}
178179 """
180+ if not self ._editable :
181+ return
179182 node = self .get_node_by_id (node_id )
180183
181184 # exclude the BackdropNode
@@ -203,6 +206,8 @@ def _toggle_tab_search(self):
203206 """
204207 toggle the tab search widget.
205208 """
209+ if not self ._editable :
210+ return
206211 if self ._viewer .underMouse ():
207212 self ._viewer .tab_search_set_nodes (self ._node_factory .names )
208213 self ._viewer .tab_search_toggle ()
@@ -217,6 +222,8 @@ def _on_property_bin_changed(self, node_id, prop_name, prop_value):
217222 prop_name (str): node property name.
218223 prop_value (object): python object.
219224 """
225+ if not self ._editable :
226+ return
220227 node = self .get_node_by_id (node_id )
221228
222229 # prevent signals from causing a infinite loop.
@@ -307,6 +314,8 @@ def _on_connection_changed(self, disconnected, connected):
307314 connected (list[list[widgets.port.PortItem]]):
308315 pair list of port view items.
309316 """
317+ if not self ._editable :
318+ return
310319 if not (disconnected or connected ):
311320 return
312321
@@ -336,7 +345,7 @@ def _on_connection_sliced(self, ports):
336345 ports (list[list[widgets.port.PortItem]]):
337346 pair list of port connections (in port, out port)
338347 """
339- if not ports :
348+ if not ports or not self . _editable :
340349 return
341350 ptypes = {IN_PORT : 'inputs' , OUT_PORT : 'outputs' }
342351 self ._undo_stack .beginMacro ('slice connections' )
@@ -385,6 +394,25 @@ def auto_update(self):
385394 """
386395 return self ._auto_update
387396
397+ @property
398+ def editable (self ):
399+ """
400+ Returns whether the graph is editable.
401+ """
402+ return self ._editable
403+
404+ @editable .setter
405+ def editable (self , state ):
406+ """
407+ Set whether the graph is editable.
408+
409+ Args:
410+ state(bool).
411+ """
412+ self ._editable = state
413+ self ._viewer .editable = state
414+ self ._viewer .scene ().editable = state
415+
388416 def show (self ):
389417 """
390418 Show node graph widget this is just a convenience
@@ -513,6 +541,7 @@ def clear_undo_stack(self):
513541 :meth:`NodeGraph.undo_stack()`
514542 """
515543 self ._undo_stack .clear ()
544+ gc .collect ()
516545
517546 def begin_undo (self , name ):
518547 """
@@ -747,6 +776,8 @@ def create_node(self, node_type, name=None, selected=True, color=None,
747776 Returns:
748777 NodeGraphQt.BaseNode: the created instance of the node.
749778 """
779+ if not self ._editable :
780+ return
750781 NodeCls = self ._node_factory .create_node_instance (node_type )
751782 if NodeCls :
752783 node = NodeCls ()
@@ -813,6 +844,8 @@ def add_node(self, node, pos=None, unique_name=True):
813844 pos (list[float]): node x,y position. (optional)
814845 unique_name (bool): make node name unique
815846 """
847+ if not self ._editable :
848+ return
816849 assert isinstance (node , NodeObject ), 'node must be a Node instance.'
817850
818851 wid_types = node .model .__dict__ .pop ('_TEMP_property_widget_types' )
@@ -850,6 +883,10 @@ def set_node_space(self, node):
850883 if node is not None :
851884 node .enter ()
852885 self ._node_space_bar .set_node (node )
886+ self .editable = node .is_editable ()
887+ [n .set_editable (self .editable ) for n in node .children () if isinstance (n , BaseNode )]
888+ else :
889+ self .editable = True
853890
854891 def get_node_space (self ):
855892 """
@@ -867,6 +904,8 @@ def delete_node(self, node):
867904 Args:
868905 node (NodeGraphQt.BaseNode): node object.
869906 """
907+ if not self ._editable :
908+ return
870909 assert isinstance (node , NodeObject ), \
871910 'node must be a instance of a NodeObject.'
872911 if node is self .root_node ():
@@ -887,6 +926,8 @@ def delete_nodes(self, nodes):
887926 Args:
888927 nodes (list[NodeGraphQt.BaseNode]): list of node instances.
889928 """
929+ if not self ._editable :
930+ return
890931 root_node = self .root_node ()
891932 self .nodes_deleted .emit ([n .id for n in nodes ])
892933 self ._undo_stack .beginMacro ('delete nodes' )
@@ -1056,7 +1097,7 @@ def clear_session(self):
10561097 continue
10571098 self ._undo_stack .push (NodeRemovedCmd (self , n ))
10581099 self .set_node_space (root_node )
1059- self ._undo_stack . clear ()
1100+ self .clear_undo_stack ()
10601101 self ._model .session = None
10611102 self .session_changed .emit ("" )
10621103
@@ -1082,9 +1123,7 @@ def _serialize(self, nodes):
10821123 node_dict = n .model .to_dict
10831124
10841125 if isinstance (n , SubGraph ):
1085- published = n .has_property ('published' )
1086- if published :
1087- published = n .get_property ('published' )
1126+ published = n .get_property ('published' )
10881127 if not published :
10891128 children = n .children ()
10901129 if children :
@@ -1132,6 +1171,8 @@ def _deserialize(self, data, relative_pos=False, pos=None, set_parent=True):
11321171 Returns:
11331172 list[NodeGraphQt.Nodes]: list of node instances.
11341173 """
1174+ if not self ._editable :
1175+ return
11351176 nodes = {}
11361177 # build the nodes.
11371178 for n_id , n_data in data .get ('nodes' , {}).items ():
@@ -1148,18 +1189,18 @@ def _deserialize(self, data, relative_pos=False, pos=None, set_parent=True):
11481189 for prop , val in n_data .get ('custom' , {}).items ():
11491190 node .model .set_property (prop , val )
11501191 nodes [n_id ] = node
1151- self .add_node (node , n_data .get ('pos' ), unique_name = set_parent )
1152- node .set_disabled (n_data .get ('disabled' , False ))
1192+
11531193 if isinstance (node , SubGraph ):
1154- if n_data .get ('custom' , None ):
1155- published = n_data ['custom' ].get ('published' , False )
1156- else :
1157- published = False
1194+ node .create_by_deserialize = True
1195+ self .add_node (node , n_data .get ('pos' ), unique_name = set_parent )
1196+ published = n_data ['custom' ].get ('published' , False )
11581197 if not published :
11591198 sub_graph = n_data .get ('sub_graph' , None )
11601199 if sub_graph :
11611200 children = self ._deserialize (sub_graph , relative_pos , pos , False )
11621201 [child .set_parent (node ) for child in children ]
1202+ else :
1203+ self .add_node (node , n_data .get ('pos' ), unique_name = set_parent )
11631204
11641205 if n_data .get ('dynamic_port' , None ):
11651206 node .set_ports ({'input_ports' : n_data ['input_ports' ], 'output_ports' : n_data ['output_ports' ]})
@@ -1212,7 +1253,7 @@ def deserialize_session(self, layout_data):
12121253 """
12131254 self .clear_session ()
12141255 self ._deserialize (layout_data )
1215- self ._undo_stack . clear ()
1256+ self .clear_undo_stack ()
12161257
12171258 def save_session (self , file_path ):
12181259 """
@@ -1287,7 +1328,7 @@ def import_session(self, file_path):
12871328 self .set_grid_mode (layout_data ['graph' ].get ('grid_mode' , VIEWER_GRID_LINES ))
12881329
12891330 self .set_node_space (self .root_node ())
1290- self ._undo_stack . clear ()
1331+ self .clear_undo_stack ()
12911332 self ._model .session = file_path
12921333 self .session_changed .emit (file_path )
12931334 self ._auto_update = _temp_auto_update
@@ -1325,6 +1366,8 @@ def paste_nodes(self):
13251366 """
13261367 Pastes nodes copied from the clipboard.
13271368 """
1369+ if not self ._editable :
1370+ return
13281371 clipboard = QtWidgets .QApplication .clipboard ()
13291372 cb_text = clipboard .text ()
13301373 if not cb_text :
@@ -1346,7 +1389,7 @@ def duplicate_nodes(self, nodes):
13461389 Returns:
13471390 list[NodeGraphQt.BaseNode]: list of duplicated node instances.
13481391 """
1349- if not nodes :
1392+ if not nodes or not self . _editable :
13501393 return
13511394
13521395 self ._undo_stack .beginMacro ('duplicate nodes' )
@@ -1374,7 +1417,7 @@ def disable_nodes(self, nodes, mode=None):
13741417 nodes (list[NodeGraphQt.BaseNode]): list of node instances.
13751418 mode (bool): (optional) disable state of the nodes.
13761419 """
1377- if not nodes :
1420+ if not nodes or not self . _editable :
13781421 return
13791422 if mode is None :
13801423 mode = not nodes [0 ].disabled ()
0 commit comments