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

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 7969b9c was 4992ff2, checked in by Piotr Rozyczko <rozyczko@…>, 6 years ago

Initial, in-progress version. Not really working atm. SASVIEW-787

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