Salome HOME
Issue #1834: Fix length of lines
[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 }
94
95 double ModuleBase_ParamSpinBox::valueFromText(const QString& theText) const
96 {
97   if (!hasVariable(theText))
98     return ModuleBase_DoubleSpinBox::valueFromText(theText);
99
100   // small hack: return hash of the string to initiate valuesChanged signal
101   return qHash(theText);
102 }
103
104 QString ModuleBase_ParamSpinBox::textFromValue (double theValue) const
105 {
106   if ((!myTextValue.isEmpty()) && hasVariable(myTextValue)){
107     return myTextValue;
108   }
109   return ModuleBase_DoubleSpinBox::textFromValue(theValue);
110 }
111
112 /*!
113  \brief This function is used to determine whether input is valid.
114  \param str currently entered value
115  \param pos cursor position in the string
116  \return validating operation result
117  */
118 QValidator::State ModuleBase_ParamSpinBox::validate(QString& str, int& pos) const
119 {
120   // Trying to interpret the current input text as a numeric value
121   if (!hasVariable(str))
122     return ModuleBase_DoubleSpinBox::validate(str, pos);
123
124   QValidator::State res = QValidator::Invalid;
125   if (isAcceptVariables()) {
126     res = QValidator::Acceptable;
127   }
128   return res;
129 }
130
131 /*!
132  \brief This function is used to set a current value for this spinbox.
133  \param value current value
134
135  The new value is ignored if the spinbox has a variable.
136  */
137 void ModuleBase_ParamSpinBox::setValue(const double value)
138 {
139   if (hasVariable())
140     return;
141
142   myTextValue = ModuleBase_DoubleSpinBox::textFromValue(value);
143   ModuleBase_DoubleSpinBox::setValue(value);
144 }
145
146 /*!
147  \brief This function is used to set a text for this spinbox.
148  \param value current value
149  */
150 void ModuleBase_ParamSpinBox::setText(const QString& value)
151 {
152   myTextValue = value;
153   lineEdit()->setText(value);
154 }
155
156 /*!
157  \brief Enables or disables variable names in the spin box.
158  By default, variable names are enabled.
159  \param flag If true, variable names are enabled.
160  */
161 void ModuleBase_ParamSpinBox::setAcceptVariables(const bool flag)
162 {
163   myAcceptVariables = flag;
164 }
165
166 /*!
167  \brief Returns true if the spin box accepts variable names.
168  */
169 bool ModuleBase_ParamSpinBox::isAcceptVariables() const
170 {
171   return myAcceptVariables;
172 }
173
174 bool ModuleBase_ParamSpinBox::hasVariable() const
175 {
176   if (myTextValue.isEmpty())
177     return false;
178   return hasVariable(myTextValue);
179 }
180
181 bool ModuleBase_ParamSpinBox::hasVariable(const QString& theText) const
182 {
183   //const QString aDigitPattern = QString("[-+]?[0-9]*[%1]?[0-9]*([eE][-+]?[0-9]+)?");
184
185   //bool aHasDigit = false;
186   //{
187   //  QRegExp varNameMask(aDigitPattern.arg("."));
188   //  aHasDigit = varNameMask.exactMatch(theText);
189   //}
190   //if (!aHasDigit)
191   //{
192   //  QRegExp varNameMask(aDigitPattern.arg(","));
193   //  aHasDigit = varNameMask.exactMatch(theText);
194   //}
195   bool isDouble = false;
196   QLocale::c().toDouble(theText, &isDouble);
197
198 //  theText.toDouble(&isDouble);
199 //  if (isDouble) {
200 //    QLocale aLoc; // create default locale
201 //    QChar aDecPnt = aLoc.decimalPoint();
202 //    if (aDecPnt == '.')
203 //      isDouble = theText.contains(aDecPnt) || (!theText.contains(','));
204 //    else if (aDecPnt == ',')
205 //      isDouble = theText.contains(aDecPnt) || (!theText.contains('.'));
206 //  }
207   return !isDouble;
208 }
209
210 /*!
211  \brief This function is used to determine whether input is valid.
212  \return validating operation result
213  */
214 ModuleBase_ParamSpinBox::State ModuleBase_ParamSpinBox::isValid(const QString& theText,
215                                                                 double& theValue) const
216 {
217   if (hasVariable() && !findVariable(theText, theValue)) {
218     bool ok = false;
219     theValue = locale().toDouble(theText, &ok);
220     if (!ok) {
221       return NoVariable;
222     }
223   }
224   if (!checkRange(theValue)) {
225     return Invalid;
226   }
227
228   return Acceptable;
229 }
230
231 /*!
232  \brief This function is used to check that string value lies within predefined range.
233  \return check status
234  */
235 bool ModuleBase_ParamSpinBox::checkRange(const double theValue) const
236 {
237   return theValue >= minimum() && theValue <= maximum();
238 }
239
240 /*!
241  \brief This function is used to determine whether input is a variable name and to get its value.
242  \return status of search operation
243  */
244 bool ModuleBase_ParamSpinBox::findVariable(const QString& theName,
245                                            double& outValue) const
246 {
247   ResultParameterPtr aParam;
248   return ModelAPI_Tools::findVariable(FeaturePtr(), theName.toStdString(), outValue, aParam);
249 }
250
251 /*!
252  \brief This function is called when the spinbox receives key press event.
253  */
254 //void ModuleBase_ParamSpinBox::keyPressEvent(QKeyEvent* e)
255 //{
256 //  if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) {
257 //    QWidget::keyPressEvent(e);
258 //  } else {
259 //    ModuleBase_DoubleSpinBox::keyPressEvent(e);
260 //  }
261 //}
262
263 /*!
264  \brief This function is called when the spinbox receives show event.
265  */
266 void ModuleBase_ParamSpinBox::showEvent(QShowEvent* theEvent)
267 {
268   ModuleBase_DoubleSpinBox::showEvent(theEvent);
269   if ((!myTextValue.isEmpty()) && hasVariable(myTextValue)) {
270     setText(myTextValue);
271   }
272 }