1 // Copyright (C) 2014-2020 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);
85 QAbstractItemView* aPopup = myCompleter->popup();
86 QFontMetrics aMetric = aPopup->fontMetrics();
89 foreach(QString aStr, theList) {
90 aRect = aMetric.boundingRect(aStr);
91 if (aRect.width() > aWidth)
92 aWidth = aRect.width();
94 aPopup->setMinimumWidth(aWidth + 25);
100 ModuleBase_ParamSpinBox::~ModuleBase_ParamSpinBox()
106 \brief Perform \a steps increment/decrement steps.
108 Re-implemented to handle cases when Notebook variable
109 name is specified by the user as the widget text.
110 Otherwise, simply calls the base implementation.
112 \param steps number of increment/decrement steps
114 void ModuleBase_ParamSpinBox::stepBy(int steps)
119 double aVal = lineEdit()->text().toDouble();
120 aVal += steps * mySingleStep;
122 //QAbstractSpinBox::stepBy(steps);
125 void ModuleBase_ParamSpinBox::onTextChanged(const QString& theText)
127 myIsEquation = hasVariable(theText);
128 emit textChanged(theText);
133 \brief This function is used to determine whether input is valid.
134 \param str currently entered value
135 \param pos cursor position in the string
136 \return validating operation result
138 QValidator::State ModuleBase_ParamSpinBox::validate(QString& str, int& pos) const
140 // Trying to interpret the current input text as a numeric value
141 if (!hasVariable(str)) {
142 /// If decimals = 0 do not accept '.' (interpret as int)
143 if ((myValidator->decimals() == 0) && str.endsWith('.'))
144 return QValidator::Invalid;
145 return myValidator->validate(str, pos);
148 return isAcceptVariables() ? QValidator::Acceptable : QValidator::Invalid;
152 \brief This function is used to set a current value for this spinbox.
153 \param value current value
155 The new value is ignored if the spinbox has a variable.
157 void ModuleBase_ParamSpinBox::setValue(double value)
159 myIsEquation = false;
161 if (aVal < myMinimum)
163 else if (aVal > myMaximum)
165 QString aText = (myValidator->decimals() == 0) ? QString::number((int)aVal) :
166 QString::number(aVal, 'g', decimals());
167 lineEdit()->blockSignals(true);
168 lineEdit()->setText(aText);
169 lineEdit()->blockSignals(false);
170 emit textChanged(aText);
173 double ModuleBase_ParamSpinBox::value() const
175 return lineEdit()->text().toDouble();
179 \brief This function is used to set a text for this spinbox.
180 \param value current value
182 void ModuleBase_ParamSpinBox::setText(const QString& value)
184 myIsEquation = hasVariable(value);
185 if (myAcceptVariables && myIsEquation) {
186 lineEdit()->setText(value);
187 emit textChanged(value);
191 double aVal = value.toDouble(&isConv);
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);
230 void ModuleBase_ParamSpinBox::showCompletion(bool checkPrefix)
232 myCompletePos = lineEdit()->cursorPosition();
235 aPrefix = getPrefix(aStart, aEnd);
237 if (aPrefix.length() > 0) {
238 myCompleter->setCompletionPrefix(aPrefix);
239 myCompleter->complete();
242 myCompleter->setCompletionPrefix(aPrefix);
243 myCompleter->complete();
247 void ModuleBase_ParamSpinBox::keyReleaseEvent(QKeyEvent* e)
252 case Qt::Key_Backspace:
253 if (myCompleter->popup()->isVisible()) {
254 myCompleter->popup()->hide();
256 showCompletion(true);
260 if (myCompleter->popup()->isVisible()) {
261 myCompleter->popup()->hide();
264 emit textChanged(lineEdit()->text());
267 if (e->modifiers() & Qt::ControlModifier) {
268 showCompletion(false);
272 if (aText.length() == 1) {
273 QChar aChar = aText.at(0);
274 if (isVariableSymbol(aChar)) {
275 showCompletion(true);
279 QAbstractSpinBox::keyReleaseEvent(e);
282 bool ModuleBase_ParamSpinBox::eventFilter(QObject* theObj, QEvent* theEvent)
284 if (theEvent->type() == QEvent::KeyRelease) {
285 keyReleaseEvent((QKeyEvent*)theEvent);
287 return QAbstractSpinBox::eventFilter(theObj, theEvent);
291 QString ModuleBase_ParamSpinBox::getPrefix(int& theStart, int& theEnd) const
294 QString aText = lineEdit()->text();
295 theStart = theEnd = myCompletePos;
296 const int aLen = aText.length();
298 if (myCompletePos > 0) {
299 int aLastChar = myCompletePos - 1;
300 QChar aChar = aText.at(aLastChar);
301 while (isVariableSymbol(aChar)) {
302 aPrefix.prepend(aText.at(aLastChar));
306 aChar = aText.at(aLastChar);
308 theStart = aLastChar + 1;
310 if (myCompletePos < aLen) {
311 int aLastChar = myCompletePos;
312 QChar aChar = aText.at(aLastChar);
313 while (isVariableSymbol(aChar)) {
314 aPrefix.append(aText.at(aLastChar));
316 if (aLastChar >= aLen)
318 aChar = aText.at(aLastChar);
327 void ModuleBase_ParamSpinBox::insertCompletion(const QString& theText)
329 QString aText = lineEdit()->text();
331 QString aPrefix = getPrefix(aStart, aEnd);
334 int aPrefLen = aPrefix.length();
336 aResult = aText.insert(myCompletePos, theText);
338 aResult = aText.left(aStart) + theText + aText.right(aText.length() - aEnd);
340 lineEdit()->setText(aResult);
345 void ModuleBase_ParamSpinBox::setValueEnabled(bool theEnable)
347 setReadOnly(!theEnable);
349 QPalette aPal = palette();
350 aPal.setColor(QPalette::All, QPalette::Base,
351 theEnable ? myEnabledBaseColor : aPal.color(QPalette::Disabled, QPalette::Base));