source: sasview/src/sas/qtgui/Plotting/SlicerParameters.py @ 0239237

Last change on this file since 0239237 was 2e7be0d, checked in by Piotr Rozyczko <piotr.rozyczko@…>, 6 years ago

Added explicit handler for Escape keystroke

  • Property mode set to 100644
File size: 6.3 KB
Line 
1"""
2Allows users to modify the box slicer parameters.
3"""
4import numpy
5import functools
6
7from PyQt5 import QtCore
8from PyQt5 import QtGui
9from PyQt5 import QtWidgets
10
11import sas.qtgui.Utilities.GuiUtils as GuiUtils
12
13# Local UI
14from sas.qtgui.UI import main_resources_rc
15from sas.qtgui.Plotting.UI.SlicerParametersUI import Ui_SlicerParametersUI
16
17class SlicerParameters(QtWidgets.QDialog, Ui_SlicerParametersUI):
18    """
19    Interaction between the QTableView and the underlying model,
20    passed from a slicer instance.
21    """
22    closeWidgetSignal = QtCore.pyqtSignal()
23    def __init__(self, model=None, validate_method=None):
24        super(SlicerParameters, self).__init__()
25
26        self.setupUi(self)
27
28        assert isinstance(model, QtGui.QStandardItemModel)
29
30        self.model = model
31        self.validate_method = validate_method
32
33        # Define a proxy model so cell enablement can be finegrained.
34        self.proxy = ProxyModel(self)
35        self.proxy.setSourceModel(self.model)
36
37        # Set the proxy model for display in the Table View.
38        self.lstParams.setModel(self.proxy)
39
40        # Disallow edit of the parameter name column.
41        self.lstParams.model().setColumnReadOnly(0, True)
42
43        # Specify the validator on the parameter value column.
44        self.delegate = EditDelegate(self, validate_method=self.validate_method)
45        self.lstParams.setItemDelegate(self.delegate)
46        self.delegate.refocus_signal.connect(self.onFocus)
47
48        # Display Help on clicking the button
49        self.buttonBox.button(QtWidgets.QDialogButtonBox.Help).clicked.connect(self.onHelp)
50
51        # Close doesn't trigger closeEvent automatically, so force it
52        self.buttonBox.button(QtWidgets.QDialogButtonBox.Close).clicked.connect(functools.partial(self.closeEvent, None))
53
54        # Disable row number display
55        self.lstParams.verticalHeader().setVisible(False)
56        self.lstParams.setAlternatingRowColors(True)
57        self.lstParams.setSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Expanding)
58
59        # Header properties for nicer display
60        header = self.lstParams.horizontalHeader()
61        header.setSectionResizeMode(QtWidgets.QHeaderView.Stretch)
62        header.setStretchLastSection(True)
63
64    def onFocus(self, row, column):
65        """ Set the focus on the cell (row, column) """
66        selection_model = self.lstParams.selectionModel()
67        selection_model.select(self.model.index(row, column), QtGui.QItemSelectionModel.Select)
68        self.lstParams.setSelectionModel(selection_model)
69        self.lstParams.setCurrentIndex(self.model.index(row, column))
70
71    def setModel(self, model):
72        """ Model setter """
73        self.model = model
74        self.proxy.setSourceModel(self.model)
75
76    def keyPressEvent(self, event):
77         key = event.key()
78
79         if key == QtCore.Qt.Key_Escape:
80            self.closeWidgetSignal.emit()
81
82    def closeEvent(self, event):
83        """
84        Overwritten close widget method in order to send the close
85        signal to the parent.
86        """
87        self.closeWidgetSignal.emit()
88        if event:
89            event.accept()
90
91    def onHelp(self):
92        """
93        Display generic data averaging help
94        """
95        url = "/user/qtgui/MainWindow/graph_help.html#d-data-averaging"
96        GuiUtils.showHelp(url)
97
98class ProxyModel(QtCore.QIdentityProxyModel):
99    """
100    Trivial proxy model with custom column edit flag
101    """
102    def __init__(self, parent=None):
103        super(ProxyModel, self).__init__(parent)
104        self._columns = set()
105
106    def columnReadOnly(self, column):
107        '''Returns True if column is read only, false otherwise'''
108        return column in self._columns
109
110    def setColumnReadOnly(self, column, readonly=True):
111        '''Add/removes a column from the readonly list'''
112        if readonly:
113            self._columns.add(column)
114        else:
115            self._columns.discard(column)
116
117    def flags(self, index):
118        '''Sets column flags'''
119        flags = super(ProxyModel, self).flags(index)
120        if self.columnReadOnly(index.column()):
121            flags &= ~QtCore.Qt.ItemIsEditable
122        return flags
123
124class PositiveDoubleEditor(QtWidgets.QLineEdit):
125    # a signal to tell the delegate when we have finished editing
126    editingFinished = QtCore.Signal()
127
128    def __init__(self, parent=None):
129            # Initialize the editor object
130            super(PositiveDoubleEditor, self).__init__(parent)
131            self.setAutoFillBackground(True)
132            validator = GuiUtils.DoubleValidator()
133            # Don't use the scientific notation, cause 'e'.
134            validator.setNotation(GuiUtils.DoubleValidator.StandardNotation)
135
136            self.setValidator(validator)
137
138    def focusOutEvent(self, event):
139            # Once focus is lost, tell the delegate we're done editing
140            self.editingFinished.emit()
141
142
143class EditDelegate(QtWidgets.QStyledItemDelegate):
144    refocus_signal = QtCore.pyqtSignal(int, int)
145    def __init__(self, parent=None, validate_method=None):
146        super(EditDelegate, self).__init__(parent)
147        self.editor = None
148        self.index = None
149        self.validate_method = validate_method
150
151    def createEditor(self, parent, option, index):
152        # Creates and returns the custom editor object we will use to edit the cell
153        if not index.isValid():
154            return 0
155
156        result = index.column()
157        if result==1:
158                self.editor = PositiveDoubleEditor(parent)
159                self.index = index
160                return self.editor
161        else:
162                return QtWidgets.QStyledItemDelegate.createEditor(self, parent, option, index)
163
164    def setModelData(self, editor, model, index):
165        """
166        Custom version of the model update, rejecting bad values
167        """
168        self.index = index
169
170        # Find out the changed parameter name and proposed value
171        new_value = GuiUtils.toDouble(self.editor.text())
172        param_name = model.sourceModel().item(index.row(),0).text()
173
174        validated = True
175        if self.validate_method:
176            # Validate the proposed value in the slicer
177            value_accepted = self.validate_method(param_name, new_value)
178
179        if value_accepted:
180            # Update the model only if value accepted
181            return super(EditDelegate, self).setModelData(editor, model, index)         
Note: See TracBrowser for help on using the repository browser.