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

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

More Qt5 related fixes

  • 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
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    close_signal = 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 closeEvent(self, event):
77        """
78        Overwritten close widget method in order to send the close
79        signal to the parent.
80        """
81        self.close_signal.emit()
82        if event:
83            event.accept()
84
85    def onHelp(self):
86        """
87        Display generic data averaging help
88        """
89        location = "docs/sphinx-docs/build/html" + \
90            "/user/sasgui/guiframe/graph_help.html#d-data-averaging"
91        self.helpView = QtWebKitWidgets.QWebView()
92        self.helpView.load(QtCore.QUrl(location))
93        self.helpView.show()
94
95
96class ProxyModel(QtCore.QIdentityProxyModel):
97    """
98    Trivial proxy model with custom column edit flag
99    """
100    def __init__(self, parent=None):
101        super(ProxyModel, self).__init__(parent)
102        self._columns = set()
103
104    def columnReadOnly(self, column):
105        '''Returns True if column is read only, false otherwise'''
106        return column in self._columns
107
108    def setColumnReadOnly(self, column, readonly=True):
109        '''Add/removes a column from the readonly list'''
110        if readonly:
111            self._columns.add(column)
112        else:
113            self._columns.discard(column)
114
115    def flags(self, index):
116        '''Sets column flags'''
117        flags = super(ProxyModel, self).flags(index)
118        if self.columnReadOnly(index.column()):
119            flags &= ~QtCore.Qt.ItemIsEditable
120        return flags
121
122class PositiveDoubleEditor(QtWidgets.QLineEdit):
123    # a signal to tell the delegate when we have finished editing
124    editingFinished = QtCore.Signal()
125
126    def __init__(self, parent=None):
127            # Initialize the editor object
128            super(PositiveDoubleEditor, self).__init__(parent)
129            self.setAutoFillBackground(True)
130            validator = GuiUtils.DoubleValidator()
131            # Don't use the scientific notation, cause 'e'.
132            validator.setNotation(GuiUtils.DoubleValidator.StandardNotation)
133
134            self.setValidator(validator)
135
136    def focusOutEvent(self, event):
137            # Once focus is lost, tell the delegate we're done editing
138            self.editingFinished.emit()
139
140
141class EditDelegate(QtWidgets.QStyledItemDelegate):
142    refocus_signal = QtCore.pyqtSignal(int, int)
143    def __init__(self, parent=None, validate_method=None):
144        super(EditDelegate, self).__init__(parent)
145        self.editor = None
146        self.index = None
147        self.validate_method = validate_method
148
149    def createEditor(self, parent, option, index):
150        # Creates and returns the custom editor object we will use to edit the cell
151        if not index.isValid():
152            return 0
153
154        result = index.column()
155        if result==1:
156                self.editor = PositiveDoubleEditor(parent)
157                self.index = index
158                return self.editor
159        else:
160                return QtWidgets.QStyledItemDelegate.createEditor(self, parent, option, index)
161
162    def setModelData(self, editor, model, index):
163        """
164        Custom version of the model update, rejecting bad values
165        """
166        self.index = index
167
168        # Find out the changed parameter name and proposed value
169        new_value = self.editor.text().toFloat()[0]
170        param_name = str(model.sourceModel().item(index.row(),0).text())
171
172        validated = True
173        if self.validate_method:
174            # Validate the proposed value in the slicer
175            value_accepted = self.validate_method(param_name, new_value)
176
177        if value_accepted:
178            # Update the model only if value accepted
179            return super(EditDelegate, self).setModelData(editor, model, index)         
Note: See TracBrowser for help on using the repository browser.