mirror of
https://github.com/alicevision/Meshroom.git
synced 2025-05-21 13:06:28 +02:00
[core/ui] add a locked property on nodes
Add locked property on core nodes and update UI in the same commit because both parts are very dependent for this change.
This commit is contained in:
parent
8a9499a711
commit
ff7f8b3e36
5 changed files with 69 additions and 118 deletions
|
@ -873,7 +873,7 @@ class Graph(BaseObject):
|
|||
flowEdges.append(link)
|
||||
return flowEdges
|
||||
|
||||
def nodesFromNode(self, startNode, filterTypes=None):
|
||||
def nodesFromNode(self, startNode, filterTypes=None, reverse=True):
|
||||
"""
|
||||
Return the node chain from startNode to the graph leaves.
|
||||
|
||||
|
@ -881,6 +881,9 @@ class Graph(BaseObject):
|
|||
startNode (Node): the node to start the visit from.
|
||||
filterTypes (str list): (optional) only return the nodes of the given types
|
||||
(does not stop the visit, this is a post-process only)
|
||||
reverse (bool): (optional) direction of visit.
|
||||
True is for getting nodes depending on the startNode.
|
||||
False is for getting nodes required for the startNode.
|
||||
Returns:
|
||||
The list of nodes and edges, from startNode to the graph leaves following edges.
|
||||
"""
|
||||
|
@ -894,22 +897,15 @@ class Graph(BaseObject):
|
|||
|
||||
visitor.discoverVertex = discoverVertex
|
||||
visitor.examineEdge = lambda edge, graph: edges.append(edge)
|
||||
self.dfs(visitor=visitor, startNodes=[startNode], reverse=True)
|
||||
self.dfs(visitor=visitor, startNodes=[startNode], reverse=reverse)
|
||||
return nodes, edges
|
||||
|
||||
@Slot(Node, result="QVariantList")
|
||||
def onlyNodesFromNode(self, startNode, filterType=None):
|
||||
nodes = []
|
||||
edges = []
|
||||
visitor = Visitor()
|
||||
def nodesDependingOnNode(self, startNode, filterTypes=None):
|
||||
nodes, edges = self.nodesFromNode(startNode, filterTypes=filterTypes, reverse=True)
|
||||
return nodes
|
||||
|
||||
def discoverVertex(vertex, graph):
|
||||
if not filterType or vertex.nodeType == filterType:
|
||||
nodes.append(vertex)
|
||||
|
||||
visitor.discoverVertex = discoverVertex
|
||||
visitor.examineEdge = lambda edge, graph: edges.append(edge)
|
||||
self.dfs(visitor=visitor, startNodes=[startNode], reverse=True)
|
||||
def nodesRequiredForNode(self, startNode, filterTypes=None):
|
||||
nodes, edges = self.nodesFromNode(startNode, filterTypes=filterTypes, reverse=False)
|
||||
return nodes
|
||||
|
||||
@Slot(Node, result=int)
|
||||
|
|
|
@ -462,6 +462,9 @@ class BaseNode(BaseObject):
|
|||
self._position = position or Position()
|
||||
self._attributes = DictModel(keyAttrName='name', parent=self)
|
||||
self.attributesPerUid = defaultdict(set)
|
||||
self._locked = False
|
||||
|
||||
self.globalStatusChanged.connect(self.updateLocked)
|
||||
|
||||
def __getattr__(self, k):
|
||||
try:
|
||||
|
@ -813,6 +816,55 @@ class BaseNode(BaseObject):
|
|||
def __repr__(self):
|
||||
return self.name
|
||||
|
||||
def getLocked(self):
|
||||
return self._locked
|
||||
|
||||
def setLocked(self, lock):
|
||||
if self._locked == lock:
|
||||
return
|
||||
self._locked = lock
|
||||
self.lockedChanged.emit()
|
||||
|
||||
def updateLocked(self):
|
||||
currentStatus = self.getGlobalStatus()
|
||||
|
||||
lockedStatus = (Status.RUNNING, Status.SUBMITTED)
|
||||
|
||||
# Unlock required nodes if the current node changes to Error
|
||||
if currentStatus == Status.ERROR:
|
||||
requiredNodes = self.graph.nodesRequiredForNode(self)
|
||||
for node in requiredNodes:
|
||||
node.setLocked(False)
|
||||
|
||||
# Avoid useless travel through nodes
|
||||
# For instance: when loading a scene with successful nodes
|
||||
if not self._locked and currentStatus == Status.SUCCESS:
|
||||
return
|
||||
|
||||
if currentStatus == Status.SUCCESS:
|
||||
# At this moment, the node is necessarily locked because of previous if statement
|
||||
requiredNodes = self.graph.nodesRequiredForNode(self)
|
||||
dependentNodes = self.graph.nodesDependingOnNode(self)
|
||||
stayLocked = None
|
||||
|
||||
# Check if at least one dependentNode is submitted or currently running
|
||||
for node in dependentNodes:
|
||||
if node.getGlobalStatus() in lockedStatus and node._chunks.at(0).statusNodeName == node.name:
|
||||
stayLocked = True
|
||||
break
|
||||
if not stayLocked:
|
||||
# Unlock every required node
|
||||
for node in requiredNodes:
|
||||
node.setLocked(False)
|
||||
return
|
||||
elif currentStatus in lockedStatus:
|
||||
requiredNodes = self.graph.nodesRequiredForNode(self)
|
||||
for node in requiredNodes:
|
||||
node.setLocked(True)
|
||||
return
|
||||
|
||||
self.setLocked(False)
|
||||
|
||||
name = Property(str, getName, constant=True)
|
||||
label = Property(str, getLabel, constant=True)
|
||||
nodeType = Property(str, nodeType.fget, constant=True)
|
||||
|
@ -834,6 +886,8 @@ class BaseNode(BaseObject):
|
|||
globalStatusChanged = Signal()
|
||||
globalStatus = Property(str, lambda self: self.getGlobalStatus().name, notify=globalStatusChanged)
|
||||
isComputed = Property(bool, _isComputed, notify=globalStatusChanged)
|
||||
lockedChanged = Signal()
|
||||
locked = Property(bool, getLocked, setLocked, notify=lockedChanged)
|
||||
|
||||
|
||||
class Node(BaseNode):
|
||||
|
|
|
@ -251,21 +251,7 @@ Item {
|
|||
point2x: dst.nodeItem.x + dstAnchor.x
|
||||
point2y: dst.nodeItem.y + dstAnchor.y
|
||||
onPressed: {
|
||||
var canEdit = true
|
||||
if(_reconstruction.computing) {
|
||||
if(uigraph.taskManager.nodes.contains(edge.src.node)) {
|
||||
canEdit = false;
|
||||
} else {
|
||||
if(object.globalStatus == "SUCCESS") {
|
||||
var nodes = uigraph.graph.onlyNodesFromNode(edge.src.node);
|
||||
for(var i = 0; i < nodes.length; i++) {
|
||||
if(["SUBMITTED", "RUNNING"].includes(nodes[i].globalStatus) && nodes[i].chunks.at(0).statusNodeName == nodes[i].name) {
|
||||
canEdit = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const canEdit = !edge.src.node.locked
|
||||
|
||||
if(canEdit && event.button == Qt.RightButton)
|
||||
{
|
||||
|
@ -325,27 +311,7 @@ Item {
|
|||
}
|
||||
MenuItem {
|
||||
text: "Remove Node" + (removeFollowingButton.hovered ? "s From Here" : "")
|
||||
enabled: {
|
||||
if(! _reconstruction.computing) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if(uigraph.taskManager.nodes.contains(uigraph.selectedNode)) {
|
||||
return false;
|
||||
} else {
|
||||
if(uigraph.selectedNode.globalStatus == "SUCCESS") {
|
||||
var nodes = uigraph.graph.onlyNodesFromNode(uigraph.selectedNode);
|
||||
for(var i = 0; i < nodes.length; i++) {
|
||||
if(["SUBMITTED", "RUNNING"].includes(nodes[i].globalStatus) && nodes[i].chunks.at(0).statusNodeName == nodes[i].name) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
enabled: nodeMenu.currentNode ? !nodeMenu.currentNode.locked : false
|
||||
onTriggered: uigraph.removeNode(nodeMenu.currentNode)
|
||||
MaterialToolButton {
|
||||
id: removeFollowingButton
|
||||
|
@ -361,26 +327,7 @@ Item {
|
|||
MenuSeparator {}
|
||||
MenuItem {
|
||||
text: "Delete Data" + (deleteFollowingButton.hovered ? " From Here" : "" ) + "..."
|
||||
enabled: {
|
||||
if(! _reconstruction.computing) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if(uigraph.taskManager.nodes.contains(uigraph.selectedNode) || ["SUBMITTED", "RUNNING"].includes(_reconstruction.selectedNode.globalStatus)) {
|
||||
return false;
|
||||
} else {
|
||||
if(uigraph.selectedNode.globalStatus == "SUCCESS") {
|
||||
var nodes = uigraph.graph.onlyNodesFromNode(uigraph.selectedNode);
|
||||
for(var i = 0; i < nodes.length; i++) {
|
||||
if(["SUBMITTED", "RUNNING"].includes(nodes[i].globalStatus) && nodes[i].chunks.at(0).statusNodeName == nodes[i].name) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
enabled: nodeMenu.currentNode ? !nodeMenu.currentNode.locked : false
|
||||
|
||||
function showConfirmationDialog(deleteFollowing) {
|
||||
var obj = deleteDataDialog.createObject(root,
|
||||
|
@ -443,26 +390,7 @@ Item {
|
|||
|
||||
node: object
|
||||
width: uigraph.layout.nodeWidth
|
||||
readOnly: {
|
||||
if(! uigraph.computing) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(object.globalStatus == "SUCCESS") {
|
||||
var nodes = uigraph.graph.onlyNodesFromNode(object);
|
||||
for(var i = 0; i < nodes.length; i++) {
|
||||
if(["SUBMITTED", "RUNNING"].includes(nodes[i].globalStatus) && nodes[i].chunks.at(0).statusNodeName == nodes[i].name) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else if(["SUBMITTED", "RUNNING"].includes(object.globalStatus)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
selected: uigraph.selectedNode === node
|
||||
hovered: uigraph.hoveredNode === node
|
||||
onSelectedChanged: if(selected) forceActiveFocus()
|
||||
|
|
|
@ -16,7 +16,7 @@ Item {
|
|||
/// The underlying Node object
|
||||
property variant node
|
||||
/// Whether the node can be modified
|
||||
property bool readOnly: false
|
||||
property bool readOnly: node.locked
|
||||
/// Whether the node is in compatibility mode
|
||||
readonly property bool isCompatibilityNode: node.hasOwnProperty("compatibilityIssue")
|
||||
/// Mouse related states
|
||||
|
|
|
@ -167,13 +167,10 @@ ApplicationWindow {
|
|||
}
|
||||
else
|
||||
_reconstruction.execute(node);
|
||||
|
||||
nodeEditor.updateNodeStatus()
|
||||
}
|
||||
|
||||
function submit(node) {
|
||||
_reconstruction.submit(node);
|
||||
nodeEditor.updateNodeStatus()
|
||||
}
|
||||
|
||||
|
||||
|
@ -729,32 +726,8 @@ ApplicationWindow {
|
|||
node: _reconstruction.selectedNode
|
||||
property bool computing: _reconstruction.computing
|
||||
// Make NodeEditor readOnly when computing
|
||||
readOnly: false
|
||||
onNodeChanged: { updateNodeStatus() }
|
||||
onComputingChanged: { updateNodeStatus() }
|
||||
readOnly: node.locked
|
||||
|
||||
function updateNodeStatus() {
|
||||
if(! _reconstruction.computing) {
|
||||
readOnly = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if(node.globalStatus === "SUCCESS") {
|
||||
var nodes = _reconstruction.graph.onlyNodesFromNode(node);
|
||||
for(var i = 0; i < nodes.length; i++) {
|
||||
if(["SUBMITTED", "RUNNING"].includes(nodes[i].globalStatus) && nodes[i].chunks.at(0).statusNodeName == nodes[i].name) {
|
||||
readOnly = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
readOnly = false;
|
||||
} else if(["SUBMITTED", "RUNNING"].includes(node.globalStatus)) {
|
||||
readOnly = true;
|
||||
} else {
|
||||
readOnly = false;
|
||||
}
|
||||
|
||||
}
|
||||
onAttributeDoubleClicked: workspaceView.viewAttribute(attribute, mouse)
|
||||
onUpgradeRequest: {
|
||||
var n = _reconstruction.upgradeNode(node);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue