summaryrefslogtreecommitdiff
path: root/silx/app/view/Viewer.py
diff options
context:
space:
mode:
Diffstat (limited to 'silx/app/view/Viewer.py')
-rw-r--r--silx/app/view/Viewer.py686
1 files changed, 686 insertions, 0 deletions
diff --git a/silx/app/view/Viewer.py b/silx/app/view/Viewer.py
new file mode 100644
index 0000000..8f5db60
--- /dev/null
+++ b/silx/app/view/Viewer.py
@@ -0,0 +1,686 @@
+# coding: utf-8
+# /*##########################################################################
+# Copyright (C) 2016-2018 European Synchrotron Radiation Facility
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# ############################################################################*/
+"""Browse a data file with a GUI"""
+
+__authors__ = ["V. Valls"]
+__license__ = "MIT"
+__date__ = "25/06/2018"
+
+
+import os
+import collections
+import logging
+import functools
+
+import silx.io.nxdata
+from silx.gui import qt
+from silx.gui import icons
+import silx.gui.hdf5
+from .ApplicationContext import ApplicationContext
+from .CustomNxdataWidget import CustomNxdataWidget
+from .CustomNxdataWidget import CustomNxDataToolBar
+from . import utils
+from .DataPanel import DataPanel
+
+
+_logger = logging.getLogger(__name__)
+
+
+class Viewer(qt.QMainWindow):
+ """
+ This window allows to browse a data file like images or HDF5 and it's
+ content.
+ """
+
+ def __init__(self, parent=None, settings=None):
+ """
+ Constructor
+ """
+
+ qt.QMainWindow.__init__(self, parent)
+ self.setWindowTitle("Silx viewer")
+
+ self.__context = ApplicationContext(self, settings)
+ self.__context.restoreLibrarySettings()
+
+ self.__dialogState = None
+ self.__customNxDataItem = None
+ self.__treeview = silx.gui.hdf5.Hdf5TreeView(self)
+ self.__treeview.setExpandsOnDoubleClick(False)
+ """Silx HDF5 TreeView"""
+
+ rightPanel = qt.QSplitter(self)
+ rightPanel.setOrientation(qt.Qt.Vertical)
+ self.__splitter2 = rightPanel
+
+ self.__treeWindow = self.__createTreeWindow(self.__treeview)
+
+ # Custom the model to be able to manage the life cycle of the files
+ treeModel = silx.gui.hdf5.Hdf5TreeModel(self.__treeview, ownFiles=False)
+ treeModel.sigH5pyObjectLoaded.connect(self.__h5FileLoaded)
+ treeModel.sigH5pyObjectRemoved.connect(self.__h5FileRemoved)
+ treeModel.sigH5pyObjectSynchronized.connect(self.__h5FileSynchonized)
+ treeModel.setDatasetDragEnabled(True)
+ treeModel2 = silx.gui.hdf5.NexusSortFilterProxyModel(self.__treeview)
+ treeModel2.setSourceModel(treeModel)
+ treeModel2.sort(0, qt.Qt.AscendingOrder)
+ treeModel2.setSortCaseSensitivity(qt.Qt.CaseInsensitive)
+
+ self.__treeview.setModel(treeModel2)
+ rightPanel.addWidget(self.__treeWindow)
+
+ self.__customNxdata = CustomNxdataWidget(self)
+ self.__customNxdata.setSelectionBehavior(qt.QAbstractItemView.SelectRows)
+ # optimise the rendering
+ self.__customNxdata.setUniformRowHeights(True)
+ self.__customNxdata.setIconSize(qt.QSize(16, 16))
+ self.__customNxdata.setExpandsOnDoubleClick(False)
+
+ self.__customNxdataWindow = self.__createCustomNxdataWindow(self.__customNxdata)
+ self.__customNxdataWindow.setVisible(False)
+ rightPanel.addWidget(self.__customNxdataWindow)
+
+ rightPanel.setStretchFactor(1, 1)
+ rightPanel.setCollapsible(0, False)
+ rightPanel.setCollapsible(1, False)
+
+ self.__dataPanel = DataPanel(self, self.__context)
+
+ spliter = qt.QSplitter(self)
+ spliter.addWidget(rightPanel)
+ spliter.addWidget(self.__dataPanel)
+ spliter.setStretchFactor(1, 1)
+ self.__splitter = spliter
+
+ main_panel = qt.QWidget(self)
+ layout = qt.QVBoxLayout()
+ layout.addWidget(spliter)
+ layout.setStretchFactor(spliter, 1)
+ main_panel.setLayout(layout)
+
+ self.setCentralWidget(main_panel)
+
+ self.__treeview.activated.connect(self.displaySelectedData)
+ self.__customNxdata.activated.connect(self.displaySelectedCustomData)
+ self.__customNxdata.sigNxdataItemRemoved.connect(self.__customNxdataRemoved)
+ self.__customNxdata.sigNxdataItemUpdated.connect(self.__customNxdataUpdated)
+ self.__treeview.addContextMenuCallback(self.customContextMenu)
+
+ treeModel = self.__treeview.findHdf5TreeModel()
+ columns = list(treeModel.COLUMN_IDS)
+ columns.remove(treeModel.DESCRIPTION_COLUMN)
+ columns.remove(treeModel.NODE_COLUMN)
+ self.__treeview.header().setSections(columns)
+
+ self._iconUpward = icons.getQIcon('plot-yup')
+ self._iconDownward = icons.getQIcon('plot-ydown')
+
+ self.createActions()
+ self.createMenus()
+ self.__context.restoreSettings()
+
+ def __createTreeWindow(self, treeView):
+ toolbar = qt.QToolBar(self)
+ toolbar.setIconSize(qt.QSize(16, 16))
+ toolbar.setStyleSheet("QToolBar { border: 0px }")
+
+ action = qt.QAction(toolbar)
+ action.setIcon(icons.getQIcon("tree-expand-all"))
+ action.setText("Expand all")
+ action.setToolTip("Expand all selected items")
+ action.triggered.connect(self.__expandAllSelected)
+ action.setShortcut(qt.QKeySequence(qt.Qt.ControlModifier + qt.Qt.Key_Plus))
+ toolbar.addAction(action)
+ treeView.addAction(action)
+ self.__expandAllAction = action
+
+ action = qt.QAction(toolbar)
+ action.setIcon(icons.getQIcon("tree-collapse-all"))
+ action.setText("Collapse all")
+ action.setToolTip("Collapse all selected items")
+ action.triggered.connect(self.__collapseAllSelected)
+ action.setShortcut(qt.QKeySequence(qt.Qt.ControlModifier + qt.Qt.Key_Minus))
+ toolbar.addAction(action)
+ treeView.addAction(action)
+ self.__collapseAllAction = action
+
+ widget = qt.QWidget(self)
+ layout = qt.QVBoxLayout(widget)
+ layout.setContentsMargins(0, 0, 0, 0)
+ layout.setSpacing(0)
+ layout.addWidget(toolbar)
+ layout.addWidget(treeView)
+ return widget
+
+ def __expandAllSelected(self):
+ """Expand all selected items of the tree.
+
+ The depth is fixed to avoid infinite loop with recurssive links.
+ """
+ qt.QApplication.setOverrideCursor(qt.Qt.WaitCursor)
+
+ selection = self.__treeview.selectionModel()
+ indexes = selection.selectedIndexes()
+ model = self.__treeview.model()
+ while len(indexes) > 0:
+ index = indexes.pop(0)
+ if isinstance(index, tuple):
+ index, depth = index
+ else:
+ depth = 0
+
+ if depth > 10:
+ # Avoid infinite loop with recursive links
+ break
+
+ if model.hasChildren(index):
+ self.__treeview.setExpanded(index, True)
+ for row in range(model.rowCount(index)):
+ childIndex = model.index(row, 0, index)
+ indexes.append((childIndex, depth + 1))
+ qt.QApplication.restoreOverrideCursor()
+
+ def __collapseAllSelected(self):
+ """Collapse all selected items of the tree.
+
+ The depth is fixed to avoid infinite loop with recurssive links.
+ """
+ selection = self.__treeview.selectionModel()
+ indexes = selection.selectedIndexes()
+ model = self.__treeview.model()
+ while len(indexes) > 0:
+ index = indexes.pop(0)
+ if isinstance(index, tuple):
+ index, depth = index
+ else:
+ depth = 0
+
+ if depth > 10:
+ # Avoid infinite loop with recursive links
+ break
+
+ if model.hasChildren(index):
+ self.__treeview.setExpanded(index, False)
+ for row in range(model.rowCount(index)):
+ childIndex = model.index(row, 0, index)
+ indexes.append((childIndex, depth + 1))
+
+ def __createCustomNxdataWindow(self, customNxdataWidget):
+ toolbar = CustomNxDataToolBar(self)
+ toolbar.setCustomNxDataWidget(customNxdataWidget)
+ toolbar.setIconSize(qt.QSize(16, 16))
+ toolbar.setStyleSheet("QToolBar { border: 0px }")
+
+ widget = qt.QWidget(self)
+ layout = qt.QVBoxLayout(widget)
+ layout.setContentsMargins(0, 0, 0, 0)
+ layout.setSpacing(0)
+ layout.addWidget(toolbar)
+ layout.addWidget(customNxdataWidget)
+ return widget
+
+ def __h5FileLoaded(self, loadedH5):
+ self.__context.pushRecentFile(loadedH5.file.filename)
+
+ def __h5FileRemoved(self, removedH5):
+ self.__dataPanel.removeDatasetsFrom(removedH5)
+ self.__customNxdata.removeDatasetsFrom(removedH5)
+ removedH5.close()
+
+ def __h5FileSynchonized(self, removedH5, loadedH5):
+ self.__dataPanel.replaceDatasetsFrom(removedH5, loadedH5)
+ self.__customNxdata.replaceDatasetsFrom(removedH5, loadedH5)
+ removedH5.close()
+
+ def closeEvent(self, event):
+ self.__context.saveSettings()
+
+ # Clean up as much as possible Python objects
+ model = self.__customNxdata.model()
+ model.clear()
+ model = self.__treeview.findHdf5TreeModel()
+ model.clear()
+
+ def saveSettings(self, settings):
+ """Save the window settings to this settings object
+
+ :param qt.QSettings settings: Initialized settings
+ """
+ isFullScreen = bool(self.windowState() & qt.Qt.WindowFullScreen)
+ if isFullScreen:
+ # show in normal to catch the normal geometry
+ self.showNormal()
+
+ settings.beginGroup("mainwindow")
+ settings.setValue("size", self.size())
+ settings.setValue("pos", self.pos())
+ settings.setValue("full-screen", isFullScreen)
+ settings.endGroup()
+
+ settings.beginGroup("mainlayout")
+ settings.setValue("spliter", self.__splitter.sizes())
+ settings.setValue("spliter2", self.__splitter2.sizes())
+ isVisible = self.__customNxdataWindow.isVisible()
+ settings.setValue("custom-nxdata-window-visible", isVisible)
+ settings.endGroup()
+
+ if isFullScreen:
+ self.showFullScreen()
+
+ def restoreSettings(self, settings):
+ """Restore the window settings using this settings object
+
+ :param qt.QSettings settings: Initialized settings
+ """
+ settings.beginGroup("mainwindow")
+ size = settings.value("size", qt.QSize(640, 480))
+ pos = settings.value("pos", qt.QPoint())
+ isFullScreen = settings.value("full-screen", False)
+ try:
+ if not isinstance(isFullScreen, bool):
+ isFullScreen = utils.stringToBool(isFullScreen)
+ except ValueError:
+ isFullScreen = False
+ settings.endGroup()
+
+ settings.beginGroup("mainlayout")
+ try:
+ data = settings.value("spliter")
+ data = [int(d) for d in data]
+ self.__splitter.setSizes(data)
+ except Exception:
+ _logger.debug("Backtrace", exc_info=True)
+ try:
+ data = settings.value("spliter2")
+ data = [int(d) for d in data]
+ self.__splitter2.setSizes(data)
+ except Exception:
+ _logger.debug("Backtrace", exc_info=True)
+ isVisible = settings.value("custom-nxdata-window-visible", False)
+ try:
+ if not isinstance(isVisible, bool):
+ isVisible = utils.stringToBool(isVisible)
+ except ValueError:
+ isVisible = False
+ self.__customNxdataWindow.setVisible(isVisible)
+ self._displayCustomNxdataWindow.setChecked(isVisible)
+
+ settings.endGroup()
+
+ if not pos.isNull():
+ self.move(pos)
+ if not size.isNull():
+ self.resize(size)
+ if isFullScreen:
+ self.showFullScreen()
+
+ def createActions(self):
+ action = qt.QAction("E&xit", self)
+ action.setShortcuts(qt.QKeySequence.Quit)
+ action.setStatusTip("Exit the application")
+ action.triggered.connect(self.close)
+ self._exitAction = action
+
+ action = qt.QAction("&Open...", self)
+ action.setStatusTip("Open a file")
+ action.triggered.connect(self.open)
+ self._openAction = action
+
+ action = qt.QAction("Open Recent", self)
+ action.setStatusTip("Open a recently openned file")
+ action.triggered.connect(self.open)
+ self._openRecentAction = action
+
+ action = qt.QAction("&About", self)
+ action.setStatusTip("Show the application's About box")
+ action.triggered.connect(self.about)
+ self._aboutAction = action
+
+ # Plot backend
+
+ action = qt.QAction("Plot rendering backend", self)
+ action.setStatusTip("Select plot rendering backend")
+ self._plotBackendSelection = action
+
+ menu = qt.QMenu()
+ action.setMenu(menu)
+ group = qt.QActionGroup(self)
+ group.setExclusive(True)
+
+ action = qt.QAction("matplotlib", self)
+ action.setStatusTip("Plot will be rendered using matplotlib")
+ action.setCheckable(True)
+ action.triggered.connect(self.__forceMatplotlibBackend)
+ group.addAction(action)
+ menu.addAction(action)
+ self._usePlotWithMatplotlib = action
+
+ action = qt.QAction("OpenGL", self)
+ action.setStatusTip("Plot will be rendered using OpenGL")
+ action.setCheckable(True)
+ action.triggered.connect(self.__forceOpenglBackend)
+ group.addAction(action)
+ menu.addAction(action)
+ self._usePlotWithOpengl = action
+
+ # Plot image orientation
+
+ action = qt.QAction("Default plot image y-axis orientation", self)
+ action.setStatusTip("Select the default y-axis orientation used by plot displaying images")
+ self._plotImageOrientation = action
+
+ menu = qt.QMenu()
+ action.setMenu(menu)
+ group = qt.QActionGroup(self)
+ group.setExclusive(True)
+
+ action = qt.QAction("Downward, origin on top", self)
+ action.setIcon(self._iconDownward)
+ action.setStatusTip("Plot images will use a downward Y-axis orientation")
+ action.setCheckable(True)
+ action.triggered.connect(self.__forcePlotImageDownward)
+ group.addAction(action)
+ menu.addAction(action)
+ self._useYAxisOrientationDownward = action
+
+ action = qt.QAction("Upward, origin on bottom", self)
+ action.setIcon(self._iconUpward)
+ action.setStatusTip("Plot images will use a upward Y-axis orientation")
+ action.setCheckable(True)
+ action.triggered.connect(self.__forcePlotImageUpward)
+ group.addAction(action)
+ menu.addAction(action)
+ self._useYAxisOrientationUpward = action
+
+ # Windows
+
+ action = qt.QAction("Show custom NXdata selector", self)
+ action.setStatusTip("Show a widget which allow to create plot by selecting data and axes")
+ action.setCheckable(True)
+ action.setShortcut(qt.QKeySequence(qt.Qt.Key_F5))
+ action.toggled.connect(self.__toggleCustomNxdataWindow)
+ self._displayCustomNxdataWindow = action
+
+ def __toggleCustomNxdataWindow(self):
+ isVisible = self._displayCustomNxdataWindow.isChecked()
+ self.__customNxdataWindow.setVisible(isVisible)
+
+ def __updateFileMenu(self):
+ files = self.__context.getRecentFiles()
+ self._openRecentAction.setEnabled(len(files) != 0)
+ menu = None
+ if len(files) != 0:
+ menu = qt.QMenu()
+ for filePath in files:
+ baseName = os.path.basename(filePath)
+ action = qt.QAction(baseName, self)
+ action.setToolTip(filePath)
+ action.triggered.connect(functools.partial(self.__openRecentFile, filePath))
+ menu.addAction(action)
+ menu.addSeparator()
+ baseName = os.path.basename(filePath)
+ action = qt.QAction("Clear history", self)
+ action.setToolTip("Clear the history of the recent files")
+ action.triggered.connect(self.__clearRecentFile)
+ menu.addAction(action)
+ self._openRecentAction.setMenu(menu)
+
+ def __clearRecentFile(self):
+ self.__context.clearRencentFiles()
+
+ def __openRecentFile(self, filePath):
+ self.appendFile(filePath)
+
+ def __updateOptionMenu(self):
+ """Update the state of the checked options as it is based on global
+ environment values."""
+
+ # plot backend
+
+ action = self._plotBackendSelection
+ title = action.text().split(": ", 1)[0]
+ action.setText("%s: %s" % (title, silx.config.DEFAULT_PLOT_BACKEND))
+
+ action = self._usePlotWithMatplotlib
+ action.setChecked(silx.config.DEFAULT_PLOT_BACKEND in ["matplotlib", "mpl"])
+ title = action.text().split(" (", 1)[0]
+ if not action.isChecked():
+ title += " (applied after application restart)"
+ action.setText(title)
+
+ action = self._usePlotWithOpengl
+ action.setChecked(silx.config.DEFAULT_PLOT_BACKEND in ["opengl", "gl"])
+ title = action.text().split(" (", 1)[0]
+ if not action.isChecked():
+ title += " (applied after application restart)"
+ action.setText(title)
+
+ # plot orientation
+
+ action = self._plotImageOrientation
+ if silx.config.DEFAULT_PLOT_IMAGE_Y_AXIS_ORIENTATION == "downward":
+ action.setIcon(self._iconDownward)
+ else:
+ action.setIcon(self._iconUpward)
+ action.setIconVisibleInMenu(True)
+
+ action = self._useYAxisOrientationDownward
+ action.setChecked(silx.config.DEFAULT_PLOT_IMAGE_Y_AXIS_ORIENTATION == "downward")
+ title = action.text().split(" (", 1)[0]
+ if not action.isChecked():
+ title += " (applied after application restart)"
+ action.setText(title)
+
+ action = self._useYAxisOrientationUpward
+ action.setChecked(silx.config.DEFAULT_PLOT_IMAGE_Y_AXIS_ORIENTATION != "downward")
+ title = action.text().split(" (", 1)[0]
+ if not action.isChecked():
+ title += " (applied after application restart)"
+ action.setText(title)
+
+ def createMenus(self):
+ fileMenu = self.menuBar().addMenu("&File")
+ fileMenu.addAction(self._openAction)
+ fileMenu.addAction(self._openRecentAction)
+ fileMenu.addSeparator()
+ fileMenu.addAction(self._exitAction)
+ fileMenu.aboutToShow.connect(self.__updateFileMenu)
+
+ optionMenu = self.menuBar().addMenu("&Options")
+ optionMenu.addAction(self._plotImageOrientation)
+ optionMenu.addAction(self._plotBackendSelection)
+ optionMenu.aboutToShow.connect(self.__updateOptionMenu)
+
+ viewMenu = self.menuBar().addMenu("&Views")
+ viewMenu.addAction(self._displayCustomNxdataWindow)
+
+ helpMenu = self.menuBar().addMenu("&Help")
+ helpMenu.addAction(self._aboutAction)
+
+ def open(self):
+ dialog = self.createFileDialog()
+ if self.__dialogState is None:
+ currentDirectory = os.getcwd()
+ dialog.setDirectory(currentDirectory)
+ else:
+ dialog.restoreState(self.__dialogState)
+
+ result = dialog.exec_()
+ if not result:
+ return
+
+ self.__dialogState = dialog.saveState()
+
+ filenames = dialog.selectedFiles()
+ for filename in filenames:
+ self.appendFile(filename)
+
+ def createFileDialog(self):
+ dialog = qt.QFileDialog(self)
+ dialog.setWindowTitle("Open")
+ dialog.setModal(True)
+
+ # NOTE: hdf5plugin have to be loaded before
+ extensions = collections.OrderedDict()
+ for description, ext in silx.io.supported_extensions().items():
+ extensions[description] = " ".join(sorted(list(ext)))
+
+ try:
+ # NOTE: hdf5plugin have to be loaded before
+ import fabio
+ except Exception:
+ _logger.debug("Backtrace while loading fabio", exc_info=True)
+ fabio = None
+
+ if fabio is not None:
+ extensions["NeXus layout from EDF files"] = "*.edf"
+ extensions["NeXus layout from TIFF image files"] = "*.tif *.tiff"
+ extensions["NeXus layout from CBF files"] = "*.cbf"
+ extensions["NeXus layout from MarCCD image files"] = "*.mccd"
+
+ all_supported_extensions = set()
+ for name, exts in extensions.items():
+ exts = exts.split(" ")
+ all_supported_extensions.update(exts)
+ all_supported_extensions = sorted(list(all_supported_extensions))
+
+ filters = []
+ filters.append("All supported files (%s)" % " ".join(all_supported_extensions))
+ for name, extension in extensions.items():
+ filters.append("%s (%s)" % (name, extension))
+ filters.append("All files (*)")
+
+ dialog.setNameFilters(filters)
+ dialog.setFileMode(qt.QFileDialog.ExistingFiles)
+ return dialog
+
+ def about(self):
+ from .About import About
+ About.about(self, "Silx viewer")
+
+ def __forcePlotImageDownward(self):
+ silx.config.DEFAULT_PLOT_IMAGE_Y_AXIS_ORIENTATION = "downward"
+
+ def __forcePlotImageUpward(self):
+ silx.config.DEFAULT_PLOT_IMAGE_Y_AXIS_ORIENTATION = "upward"
+
+ def __forceMatplotlibBackend(self):
+ silx.config.DEFAULT_PLOT_BACKEND = "matplotlib"
+
+ def __forceOpenglBackend(self):
+ silx.config.DEFAULT_PLOT_BACKEND = "opengl"
+
+ def appendFile(self, filename):
+ self.__treeview.findHdf5TreeModel().appendFile(filename)
+
+ def displaySelectedData(self):
+ """Called to update the dataviewer with the selected data.
+ """
+ selected = list(self.__treeview.selectedH5Nodes(ignoreBrokenLinks=False))
+ if len(selected) == 1:
+ # Update the viewer for a single selection
+ data = selected[0]
+ self.__dataPanel.setData(data)
+ else:
+ _logger.debug("Too many data selected")
+
+ def displayData(self, data):
+ """Called to update the dataviewer with a secific data.
+ """
+ self.__dataPanel.setData(data)
+
+ def displaySelectedCustomData(self):
+ selected = list(self.__customNxdata.selectedItems())
+ if len(selected) == 1:
+ # Update the viewer for a single selection
+ item = selected[0]
+ self.__dataPanel.setCustomDataItem(item)
+ else:
+ _logger.debug("Too many items selected")
+
+ def __customNxdataRemoved(self, item):
+ if self.__dataPanel.getCustomNxdataItem() is item:
+ self.__dataPanel.setCustomDataItem(None)
+
+ def __customNxdataUpdated(self, item):
+ if self.__dataPanel.getCustomNxdataItem() is item:
+ self.__dataPanel.setCustomDataItem(item)
+
+ def __makeSureCustomNxDataWindowIsVisible(self):
+ if not self.__customNxdataWindow.isVisible():
+ self.__customNxdataWindow.setVisible(True)
+ self._displayCustomNxdataWindow.setChecked(True)
+
+ def useAsNewCustomSignal(self, h5dataset):
+ self.__makeSureCustomNxDataWindowIsVisible()
+ model = self.__customNxdata.model()
+ model.createFromSignal(h5dataset)
+
+ def useAsNewCustomNxdata(self, h5nxdata):
+ self.__makeSureCustomNxDataWindowIsVisible()
+ model = self.__customNxdata.model()
+ model.createFromNxdata(h5nxdata)
+
+ def customContextMenu(self, event):
+ """Called to populate the context menu
+
+ :param silx.gui.hdf5.Hdf5ContextMenuEvent event: Event
+ containing expected information to populate the context menu
+ """
+ selectedObjects = event.source().selectedH5Nodes(ignoreBrokenLinks=False)
+ menu = event.menu()
+
+ if not menu.isEmpty():
+ menu.addSeparator()
+
+ for obj in selectedObjects:
+ h5 = obj.h5py_object
+
+ name = obj.name
+ if name.startswith("/"):
+ name = name[1:]
+ if name == "":
+ name = "the root"
+
+ action = qt.QAction("Show %s" % name, event.source())
+ action.triggered.connect(lambda: self.displayData(h5))
+ menu.addAction(action)
+
+ if silx.io.is_dataset(h5):
+ action = qt.QAction("Use as a new custom signal", event.source())
+ action.triggered.connect(lambda: self.useAsNewCustomSignal(h5))
+ menu.addAction(action)
+
+ if silx.io.is_group(h5) and silx.io.nxdata.is_valid_nxdata(h5):
+ action = qt.QAction("Use as a new custom NXdata", event.source())
+ action.triggered.connect(lambda: self.useAsNewCustomNxdata(h5))
+ menu.addAction(action)
+
+ if silx.io.is_file(h5):
+ action = qt.QAction("Remove %s" % obj.local_filename, event.source())
+ 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))
+ menu.addAction(action)