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