1 // Copyright (C) 2014-2017 CEA/DEN, EDF R&D
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.
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.
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
17 // See http://www.salome-platform.org/ or
18 // email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
21 #include "ModuleBase_ParamSpinBox.h"
27 #include <QApplication>
29 #include <QStringListModel>
31 #include <QAbstractItemView>
37 ModuleBase_ParamSpinBox::ModuleBase_ParamSpinBox(QWidget* theParent, int thePrecision)
38 : QAbstractSpinBox(theParent),
39 myPrecision(thePrecision),
41 myAcceptVariables(true),
47 myCompleter = new QCompleter(this);
48 myCompleter->setWidget(lineEdit());
49 myCompleter->setCompletionMode(QCompleter::PopupCompletion);
51 myCompleterModel = new QStringListModel(this);
52 myCompleter->setModel(myCompleterModel);
53 // Use sorted model to accelerate completion (QCompleter will use binary search)
54 myCompleter->setModelSorting(QCompleter::CaseInsensitivelySortedModel);
55 myCompleter->setCaseSensitivity(Qt::CaseInsensitive);
56 connect(myCompleter, SIGNAL(highlighted(const QString&)),
57 this, SLOT(insertCompletion(const QString&)));
59 // connectSignalsAndSlots();
60 myEnabledBaseColor = palette().color(QPalette::Active, QPalette::Base);
61 connect(lineEdit(), SIGNAL(textChanged(const QString&)),
62 this, SLOT(onTextChanged(const QString&)));
64 myValidator = new QDoubleValidator(this);
65 myValidator->setLocale(locale());
66 myValidator->setRange(myMinimum, myMaximum);
69 void ModuleBase_ParamSpinBox::setCompletionList(QStringList& theList)
72 theList.removeDuplicates();
73 myCompleterModel->setStringList(theList);
79 ModuleBase_ParamSpinBox::~ModuleBase_ParamSpinBox()
84 \brief Perform \a steps increment/decrement steps.
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.
90 \param steps number of increment/decrement steps
92 void ModuleBase_ParamSpinBox::stepBy(int steps)
97 double aVal = lineEdit()->text().toDouble();
98 aVal += steps * mySingleStep;
100 QAbstractSpinBox::stepBy(steps);
103 void ModuleBase_ParamSpinBox::onTextChanged(const QString& theText)
105 myIsEquation = hasVariable(theText);
106 emit textChanged(theText);
111 // \brief Connect signals and slots.
113 //void ModuleBase_ParamSpinBox::connectSignalsAndSlots()
115 // connect(this, SIGNAL(valueChanged(const QString&)),
116 // this, SLOT(onTextChanged(const QString&)));
119 //void ModuleBase_ParamSpinBox::onTextChanged(const QString& text)
121 // myTextValue = text;
122 // emit textChanged(text);
125 //double ModuleBase_ParamSpinBox::valueFromText(const QString& theText) const
127 // if (!hasVariable(theText))
128 // return ModuleBase_DoubleSpinBox::valueFromText(theText);
130 // // small hack: return hash of the string to initiate valuesChanged signal
131 // return qHash(theText);
134 //QString ModuleBase_ParamSpinBox::textFromValue (double theValue) const
136 // if ((!myTextValue.isEmpty()) && hasVariable(myTextValue)){
137 // return myTextValue;
139 // return ModuleBase_DoubleSpinBox::textFromValue(theValue);
143 \brief This function is used to determine whether input is valid.
144 \param str currently entered value
145 \param pos cursor position in the string
146 \return validating operation result
148 QValidator::State ModuleBase_ParamSpinBox::validate(QString& str, int& pos) const
150 // Trying to interpret the current input text as a numeric value
151 if (!hasVariable(str))
152 return myValidator->validate(str, pos);
154 return isAcceptVariables() ? QValidator::Acceptable : QValidator::Invalid;
158 \brief This function is used to set a current value for this spinbox.
159 \param value current value
161 The new value is ignored if the spinbox has a variable.
163 void ModuleBase_ParamSpinBox::setValue(double value)
165 myIsEquation = false;
167 if (aVal < myMinimum)
169 else if (aVal > myMaximum)
171 QString aText = QString::number(aVal, 'g', myDecimals);
172 lineEdit()->setText(aText);
173 emit textChanged(aText);
176 double ModuleBase_ParamSpinBox::value() const
178 //if (myIsEquation) {
181 return lineEdit()->text().toDouble();
185 \brief This function is used to set a text for this spinbox.
186 \param value current value
188 void ModuleBase_ParamSpinBox::setText(const QString& value)
190 myIsEquation = hasVariable(value);
191 if (myAcceptVariables && myIsEquation) {
192 lineEdit()->setText(value);
193 emit textChanged(value);
198 \brief Enables or disables variable names in the spin box.
199 By default, variable names are enabled.
200 \param flag If true, variable names are enabled.
202 void ModuleBase_ParamSpinBox::setAcceptVariables(const bool flag)
204 myAcceptVariables = flag;
205 if ((!myAcceptVariables) && myIsEquation) {
211 \brief Returns true if the spin box accepts variable names.
213 bool ModuleBase_ParamSpinBox::isAcceptVariables() const
215 return myAcceptVariables;
218 bool ModuleBase_ParamSpinBox::hasVariable() const
223 bool ModuleBase_ParamSpinBox::hasVariable(const QString& theText) const
225 bool isDouble = false;
226 QLocale::c().toDouble(theText, &isDouble);
231 // \brief This function is used to determine whether input is valid.
232 // \return validating operation result
234 //ModuleBase_ParamSpinBox::State ModuleBase_ParamSpinBox::isValid(const QString& theText,
235 // double& theValue) const
237 // if (hasVariable() && !findVariable(theText, theValue)) {
239 // theValue = locale().toDouble(theText, &ok);
241 // return NoVariable;
244 // if (!checkRange(theValue)) {
248 // return Acceptable;
252 // \brief This function is used to check that string value lies within predefined range.
253 // \return check status
255 //bool ModuleBase_ParamSpinBox::checkRange(const double theValue) const
257 // return theValue >= minimum() && theValue <= maximum();
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
264 //bool ModuleBase_ParamSpinBox::findVariable(const QString& theName,
265 // double& outValue) const
267 // ResultParameterPtr aParam;
268 // return ModelAPI_Tools::findVariable(FeaturePtr(), theName.toStdString(), outValue, aParam);
271 void ModuleBase_ParamSpinBox::keyReleaseEvent(QKeyEvent* e)
278 if (myCompleter->popup()->isVisible()) {
279 myCompleter->popup()->hide();
282 emit textChanged(lineEdit()->text());
286 if (e->modifiers() & Qt::ControlModifier) {
287 myCompletePos = lineEdit()->cursorPosition();
289 QString aPrefix = getPrefix(aStart, aEnd);
290 myCompleter->setCompletionPrefix(aPrefix);
291 myCompleter->complete();
295 QAbstractSpinBox::keyReleaseEvent(e);
300 QString ModuleBase_ParamSpinBox::getPrefix(int& theStart, int& theEnd) const
303 QString aText = lineEdit()->text();
304 theStart = theEnd = myCompletePos;
305 const int aLen = aText.length();
307 if (myCompletePos > 0) {
308 int aLastChar = myCompletePos - 1;
309 QChar aChar = aText.at(aLastChar);
310 while (aChar.isLetter() || aChar.isDigit()) {
311 aPrefix.prepend(aText.at(aLastChar));
315 aChar = aText.at(aLastChar);
317 theStart = aLastChar + 1;
319 if (myCompletePos < aLen) {
320 int aLastChar = myCompletePos;
321 QChar aChar = aText.at(aLastChar);
322 while (aChar.isLetter() || aChar.isDigit()) {
323 aPrefix.append(aText.at(aLastChar));
325 if (aLastChar >= aLen)
327 aChar = aText.at(aLastChar);
336 void ModuleBase_ParamSpinBox::insertCompletion(const QString& theText)
338 QString aText = lineEdit()->text();
340 QString aPrefix = getPrefix(aStart, aEnd);
343 int aPrefLen = aPrefix.length();
345 aResult = aText.insert(myCompletePos, theText);
347 aResult = aText.left(aStart) + theText + aText.right(aText.length() - aEnd);
349 lineEdit()->setText(aResult);
355 // \brief This function is called when the spinbox receives show event.
357 //void ModuleBase_ParamSpinBox::showEvent(QShowEvent* theEvent)
359 // ModuleBase_DoubleSpinBox::showEvent(theEvent);
360 // if ((!myTextValue.isEmpty()) && hasVariable(myTextValue)) {
361 // setText(myTextValue);
365 void ModuleBase_ParamSpinBox::setValueEnabled(bool theEnable)
367 setReadOnly(!theEnable);
369 QPalette aPal = palette();
370 aPal.setColor(QPalette::All, QPalette::Base,
371 theEnable ? myEnabledBaseColor : aPal.color(QPalette::Disabled, QPalette::Base));