[ui] save after drag&drop: split of handling types and processing files

First get type of files, then either ensure the save or process files.
This commit is contained in:
Aurore LAFAURIE 2024-03-21 18:35:46 +01:00
parent 67fbf1b00f
commit 58e9bafa45
3 changed files with 47 additions and 29 deletions

View file

@ -81,7 +81,14 @@ Item {
onRemoveImageRequest: reconstruction.removeAttribute(attribute)
onAllViewpointsCleared: { reconstruction.removeAllImages(); reconstruction.selectedViewId = "-1" }
onFilesDropped: {
reconstruction.handleFilesUrl(drop.urls, augmentSfm ? null : cameraInit)
var filesByType = _reconstruction.getFilesByTypeFromDrop(drop.urls)
if (filesByType["other"].length > 0) {
ensureSaved(function() {
reconstruction.handleFilesUrl(filesByType, augmentSfm ? null : cameraInit)
})
} else {
reconstruction.handleFilesUrl(filesByType, augmentSfm ? null : cameraInit)
}
}
}
LiveSfmView {

View file

@ -1187,7 +1187,14 @@ ApplicationWindow {
computeManager.submit(node)
}
onFilesDropped: {
_reconstruction.handleFilesUrl(drop.urls, null, mousePosition)
var filesByType = _reconstruction.getFilesByTypeFromDrop(drop.urls)
if (filesByType["other"].length > 0) {
ensureSaved(function() {
_reconstruction.handleFilesUrl(filesByType, null, mousePosition)
})
} else {
_reconstruction.handleFilesUrl(filesByType, null, mousePosition)
}
}
}

View file

