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