# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2017 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.
#
# ###########################################################################*/
"""This package provides a set of helper class and function used by the
package `silx.gui.hdf5` package.
"""
__authors__ = ["V. Valls"]
__license__ = "MIT"
__date__ = "26/04/2017"
import logging
import numpy
from .. import qt
import silx.io.utils
from silx.utils.html import escape
_logger = logging.getLogger(__name__)
try:
import h5py
except ImportError as e:
_logger.error("Module %s requires h5py", __name__)
raise e
class Hdf5ContextMenuEvent(object):
"""Hold information provided to context menu callbacks."""
def __init__(self, source, menu, hoveredObject):
"""
Constructor
:param QWidget source: Widget source
:param QMenu menu: Context menu which will be displayed
:param H5Node hoveredObject: Hovered H5 node
"""
self.__source = source
self.__menu = menu
self.__hoveredObject = hoveredObject
def source(self):
"""Source of the event
:rtype: Hdf5TreeView
"""
return self.__source
def menu(self):
"""Menu which will be displayed
:rtype: qt.QMenu
"""
return self.__menu
def hoveredObject(self):
"""Item content hovered by the mouse when the context menu was
requested
:rtype: H5Node
"""
return self.__hoveredObject
def htmlFromDict(dictionary, title=None):
"""Generate a readable HTML from a dictionary
:param dict dictionary: A Dictionary
:rtype: str
"""
result = """
"""
if title is not None:
result += "%s" % escape(title)
result += ""
for key, value in dictionary.items():
result += "- %s: %s
" % (escape(key), escape(value))
result += "
"
result += ""
return result
class Hdf5NodeMimeData(qt.QMimeData):
"""Mimedata class to identify an internal drag and drop of a Hdf5Node."""
MIME_TYPE = "application/x-internal-h5py-node"
def __init__(self, node=None):
qt.QMimeData.__init__(self)
self.__node = node
self.setData(self.MIME_TYPE, "".encode(encoding='utf-8'))
def node(self):
return self.__node
class H5Node(object):
"""Adapter over an h5py object to provide missing informations from h5py
nodes, like internal node path and filename (which are not provided by
:mod:`h5py` for soft and external links).
It also provides an abstraction to reach node type for mimicked h5py
objects.
"""
def __init__(self, h5py_item=None):
"""Constructor
:param Hdf5Item h5py_item: An Hdf5Item
"""
self.__h5py_object = h5py_item.obj
self.__h5py_item = h5py_item
def __getattr__(self, name):
return object.__getattribute__(self.__h5py_object, name)
@property
def h5py_object(self):
"""Returns the internal h5py node.
:rtype: h5py.File or h5py.Group or h5py.Dataset
"""
return self.__h5py_object
@property
def ntype(self):
"""Returns the node type, as an h5py class.
:rtype:
:class:`h5py.File`, :class:`h5py.Group` or :class:`h5py.Dataset`
"""
return silx.io.utils.get_h5py_class(self.__h5py_object)
@property
def basename(self):
"""Returns the basename of this h5py node. It is the last identifier of
the path.
:rtype: str
"""
return self.__h5py_object.name.split("/")[-1]
@property
def local_name(self):
"""Returns the local path of this h5py node.
For links, this path is not equal to the h5py one.
:rtype: str
"""
if self.__h5py_item is None:
raise RuntimeError("h5py_item is not defined")
result = []
item = self.__h5py_item
while item is not None:
if issubclass(item.h5pyClass, h5py.File):
break
result.append(item.basename)
item = item.parent
if item is None:
raise RuntimeError("The item does not have parent holding h5py.File")
if result == []:
return "/"
result.append("")
result.reverse()
return "/".join(result)
def __file_item(self):
"""Returns the parent item holding the :class:`h5py.File` object
:rtype: h5py.File
:raises RuntimeException: If no file are found
"""
item = self.__h5py_item
while item is not None:
if issubclass(item.h5pyClass, h5py.File):
return item
item = item.parent
raise RuntimeError("The item does not have parent holding h5py.File")
@property
def local_file(self):
"""Returns the local :class:`h5py.File` object.
For path containing external links, this file is not equal to the h5py
one.
:rtype: h5py.File
:raises RuntimeException: If no file are found
"""
item = self.__file_item()
return item.obj
@property
def local_filename(self):
"""Returns the local filename of the h5py node.
For path containing external links, this path is not equal to the
filename provided by h5py.
:rtype: str
:raises RuntimeException: If no file are found
"""
return self.local_file.filename
@property
def local_basename(self):
"""Returns the local filename of the h5py node.
For path containing links, this basename can be different than the
basename provided by h5py.
:rtype: str
"""
if issubclass(self.__h5py_item.h5pyClass, h5py.File):
return ""
return self.__h5py_item.basename