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"
23 #include <ModelAPI_Session.h>
24 #include <ModelAPI_Document.h>
25 #include <ModelAPI_Feature.h>
26 #include <ModelAPI_ResultParameter.h>
27 #include <ModelAPI_AttributeDouble.h>
28 #include <ModelAPI_Tools.h>
34 #include <QApplication>
36 #include <QStringListModel>
38 #include <QAbstractItemView>
44 ModuleBase_ParamSpinBox::ModuleBase_ParamSpinBox(QWidget* theParent, int thePrecision)
45 : QAbstractSpinBox(theParent),
46 myPrecision(thePrecision),
48 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 // Use sorted model to accelerate completion (QCompleter will use binary search)
61 myCompleter->setModelSorting(QCompleter::CaseInsensitivelySortedModel);
62 myCompleter->setCaseSensitivity(Qt::CaseInsensitive);
63 connect(myCompleter, SIGNAL(highlighted(const QString&)),
64 this, SLOT(insertCompletion(const QString&)));
66 // connectSignalsAndSlots();
67 myEnabledBaseColor = palette().color(QPalette::Active, QPalette::Base);
68 connect(lineEdit(), SIGNAL(textChanged(const QString&)),
69 this, SLOT(onTextChanged(const QString&)));
71 myValidator = new QDoubleValidator(this);
72 myValidator->setLocale(locale());
73 myValidator->setRange(myMinimum, myMaximum);
76 void ModuleBase_ParamSpinBox::setCompletionList(QStringList& theList)
79 theList.removeDuplicates();
80 myCompleterModel->setStringList(theList);
86 ModuleBase_ParamSpinBox::~ModuleBase_ParamSpinBox()
91 \brief Perform \a steps increment/decrement steps.
93 Re-implemented to handle cases when Notebook variable
94 name is specified by the user as the widget text.
95 Otherwise, simply calls the base implementation.
97 \param steps number of increment/decrement steps
99 void ModuleBase_ParamSpinBox::stepBy(int steps)
104 double aVal = lineEdit()->text().toDouble();
105 aVal += steps * mySingleStep;
107 QAbstractSpinBox::stepBy(steps);
110 void ModuleBase_ParamSpinBox::onTextChanged(const QString& theText)
112 myIsEquation = hasVariable(theText);
113 emit textChanged(theText);
118 // \brief Connect signals and slots.
120 //void ModuleBase_ParamSpinBox::connectSignalsAndSlots()
122 // connect(this, SIGNAL(valueChanged(const QString&)),
123 // this, SLOT(onTextChanged(const QString&)));
126 //void ModuleBase_ParamSpinBox::onTextChanged(const QString& text)
128 // myTextValue = text;
129 // emit textChanged(text);
132 //double ModuleBase_ParamSpinBox::valueFromText(const QString& theText) const
134 // if (!hasVariable(theText))
135 // return ModuleBase_DoubleSpinBox::valueFromText(theText);
137 // // small hack: return hash of the string to initiate valuesChanged signal
138 // return qHash(theText);
141 //QString ModuleBase_ParamSpinBox::textFromValue (double theValue) const
143 // if ((!myTextValue.isEmpty()) && hasVariable(myTextValue)){
144 // return myTextValue;
146 // return ModuleBase_DoubleSpinBox::textFromValue(theValue);
150 \brief This function is used to determine whether input is valid.
151 \param str currently entered value
152 \param pos cursor position in the string
153 \return validating operation result
155 QValidator::State ModuleBase_ParamSpinBox::validate(QString& str, int& pos) const
157 // Trying to interpret the current input text as a numeric value
158 if (!hasVariable(str))
159 return myValidator->validate(str, pos);
161 return isAcceptVariables() ? QValidator::Acceptable : QValidator::Invalid;
165 \brief This function is used to set a current value for this spinbox.
166 \param value current value
168 The new value is ignored if the spinbox has a variable.
170 void ModuleBase_ParamSpinBox::setValue(double value)
172 myIsEquation = false;
174 if (aVal < myMinimum)
176 else if (aVal > myMaximum)
178 QString aText = QString::number(aVal, 'g', myDecimals);
179 lineEdit()->setText(aText);
180 emit textChanged(aText);
183 double ModuleBase_ParamSpinBox::value() const
185 //if (myIsEquation) {
188 return lineEdit()->text().toDouble();
192 \brief This function is used to set a text for this spinbox.
193 \param value current value
195 void ModuleBase_ParamSpinBox::setText(const QString& value)
197 myIsEquation = hasVariable(value);
198 if (myAcceptVariables && myIsEquation) {
199 lineEdit()->setText(value);
200 emit textChanged(value);
205 \brief Enables or disables variable names in the spin box.
206 By default, variable names are enabled.
207 \param flag If true, variable names are enabled.
209 void ModuleBase_ParamSpinBox::setAcceptVariables(const bool flag)
211 myAcceptVariables = flag;
212 if ((!myAcceptVariables) && myIsEquation) {
218 \brief Returns true if the spin box accepts variable names.
220 bool ModuleBase_ParamSpinBox::isAcceptVariables() const
222 return myAcceptVariables;
225 bool ModuleBase_ParamSpinBox::hasVariable() const
230 bool ModuleBase_ParamSpinBox::hasVariable(const QString& theText) const
232 bool isDouble = false;
233 QLocale::c().toDouble(theText, &isDouble);
238 // \brief This function is used to determine whether input is valid.
239 // \return validating operation result
241 //ModuleBase_ParamSpinBox::State ModuleBase_ParamSpinBox::isValid(const QString& theText,
242 // double& theValue) const
244 // if (hasVariable() && !findVariable(theText, theValue)) {
246 // theValue = locale().toDouble(theText, &ok);
248 // return NoVariable;
251 // if (!checkRange(theValue)) {
255 // return Acceptable;
259 // \brief This function is used to check that string value lies within predefined range.
260 // \return check status
262 //bool ModuleBase_ParamSpinBox::checkRange(const double theValue) const
264 // return theValue >= minimum() && theValue <= maximum();
268 // \brief This function is used to determine whether input is a variable name and to get its value.
269 // \return status of search operation
271 //bool ModuleBase_ParamSpinBox::findVariable(const QString& theName,
272 // double& outValue) const
274 // ResultParameterPtr aParam;
275 // return ModelAPI_Tools::findVariable(FeaturePtr(), theName.toStdString(), outValue, aParam);
279 \brief This function is called when the spinbox receives key press event.
281 void ModuleBase_ParamSpinBox::keyReleaseEvent(QKeyEvent* e)
286 if (myCompleter->popup()->isVisible()) {
287 myCompleter->popup()->hide();
290 emit textChanged(lineEdit()->text());
293 if (e->modifiers() & Qt::ControlModifier) {
294 myCompletePos = lineEdit()->cursorPosition();
296 QString aPrefix = getPrefix(aStart, aEnd);
297 myCompleter->setCompletionPrefix(aPrefix);
298 myCompleter->complete();
302 QAbstractSpinBox::keyReleaseEvent(e);
306 QString ModuleBase_ParamSpinBox::getPrefix(int& theStart, int& theEnd) const
309 QString aText = lineEdit()->text();
310 theStart = theEnd = myCompletePos;
311 const int aLen = aText.length();
313 if (myCompletePos > 0) {
314 int aLastChar = myCompletePos - 1;
315 QChar aChar = aText.at(aLastChar);
316 while (aChar.isLetter() || aChar.isDigit()) {
317 aPrefix.prepend(aText.at(aLastChar));
321 aChar = aText.at(aLastChar);
323 theStart = aLastChar + 1;
325 if (myCompletePos < aLen) {
326 int aLastChar = myCompletePos;
327 QChar aChar = aText.at(aLastChar);
328 while (aChar.isLetter() || aChar.isDigit()) {
329 aPrefix.append(aText.at(aLastChar));
331 if (aLastChar >= aLen)
333 aChar = aText.at(aLastChar);
342 void ModuleBase_ParamSpinBox::insertCompletion(const QString& theText)
344 QString aText = lineEdit()->text();
346 QString aPrefix = getPrefix(aStart, aEnd);
349 int aPrefLen = aPrefix.length();
351 aResult = aText.insert(myCompletePos, theText);
353 aResult = aText.left(aStart) + theText + aText.right(aText.length() - aEnd);
355 lineEdit()->setText(aResult);
358 qDebug("### aPos=%i", myCompletePos);
359 qDebug("### text=%s", qPrintable(aText));
360 qDebug("### prefix=%s", qPrintable(aPrefix));
361 qDebug("### result=%s", qPrintable(aResult));
366 // \brief This function is called when the spinbox receives show event.
368 //void ModuleBase_ParamSpinBox::showEvent(QShowEvent* theEvent)
370 // ModuleBase_DoubleSpinBox::showEvent(theEvent);
371 // if ((!myTextValue.isEmpty()) && hasVariable(myTextValue)) {
372 // setText(myTextValue);
376 void ModuleBase_ParamSpinBox::setValueEnabled(bool theEnable)
378 setReadOnly(!theEnable);
380 QPalette aPal = palette();
381 aPal.setColor(QPalette::All, QPalette::Base,
382 theEnable ? myEnabledBaseColor : aPal.color(QPalette::Disabled, QPalette::Base));