mirror of
https://github.com/alicevision/Meshroom.git
synced 2025-05-22 13:36:31 +02:00
Don't lock graph and node editor while computing nodes
Add possibilty to, while computing nodes: add more nodes to the task manager, edit, duplicate and remove nodes without breaking the tasks that are submitted
This commit is contained in:
parent
51d6c18840
commit
c00db25c23
5 changed files with 94 additions and 28 deletions
|
@ -216,6 +216,7 @@ class QObjectListModel(QtCore.QAbstractListModel):
|
||||||
def reset(self, objects):
|
def reset(self, objects):
|
||||||
self.setObjectList(objects)
|
self.setObjectList(objects)
|
||||||
|
|
||||||
|
@QtCore.Slot(QtCore.QObject, result=bool)
|
||||||
def contains(self, obj):
|
def contains(self, obj):
|
||||||
""" Returns true if the list contains an occurrence of object;
|
""" Returns true if the list contains an occurrence of object;
|
||||||
otherwise returns false.
|
otherwise returns false.
|
||||||
|
|
|
@ -893,6 +893,21 @@ class Graph(BaseObject):
|
||||||
self.dfs(visitor=visitor, startNodes=[startNode], reverse=True)
|
self.dfs(visitor=visitor, startNodes=[startNode], reverse=True)
|
||||||
return nodes, edges
|
return nodes, edges
|
||||||
|
|
||||||
|
@Slot(Node, result="QVariantList")
|
||||||
|
def onlyNodesFromNode(self, startNode, filterType=None):
|
||||||
|
nodes = []
|
||||||
|
edges = []
|
||||||
|
visitor = Visitor()
|
||||||
|
|
||||||
|
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)
|
||||||
|
return nodes
|
||||||
|
|
||||||
def _applyExpr(self):
|
def _applyExpr(self):
|
||||||
with GraphModification(self):
|
with GraphModification(self):
|
||||||
for node in self._nodes:
|
for node in self._nodes:
|
||||||
|
|
|
@ -225,6 +225,9 @@ class NodeChunk(BaseObject):
|
||||||
if newStatus.value <= self.status.status.value:
|
if newStatus.value <= self.status.status.value:
|
||||||
print('WARNING: downgrade status on node "{}" from {} to {}'.format(self.name, self.status.status,
|
print('WARNING: downgrade status on node "{}" from {} to {}'.format(self.name, self.status.status,
|
||||||
newStatus))
|
newStatus))
|
||||||
|
|
||||||
|
if(newStatus == Status.SUBMITTED):
|
||||||
|
self.status = StatusData(self.node.name, self.node.nodeType, self.node.packageName, self.node.packageVersion)
|
||||||
if execMode is not None:
|
if execMode is not None:
|
||||||
self.status.execMode = execMode
|
self.status.execMode = execMode
|
||||||
self.execModeNameChanged.emit()
|
self.execModeNameChanged.emit()
|
||||||
|
@ -282,7 +285,8 @@ class NodeChunk(BaseObject):
|
||||||
try:
|
try:
|
||||||
self.node.nodeDesc.processChunk(self)
|
self.node.nodeDesc.processChunk(self)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.upgradeStatusTo(Status.ERROR)
|
if self.status.status != Status.STOPPED:
|
||||||
|
self.upgradeStatusTo(Status.ERROR)
|
||||||
raise
|
raise
|
||||||
except (KeyboardInterrupt, SystemError, GeneratorExit) as e:
|
except (KeyboardInterrupt, SystemError, GeneratorExit) as e:
|
||||||
self.upgradeStatusTo(Status.STOPPED)
|
self.upgradeStatusTo(Status.STOPPED)
|
||||||
|
@ -314,6 +318,9 @@ class NodeChunk(BaseObject):
|
||||||
logFile = Property(str, logFile.fget, notify=nodeFolderChanged)
|
logFile = Property(str, logFile.fget, notify=nodeFolderChanged)
|
||||||
statisticsFile = Property(str, statisticsFile.fget, notify=nodeFolderChanged)
|
statisticsFile = Property(str, statisticsFile.fget, notify=nodeFolderChanged)
|
||||||
|
|
||||||
|
nodeName = Property(str, lambda self: self.node.name, constant=True)
|
||||||
|
statusNodeName = Property(str, lambda self: self.status.nodeName, constant=True)
|
||||||
|
|
||||||
|
|
||||||
# simple structure for storing node position
|
# simple structure for storing node position
|
||||||
Position = namedtuple("Position", ["x", "y"])
|
Position = namedtuple("Position", ["x", "y"])
|
||||||
|
|
|
@ -60,8 +60,6 @@ Item {
|
||||||
|
|
||||||
/// Duplicate a node and optionnally all the following ones
|
/// Duplicate a node and optionnally all the following ones
|
||||||
function duplicateNode(node, duplicateFollowingNodes) {
|
function duplicateNode(node, duplicateFollowingNodes) {
|
||||||
if(root.readOnly)
|
|
||||||
return;
|
|
||||||
var nodes = uigraph.duplicateNode(node, duplicateFollowingNodes)
|
var nodes = uigraph.duplicateNode(node, duplicateFollowingNodes)
|
||||||
selectNode(nodes[0])
|
selectNode(nodes[0])
|
||||||
}
|
}
|
||||||
|
@ -120,13 +118,9 @@ Item {
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if(mouse.button == Qt.RightButton)
|
if(mouse.button == Qt.RightButton)
|
||||||
{
|
{
|
||||||
if(readOnly)
|
// store mouse click position in 'draggable' coordinates as new node spawn position
|
||||||
lockedMenu.popup();
|
newNodeMenu.spawnPosition = mouseArea.mapToItem(draggable, mouse.x, mouse.y);
|
||||||
else {
|
newNodeMenu.popup();
|
||||||
// store mouse click position in 'draggable' coordinates as new node spawn position
|
|
||||||
newNodeMenu.spawnPosition = mouseArea.mapToItem(draggable, mouse.x, mouse.y);
|
|
||||||
newNodeMenu.popup();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -281,12 +275,12 @@ Item {
|
||||||
|
|
||||||
MenuItem {
|
MenuItem {
|
||||||
text: "Compute"
|
text: "Compute"
|
||||||
enabled: !uigraph.computing && !root.readOnly && nodeMenu.canComputeNode
|
enabled: nodeMenu.canComputeNode
|
||||||
onTriggered: computeRequest(nodeMenu.currentNode)
|
onTriggered: computeRequest(nodeMenu.currentNode)
|
||||||
}
|
}
|
||||||
MenuItem {
|
MenuItem {
|
||||||
text: "Submit"
|
text: "Submit"
|
||||||
enabled: !uigraph.computing && !root.readOnly && nodeMenu.canComputeNode
|
enabled: nodeMenu.canComputeNode
|
||||||
visible: uigraph.canSubmit
|
visible: uigraph.canSubmit
|
||||||
height: visible ? implicitHeight : 0
|
height: visible ? implicitHeight : 0
|
||||||
onTriggered: submitRequest(nodeMenu.currentNode)
|
onTriggered: submitRequest(nodeMenu.currentNode)
|
||||||
|
@ -298,7 +292,7 @@ Item {
|
||||||
MenuSeparator {}
|
MenuSeparator {}
|
||||||
MenuItem {
|
MenuItem {
|
||||||
text: "Duplicate Node" + (duplicateFollowingButton.hovered ? "s From Here" : "")
|
text: "Duplicate Node" + (duplicateFollowingButton.hovered ? "s From Here" : "")
|
||||||
enabled: !root.readOnly
|
enabled: true
|
||||||
onTriggered: duplicateNode(nodeMenu.currentNode, false)
|
onTriggered: duplicateNode(nodeMenu.currentNode, false)
|
||||||
MaterialToolButton {
|
MaterialToolButton {
|
||||||
id: duplicateFollowingButton
|
id: duplicateFollowingButton
|
||||||
|
@ -313,7 +307,27 @@ Item {
|
||||||
}
|
}
|
||||||
MenuItem {
|
MenuItem {
|
||||||
text: "Remove Node" + (removeFollowingButton.hovered ? "s From Here" : "")
|
text: "Remove Node" + (removeFollowingButton.hovered ? "s From Here" : "")
|
||||||
enabled: !root.readOnly
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
onTriggered: uigraph.removeNode(nodeMenu.currentNode)
|
onTriggered: uigraph.removeNode(nodeMenu.currentNode)
|
||||||
MaterialToolButton {
|
MaterialToolButton {
|
||||||
id: removeFollowingButton
|
id: removeFollowingButton
|
||||||
|
@ -329,7 +343,26 @@ Item {
|
||||||
MenuSeparator {}
|
MenuSeparator {}
|
||||||
MenuItem {
|
MenuItem {
|
||||||
text: "Delete Data" + (deleteFollowingButton.hovered ? " From Here" : "" ) + "..."
|
text: "Delete Data" + (deleteFollowingButton.hovered ? " From Here" : "" ) + "..."
|
||||||
enabled: !root.readOnly
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
function showConfirmationDialog(deleteFollowing) {
|
function showConfirmationDialog(deleteFollowing) {
|
||||||
var obj = deleteDataDialog.createObject(root,
|
var obj = deleteDataDialog.createObject(root,
|
||||||
|
|
|
@ -21,7 +21,8 @@ ApplicationWindow {
|
||||||
visible: true
|
visible: true
|
||||||
|
|
||||||
/// Whether graph is currently locked and therefore read-only
|
/// Whether graph is currently locked and therefore read-only
|
||||||
readonly property bool graphLocked: _reconstruction.computing && GraphEditorSettings.lockOnCompute
|
readonly property bool graphLocked: _reconstruction.computing
|
||||||
|
|
||||||
|
|
||||||
title: {
|
title: {
|
||||||
var t = _reconstruction.graph.filepath || "Untitled"
|
var t = _reconstruction.graph.filepath || "Untitled"
|
||||||
|
@ -568,17 +569,6 @@ ApplicationWindow {
|
||||||
enabled: !_reconstruction.computingLocally
|
enabled: !_reconstruction.computingLocally
|
||||||
onTriggered: _reconstruction.forceNodesStatusUpdate()
|
onTriggered: _reconstruction.forceNodesStatusUpdate()
|
||||||
}
|
}
|
||||||
Menu {
|
|
||||||
title: "Advanced"
|
|
||||||
MenuItem {
|
|
||||||
text: "Lock on Compute"
|
|
||||||
ToolTip.text: "Lock Graph when computing. This should only be disabled for advanced usage."
|
|
||||||
ToolTip.visible: hovered
|
|
||||||
checkable: true
|
|
||||||
checked: GraphEditorSettings.lockOnCompute
|
|
||||||
onClicked: GraphEditorSettings.lockOnCompute = !GraphEditorSettings.lockOnCompute
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -646,7 +636,27 @@ ApplicationWindow {
|
||||||
width: Math.round(parent.width * 0.3)
|
width: Math.round(parent.width * 0.3)
|
||||||
node: _reconstruction.selectedNode
|
node: _reconstruction.selectedNode
|
||||||
// Make NodeEditor readOnly when computing
|
// Make NodeEditor readOnly when computing
|
||||||
readOnly: graphLocked
|
// readOnly: graphLocked
|
||||||
|
readOnly: {
|
||||||
|
if(! _reconstruction.computing) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_reconstruction.taskManager.nodes.contains(_reconstruction.selectedNode)) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
if(_reconstruction.selectedNode.globalStatus == "SUCCESS") {
|
||||||
|
var nodes = _reconstruction.graph.onlyNodesFromNode(_reconstruction.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 true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
onAttributeDoubleClicked: workspaceView.viewIn3D(attribute, mouse)
|
onAttributeDoubleClicked: workspaceView.viewIn3D(attribute, mouse)
|
||||||
onUpgradeRequest: {
|
onUpgradeRequest: {
|
||||||
var n = _reconstruction.upgradeNode(node);
|
var n = _reconstruction.upgradeNode(node);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue