Skip to content

Commit 3883080

Browse files
committed
Update HDF5 browser: improved tree view layout, multiple file support
1 parent 2f91273 commit 3883080

File tree

13 files changed

+833
-477
lines changed

13 files changed

+833
-477
lines changed

.vscode/launch.json

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,15 @@
1313
"envFile": "${workspaceFolder}/.env",
1414
"python": "${config:python.defaultInterpreterPath}",
1515
"justMyCode": false,
16-
// "args": [
17-
// "${workspaceFolder}/cdl/data/tests/reordering_test.h5",
18-
// ],
16+
"args": [
17+
// "--h5browser",
18+
// "${workspaceFolder}/cdl/data/tests/empty.h5"
19+
// "${workspaceFolder}/cdl/data/tests/reordering_test.h5",
20+
// "${workspaceFolder}/cdl/data/tests/reordering_test.h5,/DataLab_Sig/g001: /s003: wiener(s002)/xydata",
21+
],
1922
"env": {
2023
// "DEBUG": "1",
21-
// "LANG": "en",
24+
"LANG": "en",
2225
"QT_COLOR_MODE": "light",
2326
}
2427
},
@@ -59,8 +62,8 @@
5962
"env": {
6063
// "DEBUG": "1",
6164
// "TEST_SEGFAULT_ERROR": "1",
62-
// "LANG": "en",
63-
// "QT_COLOR_MODE": "light",
65+
"LANG": "en",
66+
"QT_COLOR_MODE": "light",
6467
}
6568
},
6669
{
@@ -80,6 +83,8 @@
8083
],
8184
"env": {
8285
// "DEBUG": "1",
86+
"LANG": "en",
87+
"QT_COLOR_MODE": "light",
8388
}
8489
},
8590
{

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,13 @@ for future and past milestones.
1414
* Editable parameters: number of bins, lower and upper bounds
1515
* HDF5 browser:
1616
* Improved tree view layout (more compact and readable)
17+
* Multiple files can now be opened at once, using the file selection dialog box
1718
* Added tabs with information below the graphical preview:
1819
* Group info: path, textual preview, etc.
1920
* Attributes info: name, value
2021
* Added "Show only supported data" check box: when checked, only supported data
2122
(signals and images) are shown in the tree view
23+
* Added "Show values" check box, to show/hide the values in the tree view
2224
* Macro Panel:
2325
* Macro commands are now numbered, starting from 1, like signals and images
2426
* Remote control API (`RemoteProxy` and `LocalProxy`):

cdl/core/gui/h5io.py

Lines changed: 37 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -70,11 +70,15 @@ def open_file(self, filename: str, import_all: bool, reset_all: bool) -> None:
7070
# KeyError was encoutered when deserializing datasets (DataLab data
7171
# model is not compatible with this version)
7272
progress.close()
73-
self.import_file(filename, import_all, reset_all)
73+
self.import_files([filename], import_all, reset_all)
7474

7575
def __add_object_from_node(self, node: BaseNode) -> None:
7676
"""Add DataLab object from h5 node"""
7777
obj = node.get_native_object()
78+
if obj is None:
79+
# TODO: Add a warning message to be shown after all imports?
80+
# (e.g. "No supported data available in HDF5 file(s)."
81+
return
7882
self.uint32_wng = self.uint32_wng or node.uint32_wng
7983
if isinstance(obj, SignalObj):
8084
self.mainwindow.signalpanel.add_object(obj)
@@ -88,39 +92,46 @@ def __eventually_show_warnings(self) -> None:
8892
self.mainwindow, _("Warning"), _("Clipping uint32 data to int32.")
8993
)
9094

91-
def import_file(self, filename: str, import_all: bool, reset_all: bool) -> None:
92-
"""Import HDF5 file"""
95+
def import_files(
96+
self, filenames: list[str], import_all: bool, reset_all: bool
97+
) -> None:
98+
"""Import HDF5 files"""
9399
h5browser = H5BrowserDialog(self.mainwindow)
94-
95-
with qt_try_loadsave_file(self.mainwindow, filename, "load"):
96-
h5browser.setup(filename)
97-
if execenv.unattended:
98-
# Unattended mode: import all datasets (for testing)
99-
import_all = True
100-
if not import_all and not exec_dialog(h5browser):
101-
h5browser.cleanup()
102-
return
103-
if import_all:
104-
nodes = h5browser.get_all_nodes()
105-
else:
106-
nodes = h5browser.get_nodes()
107-
if nodes is None:
108-
h5browser.cleanup()
109-
return
110-
if reset_all:
111-
self.mainwindow.reset_all()
112-
with create_progress_bar(
113-
self.mainwindow, self.__progbartitle(filename), len(nodes)
114-
) as progress:
100+
for filename in filenames:
101+
with qt_try_loadsave_file(self.mainwindow, filename, "load"):
102+
h5browser.open_file(filename)
103+
if h5browser.is_empty():
104+
if not execenv.unattended:
105+
QW.QMessageBox.warning(
106+
self.mainwindow,
107+
_("Warning"),
108+
_("No supported data available in HDF5 file(s)."),
109+
)
110+
return
111+
if execenv.unattended:
112+
# Unattended mode: import all datasets (for testing)
113+
import_all = True
114+
if not import_all and not exec_dialog(h5browser):
115+
return
116+
if import_all:
117+
nodes = h5browser.get_all_nodes()
118+
else:
119+
nodes = h5browser.get_nodes()
120+
if nodes is None:
121+
return
122+
if reset_all:
123+
self.mainwindow.reset_all()
124+
with qt_try_loadsave_file(self.mainwindow, "*.h5", "load"):
125+
with create_progress_bar(self.mainwindow, "", len(nodes)) as progress:
115126
self.uint32_wng = False
116127
for idx, node in enumerate(nodes):
128+
progress.setLabelText(self.__progbartitle(node.h5file.filename))
117129
progress.setValue(idx + 1)
118130
QW.QApplication.processEvents()
119131
if progress.wasCanceled():
120132
break
121133
self.__add_object_from_node(node)
122-
h5browser.cleanup()
123-
self.__eventually_show_warnings()
134+
self.__eventually_show_warnings()
124135

