Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 44 additions & 13 deletions NodeGraphQt/base/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,27 +154,14 @@ def __init__(self, graph, node):
self.scene = graph.scene()
self.model = graph.model
self.node = node
self.inputs = []
self.outputs = []
self.node_parent = node.parent()

if hasattr(self.node, 'inputs'):
input_ports = self.node.input_ports()
self.inputs = [(p, p.connected_ports()) for p in input_ports]
if hasattr(self.node, 'outputs'):
output_ports = self.node.output_ports()
self.outputs = [(p, p.connected_ports()) for p in output_ports]

def undo(self):
self.model.nodes[self.node.id] = self.node
self.scene.addItem(self.node.view)
[port.connect_to(p) for port, connected_ports in self.inputs for p in connected_ports]
[port.connect_to(p) for port, connected_ports in self.outputs for p in connected_ports]
self.node.set_parent(self.node_parent)

def redo(self):
[port.disconnect_from(p) for port, connected_ports in self.inputs for p in connected_ports]
[port.disconnect_from(p) for port, connected_ports in self.outputs for p in connected_ports]
self.model.nodes.pop(self.node.id)
self.node.delete()

Expand Down Expand Up @@ -328,6 +315,50 @@ def redo(self):
self.source.view.disconnect_from(self.target.view)


class PortLockedCmd(QtWidgets.QUndoCommand):
"""
Port locked command.

Args:
port (NodeGraphQt.Port): node port.
"""

def __init__(self, port):
QtWidgets.QUndoCommand.__init__(self)
self.setText('lock port "{}"'.format(port.name()))
self.port = port

def undo(self):
self.port.model.locked = False
self.port.view.locked = False

def redo(self):
self.port.model.locked = True
self.port.view.locked = True


class PortUnlockedCmd(QtWidgets.QUndoCommand):
"""
Port unlocked command.

Args:
port (NodeGraphQt.Port): node port.
"""

def __init__(self, port):
QtWidgets.QUndoCommand.__init__(self)
self.setText('unlock port "{}"'.format(port.name()))
self.port = port

def undo(self):
self.port.model.locked = True
self.port.view.locked = True

def redo(self):
self.port.model.locked = False
self.port.view.locked = False


