77from enum import Enum
88from threading import Thread , Event , Lock
99from multiprocessing .pool import ThreadPool
10- from typing import Iterator
10+ from typing import Iterator , Optional , Union
1111
1212from PySide6 .QtCore import (
1313 Slot ,
@@ -369,9 +369,7 @@ def __init__(self, undoStack, taskManager, parent=None):
369369 self ._sortedDFSChunks = QObjectListModel (parent = self )
370370 self ._layout = GraphLayout (self )
371371 self ._selectedNode = None
372- self ._selectedNodes = QObjectListModel (parent = self )
373372 self ._nodeSelection = QItemSelectionModel (self ._graph .nodes , parent = self )
374- self ._nodeSelection .selectionChanged .connect (self .onNodeSelectionChanged )
375373 self ._hoveredNode = None
376374
377375 self .submitLabel = "{projectName}"
@@ -516,9 +514,10 @@ def updateLockedUndoStack(self):
516514 else :
517515 self ._undoStack .unlock ()
518516
519- @Slot (QObjectListModel )
517+ @Slot ()
520518 @Slot (Node )
521- def execute (self , nodes = None ):
519+ @Slot (list )
520+ def execute (self , nodes : Optional [Union [list [Node ], Node ]] = None ):
522521 nodes = [nodes ] if not isinstance (nodes , Iterable ) and nodes else nodes
523522 self ._taskManager .compute (self ._graph , nodes )
524523 self .updateLockedUndoStack () # explicitly call the update while it is already computing
@@ -554,9 +553,10 @@ def cancelNodeComputation(self, node):
554553 n .clearSubmittedChunks ()
555554 self ._taskManager .removeNode (n , displayList = True , processList = True )
556555
557- @Slot (QObjectListModel )
556+ @Slot ()
558557 @Slot (Node )
559- def submit (self , nodes = None ):
558+ @Slot (list )
559+ def submit (self , nodes : Optional [Union [list [Node ], Node ]] = None ):
560560 """ Submit the graph to the default Submitter.
561561 If a node is specified, submit this node and its uncomputed predecessors.
562562 Otherwise, submit the whole
@@ -696,16 +696,14 @@ def removeNodes(self, nodes: list[Node]):
696696 for node in nodes :
697697 self .push (commands .RemoveNodeCommand (self ._graph , node ))
698698
699- @Slot (QObject )
700- def removeNodesFrom (self , nodes ):
699+ @Slot (list )
700+ def removeNodesFrom (self , nodes : list [ Node ] ):
701701 """
702- Remove all nodes starting from 'startNode ' to graph leaves.
702+ Remove all nodes starting from 'nodes ' to graph leaves.
703703
704704 Args:
705- startNode (Node) : the node to start from.
705+ nodes : the nodes to start from.
706706 """
707- if isinstance (nodes , Node ):
708- nodes = [nodes ]
709707 with self .groupedGraphModification ("Remove Nodes From Selected Nodes" ):
710708 nodesToRemove , _ = self ._graph .dfsOnDiscover (startNodes = nodes , reverse = True , dependenciesOnly = True )
711709 # filter out nodes that will be removed more than once
@@ -714,17 +712,17 @@ def removeNodesFrom(self, nodes):
714712 # can be re-created in correct order on redo.
715713 self .removeNodes (list (reversed (uniqueNodesToRemove )))
716714
717- @Slot (QObject , result = "QVariantList" )
718- def duplicateNodes (self , nodes ) :
715+ @Slot (list , result = list )
716+ def duplicateNodes (self , nodes : list [ Node ]) -> list [ Node ] :
719717 """
720718 Duplicate 'nodes'.
721719
722720 Args:
723- nodes (list[Node]): the nodes to duplicate
721+ nodes: the nodes to duplicate.
722+
724723 Returns:
725- list[Node]: the list of duplicated nodes
724+ The list of duplicated nodes.
726725 """
727- nodes = self .filterNodes (nodes )
728726 nPositions = [(n .x , n .y ) for n in self ._graph .nodes ]
729727 # enable updates between duplication and layout to get correct depths during layout
730728 with self .groupedGraphModification ("Duplicate Selected Nodes" , disableUpdates = False ):
@@ -747,18 +745,16 @@ def duplicateNodes(self, nodes):
747745
748746 return duplicates
749747
750- @Slot (QObject , result = "QVariantList" )
751- def duplicateNodesFrom (self , nodes ) :
748+ @Slot (list , result = list )
749+ def duplicateNodesFrom (self , nodes : list [ Node ]) -> list [ Node ] :
752750 """
753751 Duplicate all nodes starting from 'nodes' to graph leaves.
754752
755753 Args:
756- nodes (list[Node]): the nodes to start from.
754+ node: The nodes to start from.
757755 Returns:
758- list[Node]: the list of duplicated nodes
756+ The list of duplicated nodes.
759757 """
760- if isinstance (nodes , Node ):
761- nodes = [nodes ]
762758 with self .groupedGraphModification ("Duplicate Nodes From Selected Nodes" ):
763759 nodesToDuplicate , _ = self ._graph .dfsOnDiscover (startNodes = nodes , reverse = True , dependenciesOnly = True )
764760 # filter out nodes that will be duplicated more than once
@@ -789,7 +785,7 @@ def expandForLoop(self, currentEdge):
789785 dst = currentEdge .dst
790786
791787 for i in range (1 , len (listAttribute )):
792- duplicates = self .duplicateNodesFrom (dst .node )
788+ duplicates = self .duplicateNodesFrom ([ dst .node ] )
793789 newNode = duplicates [0 ]
794790 previousEdge = self .graph .edge (newNode .attribute (dst .name ))
795791 self .replaceEdge (previousEdge , listAttribute .at (i ), previousEdge .dst )
@@ -809,7 +805,7 @@ def collapseForLoop(self, currentEdge):
809805 continue
810806 occurence = allSrc .index (listAttribute .at (i )) if listAttribute .at (i ) in allSrc else - 1
811807 if occurence != - 1 :
812- self .removeNodesFrom (self .graph .edges .at (occurence ).dst .node )
808+ self .removeNodesFrom ([ self .graph .edges .at (occurence ).dst .node ] )
813809 # update the edges from allSrc
814810 allSrc = [e .src for e in self ._graph .edges .values ()]
815811
@@ -954,11 +950,6 @@ def removeImagesFromAllGroups(self):
954950 with self .groupedGraphModification ("Remove Images From All CameraInit Nodes" ):
955951 self .push (commands .RemoveImagesCommand (self ._graph , list (self .cameraInits )))
956952
957- def onNodeSelectionChanged (self , selected , deselected ):
958- # Update internal cache of selected Node instances.
959- self ._selectedNodes .setObjectList (list (self .iterSelectedNodes ()))
960- self .selectedNodesChanged .emit ()
961-
962953 @Slot (list )
963954 @Slot (list , int )
964955 def selectNodes (self , nodes , command = QItemSelectionModel .SelectionFlag .ClearAndSelect ):
@@ -1014,6 +1005,11 @@ def iterSelectedNodes(self) -> Iterator[Node]:
10141005 for idx in self ._nodeSelection .selectedRows ():
10151006 yield self ._graph .nodes .at (idx .row ())
10161007
1008+ @Slot (result = list )
1009+ def getSelectedNodes (self ) -> list [Node ]:
1010+ """Return the list of selected Node instances."""
1011+ return list (self .iterSelectedNodes ())
1012+
10171013 @Slot (Node , result = bool )
10181014 def isSelected (self , node : Node ) -> bool :
10191015 """Whether `node` is part of the current selection."""
@@ -1032,19 +1028,17 @@ def clearNodeHover(self):
10321028 @Slot (result = str )
10331029 def getSelectedNodesContent (self ) -> str :
10341030 """
1035- Return the content of the currently selected nodes in a string, formatted to JSON.
1036- If no node is currently selected, an empty string is returned.
1031+ Serialize the current node selection and return it as JSON formatted string.
1032+
1033+ Returns an empty string if the selection is empty.
10371034 """
1038- if self ._selectedNodes :
1039- d = self ._graph .toDict ()
1040- selection = {}
1041- for node in self ._selectedNodes :
1042- selection [node .name ] = d [node .name ]
1043- return json .dumps (selection , indent = 4 )
1044- return ''
1045-
1046- @Slot (str , QPoint , bool , result = "QVariantList" )
1047- def pasteNodes (self , clipboardContent , position = None , centerPosition = False ):
1035+ if not self ._nodeSelection .hasSelection ():
1036+ return ""
1037+ serializedSelection = {node .name : node .toDict () for node in self .iterSelectedNodes ()}
1038+ return json .dumps (serializedSelection , indent = 4 )
1039+
1040+ @Slot (str , QPoint , bool , result = list )
1041+ def pasteNodes (self , clipboardContent , position = None , centerPosition = False ) -> list [Node ]:
10481042 """
10491043 Parse the content of the clipboard to see whether it contains
10501044 valid node descriptions. If that is the case, the nodes described
@@ -1181,10 +1175,6 @@ def pasteNodes(self, clipboardContent, position=None, centerPosition=False):
11811175 # Current main selected node
11821176 selectedNode = makeProperty (QObject , "_selectedNode" , selectedNodeChanged , resetOnDestroy = True )
11831177
1184- selectedNodesChanged = Signal ()
1185- # Currently selected nodes
1186- selectedNodes = makeProperty (QObject , "_selectedNodes" , selectedNodesChanged , resetOnDestroy = True )
1187-
11881178 nodeSelection = makeProperty (QObject , "_nodeSelection" )
11891179
11901180 hoveredNodeChanged = Signal ()
0 commit comments