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.py831
1 files changed, 0 insertions, 831 deletions
diff --git a/silx/app/view/Viewer.py b/silx/app/view/Viewer.py
deleted file mode 100644
index 88ff989..0000000
--- a/silx/app/view/Viewer.py
+++ /dev/null
@@ -1,831 +0,0 @@
-# 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__ = "08/10/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("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")
- 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 __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.
-
- 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 index.column() != 0:
- continue
- 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 index.column() != 0:
- continue
- 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.__synchronizeH5pyObject(h5))
- menu.addAction(action)