[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) onRemoveImageRequest: reconstruction.removeAttribute(attribute)
onAllViewpointsCleared: { reconstruction.removeAllImages(); reconstruction.selectedViewId = "-1" } onAllViewpointsCleared: { reconstruction.removeAllImages(); reconstruction.selectedViewId = "-1" }
onFilesDropped: { 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 { LiveSfmView {

View file

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