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>
39 bool isVariableSymbol(const QChar& theChar) {
40 if (theChar.isLetterOrNumber())
47 ModuleBase_ParamSpinBox::ModuleBase_ParamSpinBox(QWidget* theParent, int thePrecision)
48 : QAbstractSpinBox(theParent),
49 myPrecision(thePrecision),
51 myAcceptVariables(true),
56 myCompleter = new QCompleter(this);
57 myCompleter->setWidget(lineEdit());
58 myCompleter->setCompletionMode(QCompleter::PopupCompletion);
60 myCompleterModel = new QStringListModel(this);
61 myCompleter->setModel(myCompleterModel);
62 connect(myCompleter, SIGNAL(highlighted(const QString&)),
63 this, SLOT(insertCompletion(const QString&)));
65 QAbstractItemView* aPopup = myCompleter->popup();
66 aPopup->installEventFilter(this);
68 // connectSignalsAndSlots();
69 myEnabledBaseColor = palette().color(QPalette::Active, QPalette::Base);
70 connect(lineEdit(), SIGNAL(textChanged(const QString&)),
71 this, SLOT(onTextChanged(const QString&)));
73 setLocale(QLocale::c());
75 myValidator = new QDoubleValidator(this);
76 myValidator->setLocale(locale());
77 myValidator->setRange(myMinimum, myMaximum);
78 myValidator->setDecimals(myPrecision);
81 void ModuleBase_ParamSpinBox::setCompletionList(QStringList& theList)
83 theList.removeDuplicates();
85 myCompleterModel->setStringList(theList);
91 ModuleBase_ParamSpinBox::~ModuleBase_ParamSpinBox()
97 \brief Perform \a steps increment/decrement steps.
99 Re-implemented to handle cases when Notebook variable
100 name is specified by the user as the widget text.
101 Otherwise, simply calls the base implementation.
103 \param steps number of increment/decrement steps
105 void ModuleBase_ParamSpinBox::stepBy(int steps)
110 double aVal = lineEdit()->text().toDouble();
111 aVal += steps * mySingleStep;
113 //QAbstractSpinBox::stepBy(steps);
116 void ModuleBase_ParamSpinBox::onTextChanged(const QString& theText)
118 myIsEquation = hasVariable(theText);
119 emit textChanged(theText);
124 \brief This function is used to determine whether input is valid.
125 \param str currently entered value
126 \param pos cursor position in the string
127 \return validating operation result
129 QValidator::State ModuleBase_ParamSpinBox::validate(QString& str, int& pos) const
131 // Trying to interpret the current input text as a numeric value
132 if (!hasVariable(str)) {
133 /// If decimals = 0 do not accept '.' (interpret as int)
134 if ((myValidator->decimals() == 0) && str.endsWith('.'))
135 return QValidator::Invalid;
136 return myValidator->validate(str, pos);
139 return isAcceptVariables() ? QValidator::Acceptable : QValidator::Invalid;
143 \brief This function is used to set a current value for this spinbox.
144 \param value current value
146 The new value is ignored if the spinbox has a variable.
148 void ModuleBase_ParamSpinBox::setValue(double value)
150 myIsEquation = false;
152 if (aVal < myMinimum)
154 else if (aVal > myMaximum)
156 QString aText = QString::number(aVal, 'g', decimals());
157 lineEdit()->blockSignals(true);
158 lineEdit()->setText(aText);
159 lineEdit()->blockSignals(false);
160 emit textChanged(aText);
163 double ModuleBase_ParamSpinBox::value() const
165 return lineEdit()->text().toDouble();
169 \brief This function is used to set a text for this spinbox.
170 \param value current value
172 void ModuleBase_ParamSpinBox::setText(const QString& value)
174 myIsEquation = hasVariable(value);
175 if (myAcceptVariables && myIsEquation) {
176 lineEdit()->setText(value);
177 emit textChanged(value);
182 \brief Enables or disables variable names in the spin box.
183 By default, variable names are enabled.
184 \param flag If true, variable names are enabled.
186 void ModuleBase_ParamSpinBox::setAcceptVariables(const bool flag)
188 myAcceptVariables = flag;
189 if ((!myAcceptVariables) && myIsEquation) {
195 \brief Returns true if the spin box accepts variable names.
197 bool ModuleBase_ParamSpinBox::isAcceptVariables() const
199 return myAcceptVariables;
202 bool ModuleBase_ParamSpinBox::hasVariable() const
207 bool ModuleBase_ParamSpinBox::hasVariable(const QString& theText) const
209 bool isDouble = false;
210 QLocale::c().toDouble(theText, &isDouble);
214 void ModuleBase_ParamSpinBox::showCompletion(bool checkPrefix)
216 myCompletePos = lineEdit()->cursorPosition();
219 aPrefix = getPrefix(aStart, aEnd);
221 if (aPrefix.length() > 0) {
222 myCompleter->setCompletionPrefix(aPrefix);
223 myCompleter->complete();
226 myCompleter->setCompletionPrefix(aPrefix);
227 myCompleter->complete();
231 void ModuleBase_ParamSpinBox::keyReleaseEvent(QKeyEvent* e)
236 case Qt::Key_Backspace:
237 if (myCompleter->popup()->isVisible()) {
238 myCompleter->popup()->hide();
240 showCompletion(true);
244 if (myCompleter->popup()->isVisible()) {
245 myCompleter->popup()->hide();
248 emit textChanged(lineEdit()->text());
251 if (e->modifiers() & Qt::ControlModifier) {
252 showCompletion(false);
256 if (aText.length() == 1) {
257 QChar aChar = aText.at(0);
258 if (isVariableSymbol(aChar)) {
259 showCompletion(true);
263 QAbstractSpinBox::keyReleaseEvent(e);
266 bool ModuleBase_ParamSpinBox::eventFilter(QObject* theObj, QEvent* theEvent)
268 if (theEvent->type() == QEvent::KeyRelease) {
269 keyReleaseEvent((QKeyEvent*)theEvent);
271 return QAbstractSpinBox::eventFilter(theObj, theEvent);
275 QString ModuleBase_ParamSpinBox::getPrefix(int& theStart, int& theEnd) const
278 QString aText = lineEdit()->text();
279 theStart = theEnd = myCompletePos;
280 const int aLen = aText.length();
282 if (myCompletePos > 0) {
283 int aLastChar = myCompletePos - 1;
284 QChar aChar = aText.at(aLastChar);
285 while (isVariableSymbol(aChar)) {
286 aPrefix.prepend(aText.at(aLastChar));
290 aChar = aText.at(aLastChar);
292 theStart = aLastChar + 1;
294 if (myCompletePos < aLen) {
295 int aLastChar = myCompletePos;
296 QChar aChar = aText.at(aLastChar);
297 while (isVariableSymbol(aChar)) {
298 aPrefix.append(aText.at(aLastChar));
300 if (aLastChar >= aLen)
302 aChar = aText.at(aLastChar);
311 void ModuleBase_ParamSpinBox::insertCompletion(const QString& theText)
313 QString aText = lineEdit()->text();
315 QString aPrefix = getPrefix(aStart, aEnd);
318 int aPrefLen = aPrefix.length();
320 aResult = aText.insert(myCompletePos, theText);
322 aResult = aText.left(aStart) + theText + aText.right(aText.length() - aEnd);
324 lineEdit()->setText(aResult);
329 void ModuleBase_ParamSpinBox::setValueEnabled(bool theEnable)
331 setReadOnly(!theEnable);
333 QPalette aPal = palette();
334 aPal.setColor(QPalette::All, QPalette::Base,
335 theEnable ? myEnabledBaseColor : aPal.color(QPalette::Disabled, QPalette::Base));