From d4509ec20ee482cd3adbb9a8f8bfa78d085cfa08 Mon Sep 17 00:00:00 2001 From: Yann Lanthony Date: Fri, 13 Oct 2017 10:53:49 +0200 Subject: [PATCH] [commands] new AddEdge/RemoveEdge commands --- meshroom/core/graph.py | 36 +++++++++++++++++++++++++----------- meshroom/ui/commands.py | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 11 deletions(-) diff --git a/meshroom/core/graph.py b/meshroom/core/graph.py index ecbcb340..f4be944e 100644 --- a/meshroom/core/graph.py +++ b/meshroom/core/graph.py @@ -97,12 +97,13 @@ class Attribute(BaseObject): # only dependent of the linked node uid, so it is independent # from the cache folder which may be used in the filepath. return self.node.uid() - if self.isLink(): + if self.isLink: return self.getLinkParam().uid() if isinstance(self._value, basestring): return hash(str(self._value)) return hash(self._value) + @property def isLink(self): """ If the attribute is a link to another attribute. @@ -113,7 +114,7 @@ class Attribute(BaseObject): return self in self.node.graph.edges.keys() def getLinkParam(self): - if not self.isLink(): + if not self.isLink: return None return self.node.graph.edge(self).src @@ -135,7 +136,7 @@ class Attribute(BaseObject): def getExportValue(self): value = self._value # print('getExportValue: ', self.name(), value, self.isLink()) - if self.isLink(): + if self.isLink: value = '{' + self.getLinkParam().fullName() + '}' return value @@ -144,6 +145,8 @@ class Attribute(BaseObject): valueChanged = Signal() value = Property("QVariant", value.fget, value.fset, notify=valueChanged) isOutput = Property(bool, isOutput.fget, constant=True) + isLinkChanged = Signal() + isLink = Property(bool, isLink.fget, notify=isLinkChanged) class Edge(BaseObject): @@ -602,20 +605,31 @@ class Graph(BaseObject): nodesWithOutput = set([edge.src.node for edge in self.edges]) return set(self._nodes) - nodesWithOutput - def addEdge(self, outputAttr, inputAttr): - assert isinstance(outputAttr, Attribute) - assert isinstance(inputAttr, Attribute) - if outputAttr.node.graph != self or inputAttr.node.graph != self: + def addEdge(self, srcAttr, dstAttr): + assert isinstance(srcAttr, Attribute) + assert isinstance(dstAttr, Attribute) + if srcAttr.node.graph != self or dstAttr.node.graph != self: raise RuntimeError('The attributes of the edge should be part of a common graph.') - if inputAttr in self.edges.keys(): - raise RuntimeError('Input attribute "{}" is already connected.'.format(inputAttr.fullName())) - self.edges.add(Edge(inputAttr, outputAttr)) - inputAttr.valueChanged.emit() + if dstAttr in self.edges.keys(): + raise RuntimeError('Destination attribute "{}" is already connected.'.format(dstAttr.fullName())) + edge = Edge(dstAttr, srcAttr) + self.edges.add(edge) + dstAttr.valueChanged.emit() + dstAttr.isLinkChanged.emit() + return edge def addEdges(self, *edges): for edge in edges: self.addEdge(*edge) + def removeEdge(self, dstAttr): + if dstAttr not in self.edges.keys(): + raise RuntimeError('Attribute "{}" is not connected'.format(dstAttr.fullName())) + edge = self.edges.pop(dstAttr) + dstAttr.valueChanged.emit() + dstAttr.isLinkChanged.emit() + return edge + def getDepth(self, node): return len(self.dfsNodesOnFinish([node])) diff --git a/meshroom/ui/commands.py b/meshroom/ui/commands.py index 46ab656e..89943249 100644 --- a/meshroom/ui/commands.py +++ b/meshroom/ui/commands.py @@ -132,3 +132,38 @@ class SetAttributeCommand(GraphCommand): def undoImpl(self): self.graph.node(self.nodeName).attribute(self.attrName).value = self.oldValue + + +class AddEdgeCommand(GraphCommand): + def __init__(self, graph, src, dst, parent=None): + super(AddEdgeCommand, self).__init__(graph, parent) + self.srcNode, self.srcAttr = src.fullName().split(".") + self.dstNode, self.dstAttr = dst.fullName().split(".") + self.setText("Connect '{}'->'{}'".format(src.fullName(), dst.fullName())) + + def redoImpl(self): + try: + self.graph.addEdge(self.graph.node(self.srcNode).attribute(self.srcAttr), + self.graph.node(self.dstNode).attribute(self.dstAttr)) + except RuntimeError: + return False + return True + + def undoImpl(self): + self.graph.removeEdge(self.graph.node(self.dstNode).attribute(self.dstAttr)) + + +class RemoveEdgeCommand(GraphCommand): + def __init__(self, graph, edge, parent=None): + super(RemoveEdgeCommand, self).__init__(graph, parent) + self.srcNode, self.srcAttr = edge.src.fullName().split(".") + self.dstNode, self.dstAttr = edge.dst.fullName().split(".") + self.setText("Disconnect '{}'->'{}'".format(edge.src.fullName(), edge.dst.fullName())) + + def redoImpl(self): + self.graph.removeEdge(self.graph.node(self.dstNode).attribute(self.dstAttr)) + return True + + def undoImpl(self): + self.graph.addEdge(self.graph.node(self.srcNode).attribute(self.srcAttr), + self.graph.node(self.dstNode).attribute(self.dstAttr))