Salome HOME
Merge branch 'Dev_1.1.0' of newgeom:newgeom.git into Dev_1.1.0
[modules/shaper.git] / src / ModuleBase / ModuleBase_ParamSpinBox.cpp
1 #include "ModuleBase_ParamSpinBox.h"
2
3 #include <ModelAPI_Session.h>
4 #include <ModelAPI_Document.h>
5 #include <ModelAPI_ResultParameter.h>
6 #include <ModelAPI_AttributeDouble.h>
7 #include <ModelAPI_Tools.h>
8
9 #include <QKeyEvent>
10 #include <QLineEdit>
11 #include <QToolTip>
12 #include <QRegExp>
13
14 #include <string>
15
16 /*!
17  \class ModuleBase_ParamSpinBox
18  */
19
20 /*!
21  \brief Constructor.
22
23  Constructs a spin box with 0.0 as minimum value and 99.99 as maximum value,
24  a step value of 1.0 and a precision of 2 decimal places.
25  The value is initially set to 0.00.
26
27  \param parent parent object
28  */
29 ModuleBase_ParamSpinBox::ModuleBase_ParamSpinBox(QWidget* theParent, int thePrecision)
30     : ModuleBase_DoubleSpinBox(theParent, thePrecision),
31       myAcceptVariables(true)
32 {
33   connectSignalsAndSlots();
34 }
35
36 /*!
37  \brief Destructor.
38  */
39 ModuleBase_ParamSpinBox::~ModuleBase_ParamSpinBox()
40 {
41 }
42
43 /*!
44  \brief Perform \a steps increment/decrement steps.
45
46  Re-implemented to handle cases when Notebook variable
47  name is specified by the user as the widget text.
48  Otherwise, simply calls the base implementation.
49
50  \param steps number of increment/decrement steps
51  */
52 void ModuleBase_ParamSpinBox::stepBy(int steps)
53 {
54   if (hasVariable())
55     return;
56
57   ModuleBase_DoubleSpinBox::stepBy(steps);
58 }
59
60 /*!
61  \brief Connect signals and slots.
62  */
63 void ModuleBase_ParamSpinBox::connectSignalsAndSlots()
64 {
65   connect(this, SIGNAL(editingFinished()),
66           this, SLOT(onEditingFinished()));
67
68   connect(this, SIGNAL(valueChanged(const QString&)),
69           this, SLOT(onTextChanged(const QString&)));
70
71   //connect(lineEdit(), SIGNAL(textChanged(const QString&)),
72   //        this,       SLOT(onTextChanged(const QString&)));
73
74   //connect(lineEdit(), SIGNAL(textChanged(const QString&)),
75   //        this,       SIGNAL(textChanged(const QString&)));
76 }
77
78 /*!
79  \brief This function is called when editing is finished.
80  */
81 void ModuleBase_ParamSpinBox::onEditingFinished()
82 {
83   if (myTextValue.isNull())
84     myTextValue = text();
85
86   setText(myTextValue);
87 }
88
89 /*!
90  \brief This function is called when value is changed.
91  */
92 void ModuleBase_ParamSpinBox::onTextChanged(const QString& text)
93 {
94   myTextValue = text;
95
96   double value = 0;
97   if (isValid(text, value) == Acceptable) {
98     myCorrectValue = text;
99   }
100 }
101
102 /*!
103  \brief Interpret text entered by the user as a value.
104  \param text text entered by the user
105  \return mapped value
106  \sa textFromValue()
107  */
108 double ModuleBase_ParamSpinBox::valueFromText(const QString& theText) const
109 {
110   if (!hasVariable(theText))
111     return ModuleBase_DoubleSpinBox::valueFromText(theText);
112
113   double aValue = 0;
114   findVariable(theText, aValue);
115   return aValue;
116 }
117
118 /*!
119  \brief This function is used to determine whether input is valid.
120  \param str currently entered value
121  \param pos cursor position in the string
122  \return validating operation result
123  */
124 QValidator::State ModuleBase_ParamSpinBox::validate(QString& str, int& pos) const
125 {
126   // Trying to interpret the current input text as a numeric value
127   if (!hasVariable(str))
128     return ModuleBase_DoubleSpinBox::validate(str, pos);
129
130   QValidator::State res = QValidator::Invalid;
131
132   // Considering the input text as a variable name
133   // Applying Python identifier syntax:
134   // either a string starting with a letter, or a string starting with
135   // an underscore followed by at least one alphanumeric character
136   if (isAcceptVariables()) {
137     QRegExp varNameMask("[_a-zA-Z][a-zA-Z0-9_]*");
138     if (varNameMask.exactMatch(str))
139       res = QValidator::Acceptable;
140
141     if (res == QValidator::Invalid) {
142       varNameMask.setPattern("_");
143       if (varNameMask.exactMatch(str))
144         res = QValidator::Intermediate;
145     }
146   }
147   return res;
148 }
149
150 /*!
151  \brief This function is used to set a current value for this spinbox.
152  \param value current value
153  */
154 void ModuleBase_ParamSpinBox::setValue(const double value)
155 {
156   ModuleBase_DoubleSpinBox::setValue(value);
157
158   myCorrectValue = ModuleBase_DoubleSpinBox::textFromValue(value);
159   myTextValue = myCorrectValue;
160 }
161
162 /*!
163  \brief This function is used to set a text for this spinbox.
164  \param value current value
165  */
166 void ModuleBase_ParamSpinBox::setText(const QString& value)
167 {
168   lineEdit()->setText(value);
169 }
170
171 /*!
172  \brief Enables or disables variable names in the spin box.
173  By default, variable names are enabled.
174  \param flag If true, variable names are enabled.
175  */
176 void ModuleBase_ParamSpinBox::setAcceptVariables(const bool flag)
177 {
178   myAcceptVariables = flag;
179 }
180
181 /*!
182  \brief Returns true if the spin box accepts variable names.
183  */
184 bool ModuleBase_ParamSpinBox::isAcceptVariables() const
185 {
186   return myAcceptVariables;
187 }
188
189 bool ModuleBase_ParamSpinBox::hasVariable() const
190 {
191   return hasVariable(text());
192 }
193
194 bool ModuleBase_ParamSpinBox::hasVariable(const QString& theText) const
195 {
196   QRegExp varNameMask("([a-z]|[A-Z]|_).*");
197   return varNameMask.exactMatch(theText);
198 }
199
200 /*!
201  \brief This function is used to determine whether input is valid.
202  \return validating operation result
203  */
204 ModuleBase_ParamSpinBox::State ModuleBase_ParamSpinBox::isValid(const QString& theText,
205                                                                 double& theValue) const
206 {
207   if (hasVariable() && !findVariable(theText, theValue)) {
208     bool ok = false;
209     theValue = locale().toDouble(theText, &ok);
210     if (!ok) {
211       return NoVariable;
212     }
213   }
214   if (!checkRange(theValue)) {
215     return Invalid;
216   }
217
218   return Acceptable;
219 }
220
221 /*!
222  \brief This function is used to check that string value lies within predefined range.
223  \return check status
224  */
225 bool ModuleBase_ParamSpinBox::checkRange(const double theValue) const
226 {
227   return theValue >= minimum() && theValue <= maximum();
228 }
229
230 /*!
231  \brief This function is used to determine whether input is a variable name and to get its value.
232  \return status of search operation
233  */
234 bool ModuleBase_ParamSpinBox::findVariable(const QString& theName,
235                                            double& outValue) const
236 {
237
238   return ModelAPI_Tools::findVariable(theName.toStdString(), outValue);
239 }
240
241 /*!
242  \brief This function is called when the spinbox recieves key press event.
243  */
244 void ModuleBase_ParamSpinBox::keyPressEvent(QKeyEvent* e)
245 {
246   if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) {
247     QWidget::keyPressEvent(e);
248   } else {
249     ModuleBase_DoubleSpinBox::keyPressEvent(e);
250   }
251 }
252
253 /*!
254  \brief This function is called when the spinbox recieves show event.
255  */
256 void ModuleBase_ParamSpinBox::showEvent(QShowEvent* theEvent)
257 {
258   ModuleBase_DoubleSpinBox::showEvent(theEvent);
259   if (hasVariable(myTextValue)) {
260     setText(myTextValue);
261   }
262 }