125136
def import_dataset_from_file(self, filename: str, dsetname: str) -> None:
126137
"""Import dataset from HDF5 file"""

cdl/core/gui/main.py

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -422,10 +422,10 @@ def add_label_with_title(
422422
def run_macro(self, number_or_title: int | str | None = None) -> None:
423423
"""Run macro.
424424
425-
Args:
426-
number: Number of the macro (starting at 1). Defaults to None (run
427-
current macro, or does nothing if there is no macro).
428-
"""
425+
Args:
426+
number: Number of the macro (starting at 1). Defaults to None (run
427+
current macro, or does nothing if there is no macro).
428+
"""
429429
self.macropanel.run_macro(number_or_title)
430430

431431
@remote_controlled
@@ -1327,11 +1327,19 @@ def open_h5_files(
13271327
basedir = Conf.main.base_dir.get()
13281328
with qth.save_restore_stds():
13291329
h5files, _fl = getopenfilenames(self, _("Open"), basedir, "HDF5 (*.h5)")
1330+
filenames, dsetnames = [], []
13301331
for fname_with_dset in h5files:
13311332
if "," in fname_with_dset:
13321333
filename, dsetname = fname_with_dset.split(",")
1334+
dsetnames.append(dsetname)
13331335
else:
1334-
filename, dsetname = fname_with_dset, None
1336+
filename = fname_with_dset
1337+
dsetnames.append(None)
1338+
filenames.append(filename)
1339+
if import_all is None and all([dsetname is None for dsetname in dsetnames]):
1340+
self.browse_h5_files(filenames, reset_all)
1341+
return
1342+
for filename, dsetname in zip(filenames, dsetnames):
13351343
if import_all is None and dsetname is None:
13361344
self.import_h5_file(filename, reset_all)
13371345
else:
@@ -1343,6 +1351,20 @@ def open_h5_files(
13431351
self.h5inputoutput.import_dataset_from_file(filename, dsetname)
13441352
reset_all = False
13451353

1354+
def browse_h5_files(self, filenames: list[str], reset_all: bool) -> None:
1355+
"""Browse HDF5 files
1356+
1357+
Args:
1358+
filenames (list): HDF5 filenames
1359+
reset_all (bool): Reset all application data before importing
1360+
1361+
Returns:
1362+
None
1363+
"""
1364+
for filename in filenames:
1365+
self.__check_h5file(filename, "load")
1366+
self.h5inputoutput.import_files(filenames, False, reset_all)
1367+
13461368
@remote_controlled
13471369
def import_h5_file(self, filename: str, reset_all: bool | None = None) -> None:
13481370
"""Import HDF5 file into DataLab
@@ -1357,7 +1379,7 @@ def import_h5_file(self, filename: str, reset_all: bool | None = None) -> None:
13571379
"""
13581380
with qth.qt_try_loadsave_file(self, filename, "load"):
13591381
filename = self.__check_h5file(filename, "load")
1360-
self.h5inputoutput.import_file(filename, False, reset_all)
1382+
self.h5inputoutput.import_files([filename], False, reset_all)
13611383

13621384
# This method is intentionally *not* remote controlled
13631385
# (see TODO regarding RemoteClient.add_object method)

cdl/core/io/h5/common.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ def __init__(self, filename):
147147
self.h5file = h5py.File(filename)
148148
self.__nodes = {}
149149
self.root = RootNode(self.h5file)
150-
self.__nodes[self.root.id] = self.root.dset
150+
self.__nodes[self.root.id] = self.root
151151
self.root.collect_children(self.__nodes)
152152
NODE_FACTORY.run_post_triggers(self)
153153

0 commit comments

Comments
 (0)