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