From cebdc9244c019224846cb8d2668080fe386a6adc Mon Sep 17 00:00:00 2001 From: Alexandre Marie Date: Mon, 17 Dec 2018 12:28:24 +0100 Subject: New upstream version 0.9.0+dfsg --- silx/app/view/About.py | 44 ++++++++--- silx/app/view/CustomNxdataWidget.py | 8 +- silx/app/view/DataPanel.py | 35 +++++++-- silx/app/view/Viewer.py | 149 +++++++++++++++++++++++++++++++++++- silx/app/view/test/test_view.py | 2 +- 5 files changed, 214 insertions(+), 24 deletions(-) (limited to 'silx/app/view') diff --git a/silx/app/view/About.py b/silx/app/view/About.py index 07306ef..4b804f2 100644 --- a/silx/app/view/About.py +++ b/silx/app/view/About.py @@ -25,7 +25,7 @@ __authors__ = ["V. Valls"] __license__ = "MIT" -__date__ = "05/06/2018" +__date__ = "05/07/2018" import sys @@ -147,6 +147,15 @@ class About(qt.QDialog): template = '%s is not loaded' return template % name + @staticmethod + def __formatOptionalFilters(name, isAvailable): + """Utils to format availability of features""" + if isAvailable: + template = '%s is available' + else: + template = '%s is not available' + return template % name + def __updateText(self): """Update the content of the dialog according to the settings.""" import silx._version @@ -174,14 +183,29 @@ class About(qt.QDialog):

