source: sasview/src/sas/qtgui/SlicerParameters.py @ 8595edd

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalc
Last change on this file since 8595edd was 161713c, checked in by Piotr Rozyczko <rozyczko@…>, 8 years ago

Validate Table View entries in 2D slicer parameter editor - prototype for future use in fitting

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