source: sasview/src/sas/qtgui/Perspectives/Fitting/MultiConstraint.py @ 1309205b

Last change on this file since 1309205b was aed0532, checked in by Piotr Rozyczko <rozyczko@…>, 7 years ago

Updated references to help files

  • Property mode set to 100644
File size: 5.0 KB
Line 
1"""
2Widget for parameter constraints.
3"""
4import os
5import webbrowser
6
7# numpy methods required for the validator! Don't remove.
8# pylint: disable=unused-import,unused-wildcard-import,redefined-builtin
9from numpy import *
10
11from PyQt5 import QtWidgets
12
13import sas.qtgui.Utilities.GuiUtils as GuiUtils
14
15# Local UI
16from sas.qtgui.Perspectives.Fitting.UI.MultiConstraintUI import Ui_MultiConstraintUI
17
18class MultiConstraint(QtWidgets.QDialog, Ui_MultiConstraintUI):
19    """
20    Logic class for interacting with MultiConstrainedUI view
21    """
22    def __init__(self, parent=None, params=None):
23        """
24        parent: ConstraintWidget object
25        params: tuple of strings describing model parameters
26        """
27        super(MultiConstraint, self).__init__()
28
29        self.setupUi(self)
30        self.setFixedSize(self.minimumSizeHint())
31        self.setModal(True)
32        self.params = params
33        self.parent = parent
34
35        self.setupLabels()
36        self.setupTooltip()
37
38        # Set param text control to the second parameter passed
39        self.txtConstraint.setText(self.params[1])
40
41        self.cmdOK.clicked.connect(self.accept)
42        self.cmdHelp.clicked.connect(self.onHelp)
43        self.cmdRevert.clicked.connect(self.revert)
44        self.txtConstraint.editingFinished.connect(self.validateFormula)
45
46        # Default focus is on OK
47        self.cmdOK.setFocus()
48
49    def revert(self):
50        """
51        Swap parameters in the view
52        """
53        # Switch parameters
54        self.params[1], self.params[0] = self.params[0], self.params[1]
55        # Try to swap parameter names in the line edit
56        current_text = self.txtConstraint.text()
57        new_text = current_text.replace(self.params[0], self.params[1])
58        self.txtConstraint.setText(new_text)
59        # Update labels and tooltips
60        self.setupLabels()
61        self.setupTooltip()
62
63    def setupLabels(self):
64        """
65        Setup labels based on current parameters
66        """
67        l1 = self.params[0]
68        l2 = self.params[1]
69        self.txtParam1.setText(l1)
70        self.txtParam1_2.setText(l1)
71        self.txtParam2.setText(l2)
72
73    def setupTooltip(self):
74        """
75        Tooltip for txtConstraint
76        """
77        tooltip = "E.g.\n%s = 2.0 * (%s)\n" %(self.params[0], self.params[1])
78        tooltip += "%s = sqrt(%s) + 5"%(self.params[0], self.params[1])
79        self.txtConstraint.setToolTip(tooltip)
80
81    def validateFormula(self):
82        """
83        Add visual cues when formula is incorrect
84        """
85        formula_is_valid = False
86        formula_is_valid = self.validateConstraint(self.txtConstraint.text())
87        if not formula_is_valid:
88            self.cmdOK.setEnabled(False)
89            self.txtConstraint.setStyleSheet("QLineEdit {background-color: red;}")
90        else:
91            self.cmdOK.setEnabled(True)
92            self.txtConstraint.setStyleSheet("QLineEdit {background-color: white;}")
93
94    def validateConstraint(self, constraint_text):
95        """
96        Ensure the constraint has proper form
97        """
98        # 0. none or empty
99        if not constraint_text or not isinstance(constraint_text, str):
100            return False
101
102        param_str = str(self.params[1])
103        constraint_text = constraint_text.strip()
104
105        # 1. just the parameter
106        if param_str == constraint_text:
107            return True
108
109        # 2. ensure the text contains parameter name
110        parameter_string_start = constraint_text.find(param_str)
111        if parameter_string_start < 0:
112            return False
113        parameter_string_end = parameter_string_start + len(param_str)
114
115        # 3. parameter name should be a separate word, but can have "()[]*+-/ " around
116        #valid_neighbours = "()[]*+-/ "
117        #start_loc = parameter_string_start -1
118        #end_loc = parameter_string_end
119        #if not any([constraint_text[start_loc] == ch for ch in valid_neighbours]):
120        #    return False
121        #if end_loc < len(constraint_text):
122        #    if not any([constraint_text[end_loc] == ch for ch in valid_neighbours]):
123        #        return False
124
125        # 4. replace parameter name with "1" and try to evaluate the expression
126        try:
127            expression_to_evaluate = constraint_text.replace(param_str, "1.0")
128            eval(expression_to_evaluate)
129        except Exception:
130            # Too many cases to cover individually, just a blanket
131            # Exception should be sufficient
132            # Note that in current numpy things like sqrt(-1) don't
133            # raise but just return warnings
134            return False
135
136        return True
137
138    def onHelp(self):
139        """
140        Display related help section
141        """
142        try:
143            help_location = GuiUtils.HELP_DIRECTORY_LOCATION + \
144            "/user/qtgui/Perspectives/Fitting/fitting_help.html#simultaneous-fits-with-constraints"
145            webbrowser.open('file://' + os.path.realpath(help_location))
146        except AttributeError:
147            # No manager defined - testing and standalone runs
148            pass
149
150
Note: See TracBrowser for help on using the repository browser.