""" - hdf5pluginLoaded = "hdf5plugin" in sys.modules - fabioLoaded = "fabio" in sys.modules - h5pyLoaded = "h5py" in sys.modules - - optional_lib = [] - optional_lib.append(self.__formatOptionalLibraries("FabIO", fabioLoaded)) - optional_lib.append(self.__formatOptionalLibraries("H5py", h5pyLoaded)) - optional_lib.append(self.__formatOptionalLibraries("hdf5plugin", hdf5pluginLoaded)) + optionals = [] + optionals.append(self.__formatOptionalLibraries("H5py", "h5py" in sys.modules)) + optionals.append(self.__formatOptionalLibraries("FabIO", "fabio" in sys.modules)) + + try: + import h5py.version + if h5py.version.hdf5_version_tuple >= (1, 10, 2): + # Previous versions only return True if the filter was first used + # to decode a dataset + import h5py.h5z + FILTER_LZ4 = 32004 + FILTER_BITSHUFFLE = 32008 + filters = [ + ("HDF5 LZ4 filter", FILTER_LZ4), + ("HDF5 Bitshuffle filter", FILTER_BITSHUFFLE), + ] + for name, filterId in filters: + isAvailable = h5py.h5z.filter_avail(filterId) + optionals.append(self.__formatOptionalFilters(name, isAvailable)) + else: + optionals.append(self.__formatOptionalLibraries("hdf5plugin", "hdf5plugin" in sys.modules)) + except ImportError: + pass # Access to the logo in SVG or PNG logo = icons.getQFile("../logo/silx") @@ -194,7 +218,7 @@ class About(qt.QDialog): qt_binding=qt.BINDING, qt_version=qt.qVersion(), python_version=sys.version.replace("\n", "
"), - optional_lib="
".join(optional_lib), + optional_lib="
".join(optionals), silx_image_path=logo.fileName() ) diff --git a/silx/app/view/CustomNxdataWidget.py b/silx/app/view/CustomNxdataWidget.py index 02ae6c0..72c9940 100644 --- a/silx/app/view/CustomNxdataWidget.py +++ b/silx/app/view/CustomNxdataWidget.py @@ -944,10 +944,10 @@ class CustomNxdataWidget(qt.QTreeView): if edited: item.setAxesDatasets(datasets) - dataset = item.getSignalDataset() - newDataset = self.__replaceDatasetRoot(dataset, removedRoot, loadedRoot) - if dataset is not newDataset: - item.setSignalDataset(newDataset) + dataset = item.getSignalDataset() + newDataset = self.__replaceDatasetRoot(dataset, removedRoot, loadedRoot) + if dataset is not newDataset: + item.setSignalDataset(newDataset) def __replaceDatasetRoot(self, dataset, fromRoot, toRoot): """ diff --git a/silx/app/view/DataPanel.py b/silx/app/view/DataPanel.py index 0653f74..5d87381 100644 --- a/silx/app/view/DataPanel.py +++ b/silx/app/view/DataPanel.py @@ -25,9 +25,10 @@ __authors__ = ["V. Valls"] __license__ = "MIT" -__date__ = "06/06/2018" +__date__ = "12/10/2018" import logging +import os.path from silx.gui import qt from silx.gui.data.DataViewerFrame import DataViewerFrame @@ -45,6 +46,26 @@ class _HeaderLabel(qt.QLabel): def sizeHint(self): return qt.QSize(10, 30) + def minimumSizeHint(self): + return qt.QSize(10, 30) + + def setData(self, filename, path): + if filename == "" and path == "": + text = "" + elif filename == "": + text = path + else: + text = "%s::%s" % (filename, path) + self.setText(text) + tooltip = "" + template = "
  • %s: %s
  • " + tooltip += template % ("Directory", os.path.dirname(filename)) + tooltip += template % ("File name", os.path.basename(filename)) + tooltip += template % ("Data path", path) + tooltip = "" % tooltip + tooltip = "%s" % tooltip + self.setToolTip(tooltip) + def paintEvent(self, event): painter = qt.QPainter(self) @@ -101,14 +122,14 @@ class DataPanel(qt.QWidget): self.__dataTitle.setVisible(True) if hasattr(data, "name"): if hasattr(data, "file"): - label = str(data.file.filename) - label += "::" + filename = str(data.file.filename) else: - label = "" - label += data.name + filename = "" + path = data.name else: - label = "" - self.__dataTitle.setText(label) + filename = "" + path = "" + self.__dataTitle.setData(filename, path) def setCustomDataItem(self, item): self.__customNxdataItem = item diff --git a/silx/app/view/Viewer.py b/silx/app/view/Viewer.py index 8f5db60..88ff989 100644 --- a/silx/app/view/Viewer.py +++ b/silx/app/view/Viewer.py @@ -25,7 +25,7 @@ __authors__ = ["V. Valls"] __license__ = "MIT" -__date__ = "25/06/2018" +__date__ = "08/10/2018" import os @@ -145,6 +145,18 @@ class Viewer(qt.QMainWindow): toolbar.setIconSize(qt.QSize(16, 16)) toolbar.setStyleSheet("QToolBar { border: 0px }") + action = qt.QAction(toolbar) + action.setIcon(icons.getQIcon("view-refresh")) + action.setText("Refresh") + action.setToolTip("Refresh all selected items") + action.triggered.connect(self.__refreshSelected) + action.setShortcut(qt.QKeySequence(qt.Qt.ControlModifier + qt.Qt.Key_Plus)) + toolbar.addAction(action) + treeView.addAction(action) + self.__refreshAction = action + + toolbar.addSeparator() + action = qt.QAction(toolbar) action.setIcon(icons.getQIcon("tree-expand-all")) action.setText("Expand all") @@ -173,6 +185,135 @@ class Viewer(qt.QMainWindow): layout.addWidget(treeView) return widget + def __refreshSelected(self): + """Refresh all selected items + """ + qt.QApplication.setOverrideCursor(qt.Qt.WaitCursor) + + selection = self.__treeview.selectionModel() + indexes = selection.selectedIndexes() + selectedItems = [] + model = self.__treeview.model() + h5files = set([]) + while len(indexes) > 0: + index = indexes.pop(0) + if index.column() != 0: + continue + h5 = model.data(index, role=silx.gui.hdf5.Hdf5TreeModel.H5PY_OBJECT_ROLE) + rootIndex = index + # Reach the root of the tree + while rootIndex.parent().isValid(): + rootIndex = rootIndex.parent() + rootRow = rootIndex.row() + relativePath = self.__getRelativePath(model, rootIndex, index) + selectedItems.append((rootRow, relativePath)) + h5files.add(h5.file) + + if len(h5files) == 0: + qt.QApplication.restoreOverrideCursor() + return + + model = self.__treeview.findHdf5TreeModel() + for h5 in h5files: + self.__synchronizeH5pyObject(h5) + + model = self.__treeview.model() + itemSelection = qt.QItemSelection() + for rootRow, relativePath in selectedItems: + rootIndex = model.index(rootRow, 0, qt.QModelIndex()) + index = self.__indexFromPath(model, rootIndex, relativePath) + if index is None: + continue + indexEnd = model.index(index.row(), model.columnCount() - 1, index.parent()) + itemSelection.select(index, indexEnd) + selection.select(itemSelection, qt.QItemSelectionModel.ClearAndSelect) + + qt.QApplication.restoreOverrideCursor() + + def __synchronizeH5pyObject(self, h5): + model = self.__treeview.findHdf5TreeModel() + # This is buggy right now while h5py do not allow to close a file + # while references are still used. + # FIXME: The architecture have to be reworked to support this feature. + # model.synchronizeH5pyObject(h5) + + filename = h5.filename + row = model.h5pyObjectRow(h5) + index = self.__treeview.model().index(row, 0, qt.QModelIndex()) + paths = self.__getPathFromExpandedNodes(self.__treeview, index) + model.removeH5pyObject(h5) + model.insertFile(filename, row) + index = self.__treeview.model().index(row, 0, qt.QModelIndex()) + self.__expandNodesFromPaths(self.__treeview, index, paths) + + def __getRelativePath(self, model, rootIndex, index): + """Returns a relative path from an index to his rootIndex. + + If the path is empty the index is also the rootIndex. + """ + path = "" + while index.isValid(): + if index == rootIndex: + return path + name = model.data(index) + if path == "": + path = name + else: + path = name + "/" + path + index = index.parent() + + # index is not a children of rootIndex + raise ValueError("index is not a children of the rootIndex") + + def __getPathFromExpandedNodes(self, view, rootIndex): + """Return relative path from the root index of the extended nodes""" + model = view.model() + rootPath = None + paths = [] + indexes = [rootIndex] + while len(indexes): + index = indexes.pop(0) + if not view.isExpanded(index): + continue + + node = model.data(index, role=silx.gui.hdf5.Hdf5TreeModel.H5PY_ITEM_ROLE) + path = node._getCanonicalName() + if rootPath is None: + rootPath = path + path = path[len(rootPath):] + paths.append(path) + + for child in range(model.rowCount(index)): + childIndex = model.index(child, 0, index) + indexes.append(childIndex) + return paths + + def __indexFromPath(self, model, rootIndex, path): + elements = path.split("/") + if elements[0] == "": + elements.pop(0) + index = rootIndex + while len(elements) != 0: + element = elements.pop(0) + found = False + for child in range(model.rowCount(index)): + childIndex = model.index(child, 0, index) + name = model.data(childIndex) + if element == name: + index = childIndex + found = True + break + if not found: + return None + return index + + def __expandNodesFromPaths(self, view, rootIndex, paths): + model = view.model() + for path in paths: + index = self.__indexFromPath(model, rootIndex, path) + if index is not None: + view.setExpanded(index, True) + def __expandAllSelected(self): """Expand all selected items of the tree. @@ -185,6 +326,8 @@ class Viewer(qt.QMainWindow): model = self.__treeview.model() while len(indexes) > 0: index = indexes.pop(0) + if index.column() != 0: + continue if isinstance(index, tuple): index, depth = index else: @@ -211,6 +354,8 @@ class Viewer(qt.QMainWindow): model = self.__treeview.model() while len(indexes) > 0: index = indexes.pop(0) + if index.column() != 0: + continue if isinstance(index, tuple): index, depth = index else: @@ -682,5 +827,5 @@ class Viewer(qt.QMainWindow): action.triggered.connect(lambda: self.__treeview.findHdf5TreeModel().removeH5pyObject(h5)) menu.addAction(action) action = qt.QAction("Synchronize %s" % obj.local_filename, event.source()) - action.triggered.connect(lambda: self.__treeview.findHdf5TreeModel().synchronizeH5pyObject(h5)) + action.triggered.connect(lambda: self.__synchronizeH5pyObject(h5)) menu.addAction(action) diff --git a/silx/app/view/test/test_view.py b/silx/app/view/test/test_view.py index 010cda5..ebcd405 100644 --- a/silx/app/view/test/test_view.py +++ b/silx/app/view/test/test_view.py @@ -46,7 +46,7 @@ from silx.app.view.About import About from silx.app.view.DataPanel import DataPanel from silx.app.view.CustomNxdataWidget import CustomNxdataWidget from silx.gui.hdf5._utils import Hdf5DatasetMimeData -from silx.gui.test.utils import TestCaseQt +from silx.gui.utils.testutils import TestCaseQt from silx.io import commonh5 _tmpDirectory = None -- cgit v1.2.3