Commit 6822878d authored by Damien Naudet's avatar Damien Naudet
Browse files

Split a file into several.

parent 6d667c91
......@@ -399,6 +399,13 @@ class ImageRoiManager(qt.QObject):
self._plot.sigInteractiveModeChanged.connect(
self._interactiveModeChanged, qt.Qt.QueuedConnection)
def plot(self):
"""
Returns the plot controlled by this manager.
:return:
"""
return self._plot
def _createRoiActions(self):
if self._roiActions:
......
# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2015-2016 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.
#
# ###########################################################################*/
from __future__ import absolute_import
__authors__ = ["D. Naudet"]
__license__ = "MIT"
__date__ = "15/09/2016"
from silx.gui import qt as Qt
from ...model.TreeView import TreeView
from ...model.ModelDef import ModelRoles
from ...model.Model import Model, RootNode, Node
from ...project.Hdf5Nodes import H5GroupNode
from ...project.IntensityGroup import IntensityGroup
class IntensityTotalNode(H5GroupNode):
"""
Node displaying info about the number of entries selected.
"""
total = property(lambda self: self.__total)
samplePos = property(lambda self: self.__samplePos)
icons = None
def __init__(self, checkableChildren=True, **kwargs):
"""
Node representing the total intensity. Its children
are the intensity for each angle.
:param checkableChildren: if set to True (default) the angle
intensity nodes will be checkable.
:param kwargs:
"""
super(IntensityTotalNode, self).__init__(**kwargs)
# TODO : check item type
self.nodeName = 'Total'
self.__total = None
self.__samplePos = None
self.__notifyModel = True
self.__checkableChildren = checkableChildren
def _loadChildren(self):
iGroup = IntensityGroup(self.h5File, self.h5Path)
iItems = iGroup.getIntensityItems()
children = []
for iItem in iItems:
if iItem.entry == 'Total':
continue
iNode = IntensityViewItemNode(iItem)
iNode.checkable = self.__checkableChildren
if iNode.checkable:
iNode.setCheckState(Qt.Qt.Checked)
children.append(iNode)
self.nodeName = 'Total {0} / {0}'.format(len(children))
return children
def _childInternalDataChanged(self, sender, *args):
super(IntensityTotalNode, self)._childInternalDataChanged(sender,
*args)
if sender.parent() != self:
return
if self.__notifyModel:
self.__getTotal()
self.sigInternalDataChanged.emit([0])
def __getTotal(self):
total = None
samplePos = None
nSelected = 0
childCount = self.childCount()
for childIdx in range(childCount):
child = self.child(childIdx)
if child.checkState == Qt.Qt.Unchecked:
continue
nSelected += 1
intensity, pos = child.item.getScatterData()
if total is None:
total = intensity
samplePos = pos
else:
total += intensity
blocked = self.blockSignals(True)
self.nodeName = 'Total {0} / {1}'.format(nSelected, childCount)
self.__total = total
self.__samplePos = samplePos
self.blockSignals(blocked)
def scatterData(self):
if self.total is None:
self.__getTotal()
return self.total, self.samplePos
def getCheckedEntries(self):
"""
Returns the list of entries, the list of checked entries indices,
and the list of unchecked entries indices.
:return:
"""
selected = []
unselected = []
entries = []
for childIdx in range(self.childCount()):
child = self.child(childIdx)
entries.append(child.item.entry)
if child.checkState == Qt.Qt.Unchecked:
unselected.append(childIdx)
else:
selected.append(childIdx)
return entries, selected, unselected
def checkAll(self):
"""
Check all entries.
:return:
"""
# blocked = self.blockSignals(True)
self.__notifyModel = False
for childIdx in range(self.childCount()):
child = self.child(childIdx)
child.setCheckState(Qt.Qt.Checked)
# self.blockSignals(blocked)
self.__getTotal()
self.__notifyModel = True
self._notifyDataChange()
def uncheckAll(self):
"""
Uncheck all entries.
:return:
"""
# blocked = self.blockSignals(True)
self.__notifyModel = False
for childIdx in range(self.childCount()):
child = self.child(childIdx)
child.setCheckState(Qt.Qt.Unchecked)
# self.blockSignals(blocked)
self.__getTotal()
self.__notifyModel = True
self._notifyDataChange()
class IntensityViewItemNode(Node):
checkable = True
item = property(lambda self: self.__item)
def __init__(self, iItem, **kwargs):
super(IntensityViewItemNode, self).__init__(**kwargs)
# TODO : check item type
self.__item = iItem
self.nodeName = str(iItem.projectRoot().shortName(iItem.entry))
# self.setCheckState(Qt.Qt.Checked)
self._setDataInternal(IntensityModelColumns.AngleColumn,
iItem.entry,
Qt.Qt.ToolTipRole)
def scatterData(self):
return self.item.getScatterData()
class IntensityModelColumns(object):
AngleColumn = 0
ColumnNames = ['Angle']
class IntensityRootNode(RootNode):
"""
Root node for the FitModel
"""
ColumnNames = IntensityModelColumns.ColumnNames
class IntensityModel(Model):
"""
Model displaying a FitH5 file contents.
"""
RootNode = IntensityRootNode
ModelColumns = IntensityModelColumns
ColumnsWithDelegates = None
def __iTotalNode(self):
iTotalIndex = self.index(0, 0)
return iTotalIndex.data(ModelRoles.InternalDataRole)
def getCheckedEntries(self):
iTotalNode = self.__iTotalNode()
if iTotalNode is None:
return []
return iTotalNode.getCheckedEntries()
def selectAll(self):
iTotalNode = self.__iTotalNode()
if iTotalNode is None:
return []
iTotalNode.checkAll()
def unselectAll(self):
iTotalNode = self.__iTotalNode()
if iTotalNode is None:
return []
iTotalNode.uncheckAll()
class IntensityTree(TreeView):
sigCurrentChanged = Qt.Signal(object)
def __init__(self, intensityGroupItem,
checkable=True,
**kwargs):
"""
A tree linked to the summed intensity of an acquisition
(IntensityGroup project item).
:param intensityGroupItem:
:param checkable: if True (default) the individual nodes will be
checkable.
:param kwargs:
"""
super(IntensityTree, self).__init__(**kwargs)
model = IntensityModel()
iGroupNode = IntensityTotalNode(h5File=intensityGroupItem.filename,
h5Path=intensityGroupItem.path,
checkableChildren=checkable)
model.appendGroup(iGroupNode)
self.setModel(model)
self.setShowUniqueGroup(True)
self.setExpanded(self.model().index(0, 0), True)
model.startModel()
def currentChanged(self, current, previous):
super(IntensityTree, self).currentChanged(current, previous)
node = current.data(ModelRoles.InternalDataRole)
if not node:
return
self.sigCurrentChanged.emit(node)
if __name__ == '__main__':
pass
......@@ -36,373 +36,17 @@ import numpy as np
from silx.gui import qt as Qt
from .PlotModel import PlotTree
from .IntensityModel import IntensityTree, IntensityTotalNode
from .RectRoiWidget import RectRoiWidget
from ...model.TreeView import TreeView
from ...model.ModelDef import ModelRoles
from ...model.Model import Model, RootNode, Node
from ...project.Hdf5Nodes import H5GroupNode
from ...project.IntensityGroup import IntensityGroup
from ...widgets.Containers import GroupBox
from ...widgets.Input import StyledLineEdit
from ...widgets.XsocsPlot2D import XsocsPlot2D
from ...widgets.Buttons import FixedSizePushButon
try:
from silx.gui.plot.ImageRois import ImageRoiManager
except ImportError:
# TODO remove this import once the ROIs are added to the silx release.
from ...silx_imports.ImageRois import ImageRoiManager
IntensityViewEvent = namedtuple('IntensityViewEvent', ['roi', 'entries'])
class RectRoiWidget(Qt.QWidget):
sigRoiApplied = Qt.Signal(object)
def __init__(self, roiManager, parent=None):
# TODO :
# support multiple ROIs then batch them
super(RectRoiWidget, self).__init__(parent)
self.__roiToolBar = roiToolBar = roiManager.toolBar(rois=['rectangle'],
options=['show'])
roiToolBar.setMovable(False)
topLayout = Qt.QVBoxLayout(self)
grpBox = GroupBox('ROI')
layout = Qt.QGridLayout(grpBox)
row = 0
layout.addWidget(roiToolBar, row, 0, 1, 2, Qt.Qt.AlignTop)
row += 1
self._xEdit = edit = StyledLineEdit(nChar=6)
edit.setReadOnly(True)
layout.addWidget(Qt.QLabel('x='), row, 0, Qt.Qt.AlignTop)
layout.addWidget(edit, row, 1, Qt.Qt.AlignTop)
row += 1
self._yEdit = edit = StyledLineEdit(nChar=6)
edit.setReadOnly(True)
layout.addWidget(Qt.QLabel('y='), row, 0, Qt.Qt.AlignTop)
layout.addWidget(edit, row, 1, Qt.Qt.AlignTop)
row += 1
self._wEdit = edit = StyledLineEdit(nChar=6)
edit.setReadOnly(True)
layout.addWidget(Qt.QLabel('w='), row, 0, Qt.Qt.AlignTop)
layout.addWidget(edit, row, 1, Qt.Qt.AlignTop)
row += 1
self._hEdit = edit = StyledLineEdit(nChar=6)
edit.setReadOnly(True)
layout.addWidget(Qt.QLabel('h='), row, 0, Qt.Qt.AlignTop)
layout.addWidget(edit, row, 1, Qt.Qt.AlignTop)
row += 1
hLayout = Qt.QHBoxLayout()
style = Qt.QApplication.style()
icon = style.standardIcon(Qt.QStyle.SP_DialogApplyButton)
self.__applyBn = applyBn = Qt.QToolButton()
applyBn.setToolTip('Apply ROI')
applyBn.setStatusTip('Apply ROI')
applyBn.setIcon(icon)
applyBn.setToolButtonStyle(Qt.Qt.ToolButtonTextBesideIcon)
applyBn.setText('To Q Space')
applyBn.setEnabled(False)
hLayout.addWidget(applyBn)
applyBn.clicked.connect(self.__applyRoi)
icon = style.standardIcon(Qt.QStyle.SP_DialogCloseButton)
self.__discardBn = discardBn = Qt.QToolButton()
discardBn.setToolTip('Discard ROI')
discardBn.setStatusTip('Discard ROI')
discardBn.setIcon(icon)
discardBn.setEnabled(False)
hLayout.addWidget(discardBn, Qt.Qt.AlignRight)
discardBn.clicked.connect(self.__discardRoi)
layout.addLayout(hLayout, row, 0, 1, 2, Qt.Qt.AlignCenter)
# topLayout.setSizeConstraint(Qt.QLayout.SetMinimumSize)
topLayout.addWidget(grpBox)
topLayout.addStretch(100)
# TODO : weakref
self.__roiManager = roiManager
roiManager.sigRoiDrawingFinished.connect(self.__roiDrawingFinished,
Qt.Qt.QueuedConnection)
roiManager.sigRoiRemoved.connect(self.__roiRemoved,
Qt.Qt.QueuedConnection)
roiManager.sigRoiMoved.connect(self.__roiMoved,
Qt.Qt.QueuedConnection)
def sizeHint(self):
return Qt.QSize(self.__roiToolBar.sizeHint().width() + 10, 0)
def __discardRoi(self, checked):
self.__roiManager.clear()
def __applyRoi(self, checked):
# At the moment we only support one roi at a time.
roi = self.__roiManager.rois
roiItem = self.__roiManager.roiItem(roi[0])
xMin = roiItem.pos[0]
xMax = xMin + roiItem.width
yMin = roiItem.pos[1]
yMax = yMin + roiItem.height
self.sigRoiApplied.emit([xMin, xMax, yMin, yMax])
def __roiDrawingFinished(self, event):
self.__display(event['xdata'], event['ydata'])
self.__discardBn.setEnabled(True)
self.__applyBn.setEnabled(True)
def __clear(self):
self._xEdit.clear()
self._yEdit.clear()
self._wEdit.clear()
self._hEdit.clear()
def __display(self, xData, yData):
xMin, xMax = xData[0], xData[2]
if xMax < xMin:
xMin, xMax = xMax, xMin
yMin, yMax = yData[0], yData[1]
if yMax < yMin:
yMin, yMax = yMax, yMin
self._xEdit.setText(str(xMin))
self._yEdit.setText(str(yMin))
self._wEdit.setText(str(xMax - xMin))
self._hEdit.setText(str(yMax - yMin))
def __roiRemoved(self, name):
self.__clear()
self.__discardBn.setEnabled(False)
self.__applyBn.setEnabled(False)
def __roiMoved(self, event):
self.__display(event['xdata'], event['ydata'])
class IntensityTotalNode(H5GroupNode):
"""
Node displaying info about the number of entries selected.
"""
total = property(lambda self: self.__total)
samplePos = property(lambda self: self.__samplePos)
icons = None
def __init__(self, **kwargs):
super(IntensityTotalNode, self).__init__(**kwargs)
# TODO : check item type
self.nodeName = 'Total'
self.__total = None
self.__samplePos = None
self.__notifyModel = True
def _loadChildren(self):
iGroup = IntensityGroup(self.h5File, self.h5Path)
iItems = iGroup.getIntensityItems()
children = []
for iItem in iItems:
if iItem.entry == 'Total':
continue
iNode = IntensityViewItemNode(iItem)
children.append(iNode)
self.nodeName = 'Total {0} / {0}'.format(len(children))
return children
def _childInternalDataChanged(self, sender, *args):
super(IntensityTotalNode, self)._childInternalDataChanged(sender,
*args)
if sender.parent() != self:
return
if self.__notifyModel:
self.__getTotal()
self.sigInternalDataChanged.emit([0])
def __getTotal(self):
total = None
samplePos = None
nSelected = 0
childCount = self.childCount()
for childIdx in range(childCount):
child = self.child(childIdx)
if child.checkState == Qt.Qt.Unchecked:
continue
nSelected += 1
intensity, pos = child.item.getScatterData()
if total is None:
total = intensity
samplePos = pos
else:
total += intensity
blocked = self.blockSignals(True)
self.nodeName = 'Total {0} / {1}'.format(nSelected, childCount)
self.__total = total
self.__samplePos = samplePos
self.blockSignals(blocked)
def scatterData(self):
if self.total is None:
self.__getTotal()
return self.total, self.samplePos
def getSelectedEntries(self):
"""
Returns the list of entries, the list of selected entries indices,
and the list of unselected entries indices.
:return:
"""
selected = []
unselected = []
entries = []
for childIdx in range(self.childCount()):
child = self.child(childIdx)
entries.append(child.item.entry)
if child.checkState == Qt.Qt.Unchecked:
unselected.append(childIdx)
else:
selected.append(childIdx)
return entries, selected, unselected
def selectAll(self):
"""
Selects all entries.
:return:
"""
# blocked = self.blockSignals(True)
self.__notifyModel = False
for childIdx in range(self.childCount()):
child = self.child(childIdx)
child.setCheckState(Qt.Qt.Checked)
# self.blockSignals(blocked)
self.__getTotal()
self.__notifyModel = True
self._notifyDataChange()
def unselectAll(self):
"""
Unselects all entries.
:return:
"""
# blocked = self.blockSignals(True)
self.__notifyModel = False
for childIdx in range(self.childCount()):
child = self.child(childIdx)
child.setCheckState(Qt.Qt.Unchecked)
# self.blockSignals(blocked)
self.__getTotal()
self.__notifyModel = True
self._notifyDataChange()
class IntensityViewItemNode(Node):
checkable = True
item = property(lambda self: self.__item)
def __init__(self, iItem, **kwargs):
super(IntensityViewItemNode, self).__init__(**kwargs)
# TODO : check item type
self.__item = iItem
self.nodeName = str(iItem.projectRoot().shortName(iItem.entry))
self.setCheckState(Qt.Qt.Checked)
self._setDataInternal(IntensityModelColumns.AngleColumn,
iItem.entry,
Qt.Qt.ToolTipRole)
def scatterData(self):
return self.item.getScatterData()
class IntensityModelColumns(object):