From 17506595df17a1c18b42758f2a80ff7ccab28c7f Mon Sep 17 00:00:00 2001 From: Benedikt Best <63287233+btbest@users.noreply.github.com> Date: Mon, 5 Aug 2024 16:35:13 +0200 Subject: [PATCH 1/8] H5N5 export refactor: Rename hdf5 options widget to generalise --- ...idget.py => hierarchicalFileExportOptionsWidget.py} | 10 +++++----- ...idget.ui => hierarchicalFileExportOptionsWidget.ui} | 0 .../widgets/multiformatSlotExportFileOptionsWidget.py | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) rename volumina/widgets/{hdf5ExportFileOptionsWidget.py => hierarchicalFileExportOptionsWidget.py} (95%) rename volumina/widgets/{hdf5ExportFileOptionsWidget.ui => hierarchicalFileExportOptionsWidget.ui} (100%) diff --git a/volumina/widgets/hdf5ExportFileOptionsWidget.py b/volumina/widgets/hierarchicalFileExportOptionsWidget.py similarity index 95% rename from volumina/widgets/hdf5ExportFileOptionsWidget.py rename to volumina/widgets/hierarchicalFileExportOptionsWidget.py index 483fe4df4..42e25fecd 100644 --- a/volumina/widgets/hdf5ExportFileOptionsWidget.py +++ b/volumina/widgets/hierarchicalFileExportOptionsWidget.py @@ -1,7 +1,7 @@ ############################################################################### # volumina: volume slicing and editing library # -# Copyright (C) 2011-2018, the ilastik developers +# Copyright (C) 2011-2024, the ilastik developers # # # This program is free software; you can redistribute it and/or @@ -26,11 +26,11 @@ from PyQt5.QtWidgets import QWidget, QFileDialog -class Hdf5ExportFileOptionsWidget(QWidget): +class HierarchicalFileExportOptionsWidget(QWidget): pathValidityChange = pyqtSignal(bool) def __init__(self, parent): - super(Hdf5ExportFileOptionsWidget, self).__init__(parent) + super().__init__(parent) uic.loadUi(os.path.splitext(__file__)[0] + ".ui", self) self.settings_are_valid = True @@ -51,7 +51,7 @@ def initSlots(self, filepathSlot, datasetNameSlot, fullPathOutputSlot): self.datasetEdit.installEventFilter(self) def showEvent(self, event): - super(Hdf5ExportFileOptionsWidget, self).showEvent(event) + super().showEvent(event) self.updateFromSlots() def eventFilter(self, watched, event): @@ -148,7 +148,7 @@ def propagateDirty(self, *args): op = OpMock(graph=Graph()) app = QApplication([]) - w = Hdf5ExportFileOptionsWidget(None) + w = HierarchicalFileExportOptionsWidget(None) w.initSlots(op.Filepath, op.DatasetName, op.FullPath) w.show() app.exec_() diff --git a/volumina/widgets/hdf5ExportFileOptionsWidget.ui b/volumina/widgets/hierarchicalFileExportOptionsWidget.ui similarity index 100% rename from volumina/widgets/hdf5ExportFileOptionsWidget.ui rename to volumina/widgets/hierarchicalFileExportOptionsWidget.ui diff --git a/volumina/widgets/multiformatSlotExportFileOptionsWidget.py b/volumina/widgets/multiformatSlotExportFileOptionsWidget.py index d5b8acf5e..88fb7bbbc 100644 --- a/volumina/widgets/multiformatSlotExportFileOptionsWidget.py +++ b/volumina/widgets/multiformatSlotExportFileOptionsWidget.py @@ -31,7 +31,7 @@ from PyQt5.QtWidgets import QWidget from .singleFileExportOptionsWidget import SingleFileExportOptionsWidget -from .hdf5ExportFileOptionsWidget import Hdf5ExportFileOptionsWidget +from .hierarchicalFileExportOptionsWidget import HierarchicalFileExportOptionsWidget from .n5ExportFileOptionsWidget import N5ExportFileOptionsWidget from .stackExportFileOptionsWidget import StackExportFileOptionsWidget @@ -73,7 +73,7 @@ def initExportOp(self, opDataExport): # HDF5 for fmt in ("compressed hdf5", "hdf5"): - hdf5OptionsWidget = Hdf5ExportFileOptionsWidget(self) + hdf5OptionsWidget = HierarchicalFileExportOptionsWidget(self) hdf5OptionsWidget.initSlots( opDataExport.OutputFilenameFormat, opDataExport.OutputInternalPath, opDataExport.ExportPath ) From eaa68fe5ba66e40891b13c729f0094c7f96b44e1 Mon Sep 17 00:00:00 2001 From: Benedikt Best <63287233+btbest@users.noreply.github.com> Date: Mon, 5 Aug 2024 16:39:42 +0200 Subject: [PATCH 2/8] H5N5 export refactor: Merge H5 and N5 widgets --- .../hierarchicalFileExportOptionsWidget.py | 16 +- .../multiformatSlotExportFileOptionsWidget.py | 7 +- volumina/widgets/n5ExportFileOptionsWidget.py | 159 ------------------ volumina/widgets/n5ExportFileOptionsWidget.ui | 67 -------- 4 files changed, 14 insertions(+), 235 deletions(-) delete mode 100644 volumina/widgets/n5ExportFileOptionsWidget.py delete mode 100644 volumina/widgets/n5ExportFileOptionsWidget.ui diff --git a/volumina/widgets/hierarchicalFileExportOptionsWidget.py b/volumina/widgets/hierarchicalFileExportOptionsWidget.py index 42e25fecd..fc5138cc5 100644 --- a/volumina/widgets/hierarchicalFileExportOptionsWidget.py +++ b/volumina/widgets/hierarchicalFileExportOptionsWidget.py @@ -20,6 +20,7 @@ # http://ilastik.org/license/ ############################################################################### import os +from typing import Tuple from PyQt5 import uic from PyQt5.QtCore import pyqtSignal, Qt, QEvent @@ -29,9 +30,12 @@ class HierarchicalFileExportOptionsWidget(QWidget): pathValidityChange = pyqtSignal(bool) - def __init__(self, parent): + def __init__(self, parent, file_extensions: Tuple[str, ...], default_extension: str, extension_description: str): super().__init__(parent) uic.loadUi(os.path.splitext(__file__)[0] + ".ui", self) + self.file_extensions = file_extensions + self.default_extension = default_extension + self.extension_description = extension_description self.settings_are_valid = True @@ -95,8 +99,8 @@ def updateFromSlots(self): if self._filepathSlot.ready(): file_path = self._filepathSlot.value file_path, ext = os.path.splitext(file_path) - if ext != ".h5" and ext != ".hdf5": - file_path += ".h5" + if ext not in self.file_extensions: + file_path += f".{self.default_extension}" else: file_path += ext self.filepathEdit.setText(file_path) @@ -115,9 +119,9 @@ def _browseForFilepath(self): else: starting_dir = os.path.expanduser("~") - dlg = QFileDialog(self, "Export Location", starting_dir, "HDF5 Files (*.h5 *.hdf5)") + dlg = QFileDialog(self, "Export Location", starting_dir, self.extension_description) - dlg.setDefaultSuffix("h5") + dlg.setDefaultSuffix(self.default_extension) dlg.setAcceptMode(QFileDialog.AcceptSave) if not dlg.exec_(): return @@ -148,7 +152,7 @@ def propagateDirty(self, *args): op = OpMock(graph=Graph()) app = QApplication([]) - w = HierarchicalFileExportOptionsWidget(None) + w = HierarchicalFileExportOptionsWidget(None, (".h5"), "h5", "H5 Files (*.h5)") w.initSlots(op.Filepath, op.DatasetName, op.FullPath) w.show() app.exec_() diff --git a/volumina/widgets/multiformatSlotExportFileOptionsWidget.py b/volumina/widgets/multiformatSlotExportFileOptionsWidget.py index 88fb7bbbc..50db3b39d 100644 --- a/volumina/widgets/multiformatSlotExportFileOptionsWidget.py +++ b/volumina/widgets/multiformatSlotExportFileOptionsWidget.py @@ -32,7 +32,6 @@ from .singleFileExportOptionsWidget import SingleFileExportOptionsWidget from .hierarchicalFileExportOptionsWidget import HierarchicalFileExportOptionsWidget -from .n5ExportFileOptionsWidget import N5ExportFileOptionsWidget from .stackExportFileOptionsWidget import StackExportFileOptionsWidget try: @@ -73,7 +72,9 @@ def initExportOp(self, opDataExport): # HDF5 for fmt in ("compressed hdf5", "hdf5"): - hdf5OptionsWidget = HierarchicalFileExportOptionsWidget(self) + hdf5OptionsWidget = HierarchicalFileExportOptionsWidget( + self, (".h5", ".hdf5"), "h5", "HDF5 files (*.h5 *.hdf5)" + ) hdf5OptionsWidget.initSlots( opDataExport.OutputFilenameFormat, opDataExport.OutputInternalPath, opDataExport.ExportPath ) @@ -82,7 +83,7 @@ def initExportOp(self, opDataExport): # N5 for fmt in ("compressed n5", "n5"): - n5OptionsWidget = N5ExportFileOptionsWidget(self) + n5OptionsWidget = HierarchicalFileExportOptionsWidget(self, (".n5",), "n5", "N5 files (*.n5)") n5OptionsWidget.initSlots( opDataExport.OutputFilenameFormat, opDataExport.OutputInternalPath, opDataExport.ExportPath ) diff --git a/volumina/widgets/n5ExportFileOptionsWidget.py b/volumina/widgets/n5ExportFileOptionsWidget.py deleted file mode 100644 index 739327aad..000000000 --- a/volumina/widgets/n5ExportFileOptionsWidget.py +++ /dev/null @@ -1,159 +0,0 @@ -############################################################################### -# volumina: volume slicing and editing library -# -# Copyright (C) 2011-2018, the ilastik developers -# -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the Lesser GNU General Public License -# as published by the Free Software Foundation; either version 2.1 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser General Public License for more details. -# -# See the files LICENSE.lgpl2 and LICENSE.lgpl3 for full text of the -# GNU Lesser General Public License version 2.1 and 3 respectively. -# This information is also available on the ilastik web site at: -# http://ilastik.org/license/ -############################################################################### -import os - -from PyQt5 import uic -from PyQt5.QtCore import pyqtSignal, Qt, QEvent -from PyQt5.QtWidgets import QWidget, QFileDialog - - -class N5ExportFileOptionsWidget(QWidget): - pathValidityChange = pyqtSignal(bool) - - def __init__(self, parent): - super(N5ExportFileOptionsWidget, self).__init__(parent) - uic.loadUi(os.path.splitext(__file__)[0] + ".ui", self) - - self.settings_are_valid = True - - # We need to watch the textEdited signal because Qt has a bug that causes the OK button - # to receive it's click event BEFORE the LineEdit receives its FocusOut event. - # (That is, we can't just watch for FocusOut events and disable the button before the click.) - self.datasetEdit.textEdited.connect(lambda: self._handleTextEdited(self.datasetEdit)) - self.filepathEdit.textEdited.connect(lambda: self._handleTextEdited(self.filepathEdit)) - - def initSlots(self, filepathSlot, datasetNameSlot, fullPathOutputSlot): - self._filepathSlot = filepathSlot - self._datasetNameSlot = datasetNameSlot - self._fullPathOutputSlot = fullPathOutputSlot - self.fileSelectButton.clicked.connect(self._browseForFilepath) - - self.filepathEdit.installEventFilter(self) - self.datasetEdit.installEventFilter(self) - - def showEvent(self, event): - super(N5ExportFileOptionsWidget, self).showEvent(event) - self.updateFromSlots() - - def eventFilter(self, watched, event): - """ - Apply the new path/dataset if the user presses 'enter' - or clicks outside the path/dataset edit box. - """ - if event.type() == QEvent.FocusOut or ( - event.type() == QEvent.KeyPress and (event.key() == Qt.Key_Enter or event.key() == Qt.Key_Return) - ): - if watched == self.datasetEdit: - self._applyDataset() - if watched == self.filepathEdit: - self._applyFilepath() - return False - - def _applyDataset(self): - was_valid = self.settings_are_valid - datasetName = self.datasetEdit.text() - self._datasetNameSlot.setValue(str(datasetName)) - self.settings_are_valid = str(datasetName) != "" - if self.settings_are_valid != was_valid: - self.pathValidityChange.emit(self.settings_are_valid) - - def _applyFilepath(self): - filepath = self.filepathEdit.text() - self._filepathSlot.setValue(filepath) - # TODO: Check for valid path format and signal validity - - def _handleTextEdited(self, watched): - if watched == self.datasetEdit: - self._applyDataset() - if watched == self.filepathEdit: - self._applyFilepath() - - def updateFromSlots(self): - was_valid = self.settings_are_valid - if self._datasetNameSlot.ready(): - dataset_name = self._datasetNameSlot.value - self.datasetEdit.setText(dataset_name) - self.path_is_valid = dataset_name != "" - - if self._filepathSlot.ready(): - file_path = self._filepathSlot.value - file_path, ext = os.path.splitext(file_path) - if ext != ".n5": - file_path += ".n5" - else: - file_path += ext - self.filepathEdit.setText(file_path) - - # Re-configure the file slot in case we changed the extension - self._filepathSlot.setValue(file_path) - - if was_valid != self.path_is_valid: - self.pathValidityChange.emit(self.settings_are_valid) - - def _browseForFilepath(self): - from lazyflow.utility import PathComponents - - if self._fullPathOutputSlot.ready(): - starting_dir = PathComponents(self._fullPathOutputSlot.value).externalDirectory - else: - starting_dir = os.path.expanduser("~") - - dlg = QFileDialog(self, "Export Location", starting_dir, "N5 Files (*.n5)") - - dlg.setDefaultSuffix("n5") - dlg.setAcceptMode(QFileDialog.AcceptSave) - if not dlg.exec_(): - return - - exportPath = dlg.selectedFiles()[0] - self.filepathEdit.setText(exportPath) - self._filepathSlot.setValue(exportPath) - - -if __name__ == "__main__": - from PyQt5.QtWidgets import QApplication - from lazyflow.graph import Graph, Operator, InputSlot - - class OpMock(Operator): - Filepath = InputSlot(value="~/something.n5") - DatasetName = InputSlot(value="volume/data") - FullPath = InputSlot(value="~/") - - def setupOutputs(self): - pass - - def execute(self, *args): - pass - - def propagateDirty(self, *args): - pass - - op = OpMock(graph=Graph()) - - app = QApplication([]) - w = N5ExportFileOptionsWidget(None) - w.initSlots(op.Filepath, op.DatasetName, op.FullPath) - w.show() - app.exec_() - - print("Selected Filepath: {}".format(op.Filepath.value)) - print("Selected Dataset: {}".format(op.DatasetName.value)) diff --git a/volumina/widgets/n5ExportFileOptionsWidget.ui b/volumina/widgets/n5ExportFileOptionsWidget.ui deleted file mode 100644 index 561d5b1de..000000000 --- a/volumina/widgets/n5ExportFileOptionsWidget.ui +++ /dev/null @@ -1,67 +0,0 @@ - - - Form - - - - 0 - 0 - 622 - 92 - - - - - 0 - 0 - - - - Form - - - - - - File: - - - - - - - - - - Dataset: - - - - - - - - - - Qt::Vertical - - - - 20 - 219 - - - - - - - - Select... - - - - - - - - From 1336b2574ef4b92e2e94522aba43fbd4cfc650d1 Mon Sep 17 00:00:00 2001 From: Benedikt Best <63287233+btbest@users.noreply.github.com> Date: Tue, 6 Aug 2024 12:11:43 +0200 Subject: [PATCH 3/8] OME-Zarr: Add export widget --- .../widgets/multiformatSlotExportFileOptionsWidget.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/volumina/widgets/multiformatSlotExportFileOptionsWidget.py b/volumina/widgets/multiformatSlotExportFileOptionsWidget.py index 50db3b39d..65d65d651 100644 --- a/volumina/widgets/multiformatSlotExportFileOptionsWidget.py +++ b/volumina/widgets/multiformatSlotExportFileOptionsWidget.py @@ -90,6 +90,14 @@ def initExportOp(self, opDataExport): n5OptionsWidget.pathValidityChange.connect(self._handlePathValidityChange) self._format_option_editors[fmt] = n5OptionsWidget + # Zarr + zarrOptionsWidget = HierarchicalFileExportOptionsWidget(self, (".zarr",), "zarr", "Zarr files (*.zarr)") + zarrOptionsWidget.initSlots( + opDataExport.OutputFilenameFormat, opDataExport.OutputInternalPath, opDataExport.ExportPath + ) + zarrOptionsWidget.pathValidityChange.connect(self._handlePathValidityChange) + self._format_option_editors["OME-Zarr"] = zarrOptionsWidget + # Numpy npyOptionsWidget = SingleFileExportOptionsWidget(self, "npy", "numpy files (*.npy)") npyOptionsWidget.initSlots(opDataExport.OutputFilenameFormat, opDataExport.ExportPath) From 988676bceb1d807f0564321177638be2b4cd08ad Mon Sep 17 00:00:00 2001 From: Benedikt Best <63287233+btbest@users.noreply.github.com> Date: Mon, 9 Sep 2024 12:39:26 +0200 Subject: [PATCH 4/8] OME-Zarr: Differentiate single/multiscale option --- .../multiformatSlotExportFileOptionsWidget.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/volumina/widgets/multiformatSlotExportFileOptionsWidget.py b/volumina/widgets/multiformatSlotExportFileOptionsWidget.py index 65d65d651..bda955739 100644 --- a/volumina/widgets/multiformatSlotExportFileOptionsWidget.py +++ b/volumina/widgets/multiformatSlotExportFileOptionsWidget.py @@ -91,12 +91,13 @@ def initExportOp(self, opDataExport): self._format_option_editors[fmt] = n5OptionsWidget # Zarr - zarrOptionsWidget = HierarchicalFileExportOptionsWidget(self, (".zarr",), "zarr", "Zarr files (*.zarr)") - zarrOptionsWidget.initSlots( - opDataExport.OutputFilenameFormat, opDataExport.OutputInternalPath, opDataExport.ExportPath - ) - zarrOptionsWidget.pathValidityChange.connect(self._handlePathValidityChange) - self._format_option_editors["OME-Zarr"] = zarrOptionsWidget + for fmt in ("single-scale OME-Zarr", "multi-scale OME-Zarr"): + zarrOptionsWidget = HierarchicalFileExportOptionsWidget(self, (".zarr",), "zarr", "Zarr files (*.zarr)") + zarrOptionsWidget.initSlots( + opDataExport.OutputFilenameFormat, opDataExport.OutputInternalPath, opDataExport.ExportPath + ) + zarrOptionsWidget.pathValidityChange.connect(self._handlePathValidityChange) + self._format_option_editors[fmt] = zarrOptionsWidget # Numpy npyOptionsWidget = SingleFileExportOptionsWidget(self, "npy", "numpy files (*.npy)") From 9181f7fc9c88cc8bc215838b89af79fb26fe0094 Mon Sep 17 00:00:00 2001 From: Benedikt Best <63287233+btbest@users.noreply.github.com> Date: Fri, 13 Sep 2024 08:43:41 +0200 Subject: [PATCH 5/8] OME-Zarr: Revert to single-scale only --- .../multiformatSlotExportFileOptionsWidget.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/volumina/widgets/multiformatSlotExportFileOptionsWidget.py b/volumina/widgets/multiformatSlotExportFileOptionsWidget.py index bda955739..8d3d58765 100644 --- a/volumina/widgets/multiformatSlotExportFileOptionsWidget.py +++ b/volumina/widgets/multiformatSlotExportFileOptionsWidget.py @@ -91,13 +91,12 @@ def initExportOp(self, opDataExport): self._format_option_editors[fmt] = n5OptionsWidget # Zarr - for fmt in ("single-scale OME-Zarr", "multi-scale OME-Zarr"): - zarrOptionsWidget = HierarchicalFileExportOptionsWidget(self, (".zarr",), "zarr", "Zarr files (*.zarr)") - zarrOptionsWidget.initSlots( - opDataExport.OutputFilenameFormat, opDataExport.OutputInternalPath, opDataExport.ExportPath - ) - zarrOptionsWidget.pathValidityChange.connect(self._handlePathValidityChange) - self._format_option_editors[fmt] = zarrOptionsWidget + zarrOptionsWidget = HierarchicalFileExportOptionsWidget(self, (".zarr",), "zarr", "Zarr files (*.zarr)") + zarrOptionsWidget.initSlots( + opDataExport.OutputFilenameFormat, opDataExport.OutputInternalPath, opDataExport.ExportPath + ) + zarrOptionsWidget.pathValidityChange.connect(self._handlePathValidityChange) + self._format_option_editors["single-scale OME-Zarr"] = zarrOptionsWidget # Numpy npyOptionsWidget = SingleFileExportOptionsWidget(self, "npy", "numpy files (*.npy)") From f2dea57f109748a71aee3baa1f3492b7d015c173 Mon Sep 17 00:00:00 2001 From: Benedikt Best <63287233+btbest@users.noreply.github.com> Date: Fri, 27 Sep 2024 14:10:05 +0200 Subject: [PATCH 6/8] OME-Zarr: Allow exporting without dataset name --- volumina/widgets/hierarchicalFileExportOptionsWidget.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/volumina/widgets/hierarchicalFileExportOptionsWidget.py b/volumina/widgets/hierarchicalFileExportOptionsWidget.py index fc5138cc5..a476a6c87 100644 --- a/volumina/widgets/hierarchicalFileExportOptionsWidget.py +++ b/volumina/widgets/hierarchicalFileExportOptionsWidget.py @@ -74,7 +74,7 @@ def _applyDataset(self): was_valid = self.settings_are_valid datasetName = self.datasetEdit.text() self._datasetNameSlot.setValue(str(datasetName)) - self.settings_are_valid = str(datasetName) != "" + self.settings_are_valid = str(datasetName) != "" or self.default_extension == "zarr" if self.settings_are_valid != was_valid: self.pathValidityChange.emit(self.settings_are_valid) From 9bca34a2d8c5766358882f9b4e376a1c3d2342ef Mon Sep 17 00:00:00 2001 From: Benedikt Best <63287233+btbest@users.noreply.github.com> Date: Wed, 2 Oct 2024 16:35:42 +0200 Subject: [PATCH 7/8] Hierarchical export options: Default first extension Get rid of unintuitive extensions without leading . --- .../widgets/hierarchicalFileExportOptionsWidget.py | 12 ++++++------ .../multiformatSlotExportFileOptionsWidget.py | 8 +++----- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/volumina/widgets/hierarchicalFileExportOptionsWidget.py b/volumina/widgets/hierarchicalFileExportOptionsWidget.py index a476a6c87..b860ef6d9 100644 --- a/volumina/widgets/hierarchicalFileExportOptionsWidget.py +++ b/volumina/widgets/hierarchicalFileExportOptionsWidget.py @@ -30,11 +30,11 @@ class HierarchicalFileExportOptionsWidget(QWidget): pathValidityChange = pyqtSignal(bool) - def __init__(self, parent, file_extensions: Tuple[str, ...], default_extension: str, extension_description: str): + def __init__(self, parent, file_extensions: Tuple[str, ...], extension_description: str): super().__init__(parent) uic.loadUi(os.path.splitext(__file__)[0] + ".ui", self) self.file_extensions = file_extensions - self.default_extension = default_extension + self.default_extension = file_extensions[0] self.extension_description = extension_description self.settings_are_valid = True @@ -74,7 +74,7 @@ def _applyDataset(self): was_valid = self.settings_are_valid datasetName = self.datasetEdit.text() self._datasetNameSlot.setValue(str(datasetName)) - self.settings_are_valid = str(datasetName) != "" or self.default_extension == "zarr" + self.settings_are_valid = str(datasetName) != "" or self.default_extension == ".zarr" if self.settings_are_valid != was_valid: self.pathValidityChange.emit(self.settings_are_valid) @@ -100,7 +100,7 @@ def updateFromSlots(self): file_path = self._filepathSlot.value file_path, ext = os.path.splitext(file_path) if ext not in self.file_extensions: - file_path += f".{self.default_extension}" + file_path += self.default_extension else: file_path += ext self.filepathEdit.setText(file_path) @@ -121,7 +121,7 @@ def _browseForFilepath(self): dlg = QFileDialog(self, "Export Location", starting_dir, self.extension_description) - dlg.setDefaultSuffix(self.default_extension) + dlg.setDefaultSuffix(self.default_extension.lstrip(".")) dlg.setAcceptMode(QFileDialog.AcceptSave) if not dlg.exec_(): return @@ -152,7 +152,7 @@ def propagateDirty(self, *args): op = OpMock(graph=Graph()) app = QApplication([]) - w = HierarchicalFileExportOptionsWidget(None, (".h5"), "h5", "H5 Files (*.h5)") + w = HierarchicalFileExportOptionsWidget(None, (".h5",), "H5 Files (*.h5)") w.initSlots(op.Filepath, op.DatasetName, op.FullPath) w.show() app.exec_() diff --git a/volumina/widgets/multiformatSlotExportFileOptionsWidget.py b/volumina/widgets/multiformatSlotExportFileOptionsWidget.py index 8d3d58765..af2b938bb 100644 --- a/volumina/widgets/multiformatSlotExportFileOptionsWidget.py +++ b/volumina/widgets/multiformatSlotExportFileOptionsWidget.py @@ -72,9 +72,7 @@ def initExportOp(self, opDataExport): # HDF5 for fmt in ("compressed hdf5", "hdf5"): - hdf5OptionsWidget = HierarchicalFileExportOptionsWidget( - self, (".h5", ".hdf5"), "h5", "HDF5 files (*.h5 *.hdf5)" - ) + hdf5OptionsWidget = HierarchicalFileExportOptionsWidget(self, (".h5", ".hdf5"), "HDF5 files (*.h5 *.hdf5)") hdf5OptionsWidget.initSlots( opDataExport.OutputFilenameFormat, opDataExport.OutputInternalPath, opDataExport.ExportPath ) @@ -83,7 +81,7 @@ def initExportOp(self, opDataExport): # N5 for fmt in ("compressed n5", "n5"): - n5OptionsWidget = HierarchicalFileExportOptionsWidget(self, (".n5",), "n5", "N5 files (*.n5)") + n5OptionsWidget = HierarchicalFileExportOptionsWidget(self, (".n5",), "N5 files (*.n5)") n5OptionsWidget.initSlots( opDataExport.OutputFilenameFormat, opDataExport.OutputInternalPath, opDataExport.ExportPath ) @@ -91,7 +89,7 @@ def initExportOp(self, opDataExport): self._format_option_editors[fmt] = n5OptionsWidget # Zarr - zarrOptionsWidget = HierarchicalFileExportOptionsWidget(self, (".zarr",), "zarr", "Zarr files (*.zarr)") + zarrOptionsWidget = HierarchicalFileExportOptionsWidget(self, (".zarr",), "Zarr files (*.zarr)") zarrOptionsWidget.initSlots( opDataExport.OutputFilenameFormat, opDataExport.OutputInternalPath, opDataExport.ExportPath ) From 52929237376b27db580c092cd2d84b4946b57ce8 Mon Sep 17 00:00:00 2001 From: Benedikt Best <63287233+btbest@users.noreply.github.com> Date: Wed, 2 Oct 2024 16:50:57 +0200 Subject: [PATCH 8/8] OME-Zarr: Hide datasetName (internal path) widget --- volumina/widgets/hierarchicalFileExportOptionsWidget.py | 9 +++++++-- volumina/widgets/hierarchicalFileExportOptionsWidget.ui | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/volumina/widgets/hierarchicalFileExportOptionsWidget.py b/volumina/widgets/hierarchicalFileExportOptionsWidget.py index b860ef6d9..b7fb5846c 100644 --- a/volumina/widgets/hierarchicalFileExportOptionsWidget.py +++ b/volumina/widgets/hierarchicalFileExportOptionsWidget.py @@ -42,8 +42,13 @@ def __init__(self, parent, file_extensions: Tuple[str, ...], extension_descripti # We need to watch the textEdited signal because Qt has a bug that causes the OK button # to receive it's click event BEFORE the LineEdit receives its FocusOut event. # (That is, we can't just watch for FocusOut events and disable the button before the click.) - self.datasetEdit.textEdited.connect(lambda: self._handleTextEdited(self.datasetEdit)) self.filepathEdit.textEdited.connect(lambda: self._handleTextEdited(self.filepathEdit)) + if self.default_extension == ".zarr": + self.datasetLabel.setVisible(False) + self.datasetEdit.setVisible(False) + self.datasetEdit.setEnabled(False) + else: + self.datasetEdit.textEdited.connect(lambda: self._handleTextEdited(self.datasetEdit)) def initSlots(self, filepathSlot, datasetNameSlot, fullPathOutputSlot): self._filepathSlot = filepathSlot @@ -74,7 +79,7 @@ def _applyDataset(self): was_valid = self.settings_are_valid datasetName = self.datasetEdit.text() self._datasetNameSlot.setValue(str(datasetName)) - self.settings_are_valid = str(datasetName) != "" or self.default_extension == ".zarr" + self.settings_are_valid = str(datasetName) != "" if self.settings_are_valid != was_valid: self.pathValidityChange.emit(self.settings_are_valid) diff --git a/volumina/widgets/hierarchicalFileExportOptionsWidget.ui b/volumina/widgets/hierarchicalFileExportOptionsWidget.ui index 561d5b1de..eee8c5276 100644 --- a/volumina/widgets/hierarchicalFileExportOptionsWidget.ui +++ b/volumina/widgets/hierarchicalFileExportOptionsWidget.ui @@ -31,7 +31,7 @@ - + Dataset: