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