class PortVisibleCmd(QtWidgets.QUndoCommand):
"""
Port visibility command.
Expand Down
45 changes: 36 additions & 9 deletions NodeGraphQt/base/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from .factory import NodeFactory
from .menu import NodeGraphMenu, NodesMenu
from .model import NodeGraphModel
from .node import NodeObject, BaseNode, BackdropNode
from .node import NodeObject, BackdropNode, BaseNode
from .port import Port
from ..constants import (
URI_SCHEME, URN_SCHEME,
Expand Down Expand Up @@ -1002,14 +1002,26 @@ def delete_node(self, node):
'node must be a instance of a NodeObject.'
if node is self.root_node():
return
self.nodes_deleted.emit([node.id])

node_id = node.id
self._undo_stack.beginMacro('delete node: "{}"'.format(node.name()))
if isinstance(node, BaseNode):
for p in node.input_ports():
if p.locked():
p.set_locked(False, connected_ports=False)
p.clear_connections()
for p in node.output_ports():
if p.locked():
p.set_locked(False, connected_ports=False)
p.clear_connections()

if isinstance(node, SubGraph):
self._undo_stack.beginMacro('delete sub graph')
self.delete_nodes(node.children())
self._undo_stack.push(NodeRemovedCmd(self, node))
self._undo_stack.endMacro()
else:
self._undo_stack.push(NodeRemovedCmd(self, node))

self._undo_stack.push(NodeRemovedCmd(self, node))
self._undo_stack.endMacro()
self.nodes_deleted.emit([node_id])

def delete_nodes(self, nodes):
"""
Expand All @@ -1018,14 +1030,29 @@ def delete_nodes(self, nodes):
Args:
nodes (list[NodeGraphQt.BaseNode]): list of node instances.
"""
if not nodes:
return
if not self._editable:
return
node_ids = [n.id for n in nodes]
root_node = self.root_node()
self.nodes_deleted.emit([n.id for n in nodes])
self._undo_stack.beginMacro('delete nodes')
[self.delete_nodes(n.children()) for n in nodes if isinstance(n, SubGraph)]
[self._undo_stack.push(NodeRemovedCmd(self, n)) for n in nodes if n is not root_node]
for node in nodes:
if isinstance(node, BaseNode):
for p in node.input_ports():
if p.locked():
p.set_locked(False, connected_ports=False)
p.clear_connections()
for p in node.output_ports():
if p.locked():
p.set_locked(False, connected_ports=False)
p.clear_connections()
if isinstance(node, SubGraph):
self.delete_nodes(node.children())
if node is not root_node:
self._undo_stack.push(NodeRemovedCmd(self, node))
self._undo_stack.endMacro()
self.nodes_deleted.emit(node_ids)

def delete_pipe(self, pipe):
self._on_connection_changed([(pipe.input_port, pipe.output_port)], [])
Expand Down
29 changes: 27 additions & 2 deletions NodeGraphQt/base/port.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#!/usr/bin/python
from .commands import (PortConnectedCmd,
PortDisconnectedCmd,
PortLockedCmd,
PortUnlockedCmd,
PortVisibleCmd,
NodeInputConnectedCmd,
NodeInputDisconnectedCmd)
Expand Down Expand Up @@ -162,8 +164,12 @@ def set_locked(self, state=False, connected_ports=True):
state (Bool): port lock state.
connected_ports (Bool): apply to lock state to connected ports.
"""
self.model.locked = state
self.__view.locked = state
graph = self.node().graph
undo_stack = graph.undo_stack()
if state:
undo_stack.push(PortLockedCmd(self))
else:
undo_stack.push(PortUnlockedCmd(self))
if connected_ports:
for port in self.connected_ports():
port.set_locked(state, connected_ports=False)
Expand Down Expand Up @@ -272,6 +278,25 @@ def disconnect_from(self, port=None):
ports = {p.type_(): p for p in [self, port]}
graph.port_disconnected.emit(ports[IN_PORT], ports[OUT_PORT])

def clear_connections(self):
"""
Disconnect from all pipe connections and emit the
:attr:`NodeGraph.port_disconnected` signals from the node graph.
"""
if self.locked():
err = 'Can\'t clear connections because port "{}" is locked.'
raise PortError(err.format(self.name()))

if not self.connected_ports():
return

graph = self.node().graph
undo_stack = graph.undo_stack()
undo_stack.beginMacro('"{}" clear connections')
for cp in self.connected_ports():
self.disconnect_from(cp)
undo_stack.endMacro()

@property
def color(self):
return self.__view.color
Expand Down
5 changes: 0 additions & 5 deletions NodeGraphQt/qgraphics/node_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -740,11 +740,6 @@ def get_widget(self, name):
def has_widget(self, name):
return name in self._widgets.keys()

def delete(self):
[port.delete() for port, text in self._input_items.items()]
[port.delete() for port, text in self._output_items.items()]
super(NodeItem, self).delete()

def from_dict(self, node_dict):
super(NodeItem, self).from_dict(node_dict)
widgets = node_dict.pop('widgets', {})
Expand Down
7 changes: 2 additions & 5 deletions NodeGraphQt/qgraphics/port.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,11 +131,11 @@ def mouseReleaseEvent(self, event):
super(PortItem, self).mouseReleaseEvent(event)

def hoverEnterEvent(self, event):
self.hovered = True
self._hovered = True
super(PortItem, self).hoverEnterEvent(event)

def hoverLeaveEvent(self, event):
self.hovered = False
self._hovered = False
super(PortItem, self).hoverLeaveEvent(event)

def viewer_start_connection(self):
Expand Down Expand Up @@ -253,9 +253,6 @@ def port_type(self):
def port_type(self, port_type):
self._port_type = port_type

def delete(self):
[pipe.delete() for pipe in self.connected_pipes]

def connect_to(self, port):
if not port:
for pipe in self.connected_pipes:
Expand Down