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