"""
Allows users to modify the box slicer parameters.
"""
import numpy
import functools
from PyQt5 import QtCore
from PyQt5 import QtGui
from PyQt5 import QtWidgets
import sas.qtgui.Utilities.GuiUtils as GuiUtils
# Local UI
from sas.qtgui.UI import main_resources_rc
from sas.qtgui.Plotting.UI.SlicerParametersUI import Ui_SlicerParametersUI
[docs]class SlicerParameters(QtWidgets.QDialog, Ui_SlicerParametersUI):
"""
Interaction between the QTableView and the underlying model,
passed from a slicer instance.
"""
closeWidgetSignal = QtCore.pyqtSignal()
def __init__(self, model=None, validate_method=None):
super(SlicerParameters, self).__init__()
self.setupUi(self)
assert isinstance(model, QtGui.QStandardItemModel)
self.model = model
self.validate_method = validate_method
# Define a proxy model so cell enablement can be finegrained.
self.proxy = ProxyModel(self)
self.proxy.setSourceModel(self.model)
# Set the proxy model for display in the Table View.
self.lstParams.setModel(self.proxy)
# Disallow edit of the parameter name column.
self.lstParams.model().setColumnReadOnly(0, True)
# Specify the validator on the parameter value column.
self.delegate = EditDelegate(self, validate_method=self.validate_method)
self.lstParams.setItemDelegate(self.delegate)
self.delegate.refocus_signal.connect(self.onFocus)
# Display Help on clicking the button
self.buttonBox.button(QtWidgets.QDialogButtonBox.Help).clicked.connect(self.onHelp)
# Close doesn't trigger closeEvent automatically, so force it
self.buttonBox.button(QtWidgets.QDialogButtonBox.Close).clicked.connect(functools.partial(self.closeEvent, None))
# Disable row number display
self.lstParams.verticalHeader().setVisible(False)
self.lstParams.setAlternatingRowColors(True)
self.lstParams.setSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Expanding)
# Header properties for nicer display
header = self.lstParams.horizontalHeader()
header.setSectionResizeMode(QtWidgets.QHeaderView.Stretch)
header.setStretchLastSection(True)
[docs] def onFocus(self, row, column):
""" Set the focus on the cell (row, column) """
selection_model = self.lstParams.selectionModel()
selection_model.select(self.model.index(row, column), QtGui.QItemSelectionModel.Select)
self.lstParams.setSelectionModel(selection_model)
self.lstParams.setCurrentIndex(self.model.index(row, column))
[docs] def setModel(self, model):
""" Model setter """
self.model = model
self.proxy.setSourceModel(self.model)
[docs] def keyPressEvent(self, event):
key = event.key()
if key == QtCore.Qt.Key_Escape:
self.closeWidgetSignal.emit()
[docs] def closeEvent(self, event):
"""
Overwritten close widget method in order to send the close
signal to the parent.
"""
self.closeWidgetSignal.emit()
if event:
event.accept()
[docs] def onHelp(self):
"""
Display generic data averaging help
"""
url = "/user/qtgui/MainWindow/graph_help.html#d-data-averaging"
GuiUtils.showHelp(url)
[docs]class ProxyModel(QtCore.QIdentityProxyModel):
"""
Trivial proxy model with custom column edit flag
"""
def __init__(self, parent=None):
super(ProxyModel, self).__init__(parent)
self._columns = set()
[docs] def columnReadOnly(self, column):
'''Returns True if column is read only, false otherwise'''
return column in self._columns
[docs] def setColumnReadOnly(self, column, readonly=True):
'''Add/removes a column from the readonly list'''
if readonly:
self._columns.add(column)
else:
self._columns.discard(column)
[docs] def flags(self, index):
'''Sets column flags'''
flags = super(ProxyModel, self).flags(index)
if self.columnReadOnly(index.column()):
flags &= ~QtCore.Qt.ItemIsEditable
return flags
[docs]class PositiveDoubleEditor(QtWidgets.QLineEdit):
# a signal to tell the delegate when we have finished editing
editingFinished = QtCore.Signal()
def __init__(self, parent=None):
# Initialize the editor object
super(PositiveDoubleEditor, self).__init__(parent)
self.setAutoFillBackground(True)
validator = GuiUtils.DoubleValidator()
# Don't use the scientific notation, cause 'e'.
validator.setNotation(GuiUtils.DoubleValidator.StandardNotation)
self.setValidator(validator)
[docs] def focusOutEvent(self, event):
# Once focus is lost, tell the delegate we're done editing
self.editingFinished.emit()
[docs]class EditDelegate(QtWidgets.QStyledItemDelegate):
refocus_signal = QtCore.pyqtSignal(int, int)
def __init__(self, parent=None, validate_method=None):
super(EditDelegate, self).__init__(parent)
self.editor = None
self.index = None
self.validate_method = validate_method
[docs] def createEditor(self, parent, option, index):
# Creates and returns the custom editor object we will use to edit the cell
if not index.isValid():
return 0
result = index.column()
if result==1:
self.editor = PositiveDoubleEditor(parent)
self.index = index
return self.editor
else:
return QtWidgets.QStyledItemDelegate.createEditor(self, parent, option, index)
[docs] def setModelData(self, editor, model, index):
"""
Custom version of the model update, rejecting bad values
"""
self.index = index
# Find out the changed parameter name and proposed value
new_value = GuiUtils.toDouble(self.editor.text())
param_name = model.sourceModel().item(index.row(),0).text()
validated = True
if self.validate_method:
# Validate the proposed value in the slicer
value_accepted = self.validate_method(param_name, new_value)
if value_accepted:
# Update the model only if value accepted
return super(EditDelegate, self).setModelData(editor, model, index)