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()->setText(aText);
158 emit textChanged(aText);
161 double ModuleBase_ParamSpinBox::value() const
163 return lineEdit()->text().toDouble();
167 \brief This function is used to set a text for this spinbox.
168 \param value current value
170 void ModuleBase_ParamSpinBox::setText(const QString& value)
172 myIsEquation = hasVariable(value);
173 if (myAcceptVariables && myIsEquation) {
174 lineEdit()->setText(value);
175 emit textChanged(value);
180 \brief Enables or disables variable names in the spin box.
181 By default, variable names are enabled.
182 \param flag If true, variable names are enabled.
184 void ModuleBase_ParamSpinBox::setAcceptVariables(const bool flag)
186 myAcceptVariables = flag;
187 if ((!myAcceptVariables) && myIsEquation) {
193 \brief Returns true if the spin box accepts variable names.
195 bool ModuleBase_ParamSpinBox::isAcceptVariables() const
197 return myAcceptVariables;
200 bool ModuleBase_ParamSpinBox::hasVariable() const
205 bool ModuleBase_ParamSpinBox::hasVariable(const QString& theText) const
207 bool isDouble = false;
208 QLocale::c().toDouble(theText, &isDouble);
212 void ModuleBase_ParamSpinBox::showCompletion(bool checkPrefix)
214 myCompletePos = lineEdit()->cursorPosition();
217 aPrefix = getPrefix(aStart, aEnd);
219 if (aPrefix.length() > 0) {
220 myCompleter->setCompletionPrefix(aPrefix);
221 myCompleter->complete();
224 myCompleter->setCompletionPrefix(aPrefix);
225 myCompleter->complete();
229 void ModuleBase_ParamSpinBox::keyReleaseEvent(QKeyEvent* e)
234 case Qt::Key_Backspace:
235 if (myCompleter->popup()->isVisible()) {
236 myCompleter->popup()->hide();
238 showCompletion(true);
242 if (myCompleter->popup()->isVisible()) {
243 myCompleter->popup()->hide();
246 emit textChanged(lineEdit()->text());
249 if (e->modifiers() & Qt::ControlModifier) {
250 showCompletion(false);
254 if (aText.length() == 1) {
255 QChar aChar = aText.at(0);
256 if (isVariableSymbol(aChar)) {
257 showCompletion(true);
261 QAbstractSpinBox::keyReleaseEvent(e);
264 bool ModuleBase_ParamSpinBox::eventFilter(QObject* theObj, QEvent* theEvent)
266 if (theEvent->type() == QEvent::KeyRelease) {
267 keyReleaseEvent((QKeyEvent*)theEvent);
269 return QAbstractSpinBox::eventFilter(theObj, theEvent);
273 QString ModuleBase_ParamSpinBox::getPrefix(int& theStart, int& theEnd) const
276 QString aText = lineEdit()->text();
277 theStart = theEnd = myCompletePos;
278 const int aLen = aText.length();
280 if (myCompletePos > 0) {
281 int aLastChar = myCompletePos - 1;
282 QChar aChar = aText.at(aLastChar);
283 while (isVariableSymbol(aChar)) {
284 aPrefix.prepend(aText.at(aLastChar));
288 aChar = aText.at(aLastChar);
290 theStart = aLastChar + 1;
292 if (myCompletePos < aLen) {
293 int aLastChar = myCompletePos;
294 QChar aChar = aText.at(aLastChar);
295 while (isVariableSymbol(aChar)) {
296 aPrefix.append(aText.at(aLastChar));
298 if (aLastChar >= aLen)
300 aChar = aText.at(aLastChar);
309 void ModuleBase_ParamSpinBox::insertCompletion(const QString& theText)
311 QString aText = lineEdit()->text();
313 QString aPrefix = getPrefix(aStart, aEnd);
316 int aPrefLen = aPrefix.length();
318 aResult = aText.insert(myCompletePos, theText);
320 aResult = aText.left(aStart) + theText + aText.right(aText.length() - aEnd);
322 lineEdit()->setText(aResult);
327 void ModuleBase_ParamSpinBox::setValueEnabled(bool theEnable)
329 setReadOnly(!theEnable);
331 QPalette aPal = palette();
332 aPal.setColor(QPalette::All, QPalette::Base,
333 theEnable ? myEnabledBaseColor : aPal.color(QPalette::Disabled, QPalette::Base));