1 // Copyright (C) 2014-2019 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 email : webmaster.salome@opencascade.com
20 #include "ModuleBase_ParamSpinBox.h"
26 #include <QApplication>
28 #include <QStringListModel>
30 #include <QAbstractItemView>
38 bool isVariableSymbol(const QChar& theChar) {
39 if (theChar.isLetterOrNumber())
46 ModuleBase_ParamSpinBox::ModuleBase_ParamSpinBox(QWidget* theParent, int thePrecision)
47 : QAbstractSpinBox(theParent),
49 myAcceptVariables(true),
54 myCompleter = new QCompleter(this);
55 myCompleter->setWidget(lineEdit());
56 myCompleter->setCompletionMode(QCompleter::PopupCompletion);
58 myCompleterModel = new QStringListModel(this);
59 myCompleter->setModel(myCompleterModel);
60 connect(myCompleter, SIGNAL(highlighted(const QString&)),
61 this, SLOT(insertCompletion(const QString&)));
63 QAbstractItemView* aPopup = myCompleter->popup();
64 aPopup->installEventFilter(this);
66 // connectSignalsAndSlots();
67 myEnabledBaseColor = palette().color(QPalette::Active, QPalette::Base);
68 connect(lineEdit(), SIGNAL(textChanged(const QString&)),
69 this, SLOT(onTextChanged(const QString&)));
71 setLocale(QLocale::c());
73 myValidator = new QDoubleValidator(this);
74 myValidator->setLocale(locale());
75 myValidator->setRange(myMinimum, myMaximum);
76 myValidator->setDecimals(thePrecision);
79 void ModuleBase_ParamSpinBox::setCompletionList(QStringList& theList)
81 theList.removeDuplicates();
83 myCompleterModel->setStringList(theList);
89 ModuleBase_ParamSpinBox::~ModuleBase_ParamSpinBox()
95 \brief Perform \a steps increment/decrement steps.
97 Re-implemented to handle cases when Notebook variable
98 name is specified by the user as the widget text.
99 Otherwise, simply calls the base implementation.
101 \param steps number of increment/decrement steps
103 void ModuleBase_ParamSpinBox::stepBy(int steps)
108 double aVal = lineEdit()->text().toDouble();
109 aVal += steps * mySingleStep;
111 //QAbstractSpinBox::stepBy(steps);
114 void ModuleBase_ParamSpinBox::onTextChanged(const QString& theText)
116 myIsEquation = hasVariable(theText);
117 emit textChanged(theText);
122 \brief This function is used to determine whether input is valid.
123 \param str currently entered value
124 \param pos cursor position in the string
125 \return validating operation result
127 QValidator::State ModuleBase_ParamSpinBox::validate(QString& str, int& pos) const
129 // Trying to interpret the current input text as a numeric value
130 if (!hasVariable(str)) {
131 /// If decimals = 0 do not accept '.' (interpret as int)
132 if ((myValidator->decimals() == 0) && str.endsWith('.'))
133 return QValidator::Invalid;
134 return myValidator->validate(str, pos);
137 return isAcceptVariables() ? QValidator::Acceptable : QValidator::Invalid;
141 \brief This function is used to set a current value for this spinbox.
142 \param value current value
144 The new value is ignored if the spinbox has a variable.
146 void ModuleBase_ParamSpinBox::setValue(double value)
148 myIsEquation = false;
150 if (aVal < myMinimum)
152 else if (aVal > myMaximum)
154 QString aText = (myValidator->decimals() == 0) ? QString::number((int)aVal) :
155 QString::number(aVal, 'g', decimals());
156 lineEdit()->blockSignals(true);
157 lineEdit()->setText(aText);
158 lineEdit()->blockSignals(false);
159 emit textChanged(aText);
162 double ModuleBase_ParamSpinBox::value() const
164 return lineEdit()->text().toDouble();
168 \brief This function is used to set a text for this spinbox.
169 \param value current value
171 void ModuleBase_ParamSpinBox::setText(const QString& value)
173 myIsEquation = hasVariable(value);
174 if (myAcceptVariables && myIsEquation) {
175 lineEdit()->setText(value);
176 emit textChanged(value);
180 double aVal = value.toDouble(&isConv);
187 \brief Enables or disables variable names in the spin box.
188 By default, variable names are enabled.
189 \param flag If true, variable names are enabled.
191 void ModuleBase_ParamSpinBox::setAcceptVariables(const bool flag)
193 myAcceptVariables = flag;
194 if ((!myAcceptVariables) && myIsEquation) {
200 \brief Returns true if the spin box accepts variable names.
202 bool ModuleBase_ParamSpinBox::isAcceptVariables() const
204 return myAcceptVariables;
207 bool ModuleBase_ParamSpinBox::hasVariable() const
212 bool ModuleBase_ParamSpinBox::hasVariable(const QString& theText) const
214 bool isDouble = false;
215 QLocale::c().toDouble(theText, &isDouble);
219 void ModuleBase_ParamSpinBox::showCompletion(bool checkPrefix)
221 myCompletePos = lineEdit()->cursorPosition();
224 aPrefix = getPrefix(aStart, aEnd);
226 if (aPrefix.length() > 0) {
227 myCompleter->setCompletionPrefix(aPrefix);
228 myCompleter->complete();
231 myCompleter->setCompletionPrefix(aPrefix);
232 myCompleter->complete();
236 void ModuleBase_ParamSpinBox::keyReleaseEvent(QKeyEvent* e)
241 case Qt::Key_Backspace:
242 if (myCompleter->popup()->isVisible()) {
243 myCompleter->popup()->hide();
245 showCompletion(true);
249 if (myCompleter->popup()->isVisible()) {
250 myCompleter->popup()->hide();
253 emit textChanged(lineEdit()->text());
256 if (e->modifiers() & Qt::ControlModifier) {
257 showCompletion(false);
261 if (aText.length() == 1) {
262 QChar aChar = aText.at(0);
263 if (isVariableSymbol(aChar)) {
264 showCompletion(true);
268 QAbstractSpinBox::keyReleaseEvent(e);
271 bool ModuleBase_ParamSpinBox::eventFilter(QObject* theObj, QEvent* theEvent)
273 if (theEvent->type() == QEvent::KeyRelease) {
274 keyReleaseEvent((QKeyEvent*)theEvent);
276 return QAbstractSpinBox::eventFilter(theObj, theEvent);
280 QString ModuleBase_ParamSpinBox::getPrefix(int& theStart, int& theEnd) const
283 QString aText = lineEdit()->text();
284 theStart = theEnd = myCompletePos;
285 const int aLen = aText.length();
287 if (myCompletePos > 0) {
288 int aLastChar = myCompletePos - 1;
289 QChar aChar = aText.at(aLastChar);
290 while (isVariableSymbol(aChar)) {
291 aPrefix.prepend(aText.at(aLastChar));
295 aChar = aText.at(aLastChar);
297 theStart = aLastChar + 1;
299 if (myCompletePos < aLen) {
300 int aLastChar = myCompletePos;
301 QChar aChar = aText.at(aLastChar);
302 while (isVariableSymbol(aChar)) {
303 aPrefix.append(aText.at(aLastChar));
305 if (aLastChar >= aLen)
307 aChar = aText.at(aLastChar);
316 void ModuleBase_ParamSpinBox::insertCompletion(const QString& theText)
318 QString aText = lineEdit()->text();
320 QString aPrefix = getPrefix(aStart, aEnd);
323 int aPrefLen = aPrefix.length();
325 aResult = aText.insert(myCompletePos, theText);
327 aResult = aText.left(aStart) + theText + aText.right(aText.length() - aEnd);
329 lineEdit()->setText(aResult);
334 void ModuleBase_ParamSpinBox::setValueEnabled(bool theEnable)
336 setReadOnly(!theEnable);
338 QPalette aPal = palette();
339 aPal.setColor(QPalette::All, QPalette::Base,
340 theEnable ? myEnabledBaseColor : aPal.color(QPalette::Disabled, QPalette::Base));