@ -716,15 +716,19 @@ class Reconstruction(UIGraph):
""" Get all view Ids involved in the reconstruction. """
return [vp.viewId.value for node in self._cameraInits for vp in node.viewpoints.value]
@Slot('QList<QUrl>')
@Slot('QList<QUrl>', Node)
@Slot('QList<QUrl>', Node, 'QPoint')
def handleFilesUrl(self, urls, cameraInit=None, position=None):
@Slot("QVariantMap")
@Slot("QVariantMap", Node)
@Slot("QVariantMap", Node, "QPoint")
def handleFilesUrl(self, filesByType, cameraInit=None, position=None):
""" Handle drop events aiming to add images to the Reconstruction.
This method allows to reduce process time by doing it on Python side.
Args:
{images, videos, panoramaInfo, otherFiles}: Map of paths of recognized images and list of other files
Node: cameraInit node used to add new images to it
QPoint: position to locate the node (usually the mouse position)
"""
filesByType = self.getFilesByTypeFromDrop(urls)
if filesByType.images:
if filesByType["images"]:
if cameraInit is None:
boundingBox = self.layout.boundingBox()
if not position:
@ -734,15 +738,15 @@ class Reconstruction(UIGraph):
else:
p = position
cameraInit = self.addNewNode("CameraInit", position=p)
self._workerThreads.apply_async(func=self.importImagesSync, args=(filesByType.images, cameraInit,))
if filesByType.videos:
self._workerThreads.apply_async(func=self.importImagesSync, args=(filesByType["images"], cameraInit,))
if filesByType["videos"]:
boundingBox = self.layout.boundingBox()
keyframeNode = self.addNewNode("KeyframeSelection", position=Position(boundingBox[0], boundingBox[1] + boundingBox[3]))
keyframeNode.inputPaths.value = filesByType.videos
if len(filesByType.videos) == 1:
keyframeNode.inputPaths.value = filesByType["videos"]
if len(filesByType["videos"]) == 1:
newVideoNodeMessage = "New node '{}' added for the input video.".format(keyframeNode.getLabel())
else:
newVideoNodeMessage = "New node '{}' added for a rig of {} synchronized cameras.".format(keyframeNode.getLabel(), len(filesByType.videos))
newVideoNodeMessage = "New node '{}' added for a rig of {} synchronized cameras.".format(keyframeNode.getLabel(), len(filesByType["videos"]))
self.info.emit(
Message(
"Video Input",
@ -752,17 +756,17 @@ class Reconstruction(UIGraph):
"If you know the Camera Make/Model, it is highly recommended to declare them in the Node."
))
if filesByType.panoramaInfo:
if len(filesByType.panoramaInfo) > 1:
if filesByType["panoramaInfo"]:
if len(filesByType["panoramaInfo"]) > 1:
self.error.emit(
Message(
"Multiple XML files in input",
"Ignore the xml Panorama files:\n\n'{}'.".format(',\n'.join(filesByType.panoramaInfo)),
"Ignore the xml Panorama files:\n\n'{}'.".format(',\n'.join(filesByType["panoramaInfo"])),
"",
))
else:
panoramaInitNodes = self.graph.nodesOfType('PanoramaInit')
for panoramaInfoFile in filesByType.panoramaInfo:
for panoramaInfoFile in filesByType["panoramaInfo"]:
for panoramaInitNode in panoramaInitNodes:
panoramaInitNode.attribute('initializeCameras').value = 'File'
panoramaInitNode.attribute('config').value = panoramaInfoFile
@ -771,44 +775,44 @@ class Reconstruction(UIGraph):
Message(
"Panorama XML",
"XML file declared on PanoramaInit node",
"XML file '{}' set on node '{}'".format(','.join(filesByType.panoramaInfo), ','.join([n.getLabel() for n in panoramaInitNodes])),
"XML file '{}' set on node '{}'".format(','.join(filesByType["panoramaInfo"]), ','.join([n.getLabel() for n in panoramaInitNodes])),
))
else:
self.error.emit(
Message(
"No PanoramaInit Node",
"No PanoramaInit Node to set the Panorama file:\n'{}'.".format(','.join(filesByType.panoramaInfo)),
"No PanoramaInit Node to set the Panorama file:\n'{}'.".format(','.join(filesByType["panoramaInfo"])),
"",
))
if not filesByType.images and not filesByType.videos and not filesByType.panoramaInfo:
if filesByType.other:
if not filesByType["images"] and not filesByType["videos"] and not filesByType["panoramaInfo"]:
if filesByType["other"]:
singleMgFile = False
if len(filesByType.other) == 1:
url = filesByType.other[0]
if len(filesByType["other"]) == 1:
url = filesByType["other"][0]
ext = os.path.splitext(url)[1]
if ext == '.mg':
self.loadUrl(url)
singleMgFile = True
if not singleMgFile:
extensions = set([os.path.splitext(url)[1] for url in filesByType.other])
extensions = set([os.path.splitext(url)[1] for url in filesByType["other"]])
self.error.emit(
Message(
"No Recognized Input File",
"No recognized input file in the {} dropped files".format(len(filesByType.other)),
"No recognized input file in the {} dropped files".format(len(filesByType["other"])),
"Unknown file extensions: " + ', '.join(extensions)
)
)
@staticmethod
def getFilesByTypeFromDrop(urls):
@Slot("QList<QUrl>", result="QVariantMap")
def getFilesByTypeFromDrop(self, urls):
"""
Args:
urls: list of filepaths
Returns:
<images, otherFiles> List of recognized images and list of other files
{images, otherFiles}: Map of recognized images and list of other files
"""
# Build the list of images paths
filesByType = multiview.FilesByType()
@ -818,7 +822,7 @@ class Reconstruction(UIGraph):
filesByType.extend(multiview.findFilesByTypeInFolder(localFile))
else:
filesByType.addFile(localFile)
return filesByType
return {"images": filesByType.images, "videos": filesByType.videos, "panoramaInfo":filesByType.panoramaInfo, "other":filesByType.other}
def importImagesFromFolder(self, path, recursive=False):
"""