1
/***************************************************************************
2
* Copyright (c) 2014 Werner Mayer <wmayer[at]users.sourceforge.net> *
4
* This file is part of the FreeCAD CAx development system. *
6
* This library is free software; you can redistribute it and/or *
7
* modify it under the terms of the GNU Library General Public *
8
* License as published by the Free Software Foundation; either *
9
* version 2 of the License, or (at your option) any later version. *
11
* This library is distributed in the hope that it will be useful, *
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14
* GNU Library General Public License for more details. *
16
* You should have received a copy of the GNU Library General Public *
17
* License along with this library; see the file COPYING.LIB. If not, *
18
* write to the Free Software Foundation, Inc., 51 Franklin Street, *
19
* Fifth Floor, Boston, MA 02110-1301, USA *
21
***************************************************************************/
24
#include "PreCompiled.h"
26
# include <QApplication>
28
# include <QFocusEvent>
29
# include <QFontMetrics>
31
# include <QRegularExpression>
32
# include <QRegularExpressionMatch>
34
# include <QStyleOptionSpinBox>
40
#include <App/Application.h>
41
#include <App/Document.h>
42
#include <App/DocumentObject.h>
43
#include <App/ExpressionParser.h>
44
#include <Base/Exception.h>
45
#include <Base/UnitsApi.h>
46
#include <Base/Tools.h>
48
#include "QuantitySpinBox.h"
49
#include "QuantitySpinBox_p.h"
51
#include "DlgExpressionInput.h"
61
class QuantitySpinBoxPrivate
64
QuantitySpinBoxPrivate(QuantitySpinBox *q) :
67
checkRangeInExpression(false),
75
~QuantitySpinBoxPrivate() = default;
77
QString stripped(const QString &t, int *pos) const
80
const int s = text.size();
81
text = text.trimmed();
83
(*pos) -= (s - text.size());
87
bool validate(QString& input, Base::Quantity& result, const App::ObjectIdentifier& path) const
89
Q_Q(const QuantitySpinBox);
91
// Do not accept empty strings because the parser will consider
92
// " unit" as "1 unit" which is not the desired behaviour (see #0004104)
99
auto validateInput = [&](QString& tmp) -> QValidator::State {
100
QValidator::State state;
101
Base::Quantity res = validateAndInterpret(tmp, state, path);
102
res.setFormat(quantity.getFormat());
103
if (state == QValidator::Acceptable) {
111
QValidator::State state = validateInput(tmp);
112
if (state == QValidator::Intermediate && q->hasExpression()) {
113
// Accept the expression as it is but try to add the right unit string
116
Base::Quantity quantity;
118
if (parseString(input, quantity, value, path)) {
119
quantity.setUnit(unit);
122
// Now translate the quantity into its string representation using the user-defined unit system
123
input = Base::UnitsApi::schemaTranslate(result);
129
bool parseString(const QString& str, Base::Quantity& result, double& value, const App::ObjectIdentifier& path) const
131
App::ObjectIdentifier pathtmp = path;
134
copy.remove(locale.groupSeparator());
137
std::shared_ptr<Expression> expr(ExpressionParser::parse(path.getDocumentObject(), copy.toUtf8().constData()));
140
std::unique_ptr<Expression> res(expr->eval());
141
NumberExpression * n = Base::freecad_dynamic_cast<NumberExpression>(res.get());
143
result = n->getQuantity();
144
value = result.getValue();
149
catch (Base::Exception&) {
154
Base::Quantity validateAndInterpret(QString& input, QValidator::State& state, const App::ObjectIdentifier& path) const
157
const double max = this->maximum;
158
const double min = this->minimum;
160
QString copy = input;
164
QChar plus = QLatin1Char('+'), minus = QLatin1Char('-');
166
if (locale.negativeSign() != minus)
167
copy.replace(locale.negativeSign(), minus);
168
if (locale.positiveSign() != plus)
169
copy.replace(locale.positiveSign(), plus);
171
QString reverseUnitStr = unitStr;
172
std::reverse(reverseUnitStr.begin(), reverseUnitStr.end());
174
//Prep for expression parser
175
//This regex matches chunks between +,-,$,^ accounting for matching parenthesis.
176
QRegularExpression chunkRe(QString::fromUtf8("(?<=^|[\\+\\-])((\\((?>[^()]|(?2))*\\))|[^\\+\\-\n])*(?=$|[\\+\\-])"));
177
QRegularExpressionMatchIterator expressionChunk = chunkRe.globalMatch(copy);
178
unsigned int lengthOffset = 0;
179
while (expressionChunk.hasNext()) {
180
QRegularExpressionMatch matchChunk = expressionChunk.next();
181
QString origionalChunk = matchChunk.captured(0);
182
QString copyChunk = origionalChunk;
183
std::reverse(copyChunk.begin(), copyChunk.end());
185
//Reused regex patterns
186
static const std::string regexUnits = "sAV|VC|lim|nim|im|hpm|[mf]?bl|°|ged|dar|nog|″|′|rroT[uµm]?|K[uµm]?|A[mkM]?|F[pnuµm]?|C|S[uµmkM]?|zH[kMGT]?|H[nuµm]?|mhO[kM]?|J[mk]?|Ve[kM]?|V[mk]?|hWk|sW|lack?|N[mkM]?|g[uµmk]?|lm?|(?<=\\b|[^a-zA-Z])m[nuµmcdk]?|uoht|ni|\"|'|dy|dc|bW|T|t|zo|ts|twc|Wk?|aP[kMG]?|is[pk]|h|G|M|tfc|tfqs|tf|s";
187
static const std::string regexUnitlessFunctions = "soca|nisa|2nata|nata|hsoc|hnis|hnat|soc|nat|nis|pxe|gol|01gol";
188
static const std::string regexConstants = "e|ip|lomm|lom";
189
static const std::string regexNumber = "\\d+\\s*\\.?\\s*\\d*|\\.\\s*\\d+";
191
// If expression does not contain /*() or ^, this regex will not find anything
192
if (copy.contains(QLatin1Char('/')) || copy.contains(QLatin1Char('*')) || copy.contains(QLatin1Char('(')) || copy.contains(QLatin1Char(')')) || copy.contains(QLatin1Char('^'))){
193
//Find units and replace 1/2mm -> 1/2*(1mm), 1^2mm -> 1^2*(1mm)
194
QRegularExpression fixUnits(QString::fromStdString("("+regexUnits+")(\\s*\\)|(?:\\*|(?:\\)(?:(?:\\s*(?:"+regexConstants+"|\\)(?:[^()]|(?R))*\\((?:"+regexUnitlessFunctions+")|"+regexNumber+"))|(?R))*\\(|(?:\\s*(?:"+regexConstants+"|\\)(?:[^()]|(?R))*\\((?:"+regexUnitlessFunctions+")|"+regexNumber+"))))+(?:[\\/\\^]|(.*$))(?!("+regexUnits+")))"));
195
QRegularExpressionMatch fixUnitsMatch = fixUnits.match(copyChunk);
197
//3rd capture group being filled indicates regex bailed out; no match.
198
if (fixUnitsMatch.lastCapturedIndex() == 2 || (fixUnitsMatch.lastCapturedIndex() == 3 && fixUnitsMatch.captured(3).isEmpty())){
199
QString matchUnits = fixUnitsMatch.captured(1);
200
QString matchNumbers = fixUnitsMatch.captured(2);
201
copyChunk.replace(matchUnits+matchNumbers, QString::fromUtf8(")")+matchUnits+QString::fromUtf8("1(*")+matchNumbers);
205
//Add default units to string if none are present
206
if (!copyChunk.contains(reverseUnitStr)){ // Fast check
207
QRegularExpression unitsRe(QString::fromStdString("(?<=\\b|[^a-zA-Z])("+regexUnits+")(?=\\b|[^a-zA-Z])|°|″|′|\"|'|\\p{L}\\.\\p{L}|\\[\\p{L}"));
209
QRegularExpressionMatch match = unitsRe.match(copyChunk);
210
if (!match.hasMatch() && !copyChunk.isEmpty()) //If no units are found, use default units
211
copyChunk.prepend(QString::fromUtf8(")")+reverseUnitStr+QString::fromUtf8("1(*")); // Add units to the end of chunk *(1unit)
214
std::reverse(copyChunk.begin(), copyChunk.end());
216
copy.replace(matchChunk.capturedStart() + lengthOffset,
217
matchChunk.capturedEnd() - matchChunk.capturedStart(), copyChunk);
218
lengthOffset += copyChunk.length() - origionalChunk.length();
221
ok = parseString(copy, res, value, path);
223
// If result does not have unit: add default unit
224
if (res.getUnit().isEmpty()){
229
// input may not be finished
230
state = QValidator::Intermediate;
232
else if (value >= min && value <= max) {
233
state = QValidator::Acceptable;
235
else if (max == min) { // when max and min is the same the only non-Invalid input is max (or min)
236
state = QValidator::Invalid;
239
if ((value >= 0 && value > max) || (value < 0 && value < min)) {
240
state = QValidator::Invalid;
243
state = QValidator::Intermediate;
246
if (state != QValidator::Acceptable) {
247
res.setValue(max > 0 ? min : max);
256
bool checkRangeInExpression;
258
Base::Quantity quantity;
259
Base::Quantity cached;
266
QuantitySpinBox *q_ptr;
267
std::unique_ptr<Base::UnitsSchema> scheme;
268
Q_DECLARE_PUBLIC(QuantitySpinBox)
272
QuantitySpinBox::QuantitySpinBox(QWidget *parent)
273
: QAbstractSpinBox(parent),
274
ExpressionSpinBox(this),
275
d_ptr(new QuantitySpinBoxPrivate(this))
277
d_ptr->locale = locale();
278
this->setContextMenuPolicy(Qt::DefaultContextMenu);
279
connect(lineEdit(), &QLineEdit::textChanged,
280
this, &QuantitySpinBox::userInput);
281
connect(this, &QuantitySpinBox::editingFinished,
283
this->handlePendingEmit(true);
286
// When a style sheet is set the text margins for top/bottom must be set to avoid to squash the widget
288
lineEdit()->setTextMargins(0, 2, 0, 2);
290
// https://forum.freecad.org/viewtopic.php?f=8&t=50615
291
lineEdit()->setTextMargins(0, 2, 0, 0);
295
QuantitySpinBox::~QuantitySpinBox() = default;
297
void QuantitySpinBox::bind(const App::ObjectIdentifier &_path)
299
ExpressionSpinBox::bind(_path);
302
void QuantitySpinBox::showIcon()
307
QString QuantitySpinBox::boundToName() const
310
std::string path = getPath().toString();
311
return QString::fromStdString(path);
317
* @brief Create an object identifier by name.
319
* An identifier is written as document#documentobject.property.subproperty1...subpropertyN
320
* document# may be dropped, in this case the active document is used.
322
void QuantitySpinBox::setBoundToByName(const QString &name)
326
App::Document *doc = App::GetApplication().getActiveDocument();
327
QStringList list = name.split(QLatin1Char('#'));
328
if (list.size() > 1) {
329
doc = App::GetApplication().getDocument(list.front().toLatin1());
334
qDebug() << "No such document";
338
// first element is assumed to be the document name
339
list = list.front().split(QLatin1Char('.'));
342
App::DocumentObject* obj = doc->getObject(list.front().toLatin1());
344
qDebug() << "No object " << list.front() << " in document";
349
// the rest of the list defines the property and eventually subproperties
350
App::ObjectIdentifier path(obj);
351
path.setDocumentName(std::string(doc->getName()), true);
352
path.setDocumentObjectName(std::string(obj->getNameInDocument()), true);
354
for (const auto & it : list) {
355
path << App::ObjectIdentifier::Component::SimpleComponent(it.toLatin1().constData());
358
if (path.getProperty())
361
catch (const Base::Exception& e) {
362
qDebug() << e.what();
366
QString Gui::QuantitySpinBox::expressionText() const
369
if (hasExpression()) {
370
return QString::fromStdString(getExpressionString());
373
catch (const Base::Exception& e) {
374
qDebug() << e.what();
379
void QuantitySpinBox::evaluateExpression()
381
if (isBound() && getExpression()) {
382
showValidExpression(Number::SetIfNumber);
386
void Gui::QuantitySpinBox::setNumberExpression(App::NumberExpression* expr)
388
updateEdit(getUserString(expr->getQuantity()));
392
bool QuantitySpinBox::apply(const std::string & propName)
394
if (!ExpressionBinding::apply(propName)) {
395
double dValue = value().getValue();
396
return assignToProperty(propName, dValue);
402
void QuantitySpinBox::resizeEvent(QResizeEvent * event)
404
QAbstractSpinBox::resizeEvent(event);
408
void Gui::QuantitySpinBox::keyPressEvent(QKeyEvent *event)
410
if (!handleKeyEvent(event->text()))
411
QAbstractSpinBox::keyPressEvent(event);
414
void Gui::QuantitySpinBox::paintEvent(QPaintEvent*)
416
QStyleOptionSpinBox opt;
417
initStyleOption(&opt);
421
void QuantitySpinBox::updateText(const Quantity &quant)
423
Q_D(QuantitySpinBox);
426
QString txt = getUserString(quant, dFactor, d->unitStr);
427
d->unitValue = quant.getValue()/dFactor;
432
void QuantitySpinBox::updateEdit(const QString& text)
434
Q_D(QuantitySpinBox);
436
QLineEdit* edit = lineEdit();
438
bool empty = edit->text().isEmpty();
439
int cursor = edit->cursorPosition();
440
int selsize = edit->selectedText().size();
444
cursor = qBound(0, cursor, edit->displayText().size() - d->unitStr.size());
446
edit->setSelection(0, cursor);
449
edit->setCursorPosition(empty ? 0 : cursor);
453
void QuantitySpinBox::validateInput()
455
Q_D(QuantitySpinBox);
457
QValidator::State state;
458
QString text = lineEdit()->text();
459
const App::ObjectIdentifier & path = getPath();
460
d->validateAndInterpret(text, state, path);
461
if (state != QValidator::Acceptable) {
462
updateEdit(d->validStr);
468
Base::Quantity QuantitySpinBox::value() const
470
Q_D(const QuantitySpinBox);
474
double QuantitySpinBox::rawValue() const
476
Q_D(const QuantitySpinBox);
477
return d->quantity.getValue();
480
void QuantitySpinBox::setValue(const Base::Quantity& value)
482
Q_D(QuantitySpinBox);
485
if (d->quantity.getValue() > d->maximum)
486
d->quantity.setValue(d->maximum);
487
if (d->quantity.getValue() < d->minimum)
488
d->quantity.setValue(d->minimum);
490
d->unit = value.getUnit();
495
void QuantitySpinBox::setValue(double value)
497
Q_D(QuantitySpinBox);
499
Base::QuantityFormat currentformat = d->quantity.getFormat();
500
auto quantity = Base::Quantity(value, d->unit);
501
quantity.setFormat(currentformat);
506
bool QuantitySpinBox::hasValidInput() const
508
Q_D(const QuantitySpinBox);
509
return d->validInput;
512
// Gets called after call of 'validateAndInterpret'
513
void QuantitySpinBox::userInput(const QString & text)
515
Q_D(QuantitySpinBox);
517
d->pendingEmit = true;
521
const App::ObjectIdentifier & path = getPath();
522
if (d->validate(tmp, res, path)) {
524
d->validInput = true;
527
d->validInput = false;
531
if (keyboardTracking()) {
533
handlePendingEmit(false);
540
void QuantitySpinBox::openFormulaDialog()
544
Q_D(const QuantitySpinBox);
545
auto box = new Gui::Dialog::DlgExpressionInput(getPath(), getExpression(), d->unit, this);
546
if (d->checkRangeInExpression) {
547
box->setRange(d->minimum, d->maximum);
549
QObject::connect(box, &Gui::Dialog::DlgExpressionInput::finished, [this, box]() {
550
if (box->result() == QDialog::Accepted)
551
setExpression(box->getExpression());
552
else if (box->discardedFormula())
553
setExpression(std::shared_ptr<Expression>());
556
Q_EMIT showFormulaDialog(false);
560
QPoint pos = mapToGlobal(QPoint(0,0));
561
box->move(pos-box->expressionPosition());
562
box->setExpressionInputSize(width(), height());
564
Q_EMIT showFormulaDialog(true);
567
void QuantitySpinBox::handlePendingEmit(bool updateUnit /* = true */)
569
updateFromCache(true, updateUnit);
572
void QuantitySpinBox::updateFromCache(bool notify, bool updateUnit /* = true */)
574
Q_D(QuantitySpinBox);
575
if (d->pendingEmit) {
577
const Base::Quantity& res = d->cached;
578
auto tmpUnit(d->unitStr);
579
QString text = getUserString(res, factor, updateUnit ? d->unitStr : tmpUnit);
580
d->unitValue = res.getValue() / factor;
585
d->pendingEmit = false;
586
Q_EMIT valueChanged(res);
587
Q_EMIT valueChanged(res.getValue());
588
Q_EMIT textChanged(text);
593
Base::Unit QuantitySpinBox::unit() const
595
Q_D(const QuantitySpinBox);
599
void QuantitySpinBox::setUnit(const Base::Unit &unit)
601
Q_D(QuantitySpinBox);
604
d->quantity.setUnit(unit);
605
updateText(d->quantity);
608
void QuantitySpinBox::setUnitText(const QString& str)
611
Base::Quantity quant = Base::Quantity::parse(str);
612
setUnit(quant.getUnit());
614
catch (const Base::ParserError&) {
618
QString QuantitySpinBox::unitText()
620
Q_D(QuantitySpinBox);
624
double QuantitySpinBox::singleStep() const
626
Q_D(const QuantitySpinBox);
627
return d->singleStep;
630
void QuantitySpinBox::setSingleStep(double value)
632
Q_D(QuantitySpinBox);
635
d->singleStep = value;
639
double QuantitySpinBox::minimum() const
641
Q_D(const QuantitySpinBox);
645
void QuantitySpinBox::setMinimum(double minimum)
647
Q_D(QuantitySpinBox);
648
d->minimum = minimum;
651
double QuantitySpinBox::maximum() const
653
Q_D(const QuantitySpinBox);
657
void QuantitySpinBox::setMaximum(double maximum)
659
Q_D(QuantitySpinBox);
660
d->maximum = maximum;
663
void QuantitySpinBox::setRange(double minimum, double maximum)
665
Q_D(QuantitySpinBox);
666
d->minimum = minimum;
667
d->maximum = maximum;
670
void QuantitySpinBox::checkRangeInExpression(bool on)
672
Q_D(QuantitySpinBox);
673
d->checkRangeInExpression = on;
676
bool QuantitySpinBox::isCheckedRangeInExpresion() const
678
Q_D(const QuantitySpinBox);
679
return d->checkRangeInExpression;
683
int QuantitySpinBox::decimals() const
685
Q_D(const QuantitySpinBox);
686
return d->quantity.getFormat().precision;
689
void QuantitySpinBox::setDecimals(int v)
691
Q_D(QuantitySpinBox);
692
Base::QuantityFormat f = d->quantity.getFormat();
694
d->quantity.setFormat(f);
695
updateText(d->quantity);
698
void QuantitySpinBox::setSchema(const Base::UnitSystem& s)
700
Q_D(QuantitySpinBox);
701
d->scheme = Base::UnitsApi::createSchema(s);
702
updateText(d->quantity);
705
void QuantitySpinBox::clearSchema()
707
Q_D(QuantitySpinBox);
709
updateText(d->quantity);
712
QString QuantitySpinBox::getUserString(const Base::Quantity& val, double& factor, QString& unitString) const
714
Q_D(const QuantitySpinBox);
716
return val.getUserString(d->scheme.get(), factor, unitString);
719
return val.getUserString(factor, unitString);
723
QString QuantitySpinBox::getUserString(const Base::Quantity& val) const
725
Q_D(const QuantitySpinBox);
729
return val.getUserString(d->scheme.get(), factor, unitString);
732
return val.getUserString();
736
void QuantitySpinBox::setExpression(std::shared_ptr<Expression> expr)
738
ExpressionSpinBox::setExpression(expr);
741
QAbstractSpinBox::StepEnabled QuantitySpinBox::stepEnabled() const
743
Q_D(const QuantitySpinBox);
744
if (isReadOnly()/* || !d->validInput*/)
747
return StepEnabled(StepUpEnabled | StepDownEnabled);
748
StepEnabled ret = StepNone;
749
if (d->quantity.getValue() < d->maximum) {
750
ret |= StepUpEnabled;
752
if (d->quantity.getValue() > d->minimum) {
753
ret |= StepDownEnabled;
758
void QuantitySpinBox::stepBy(int steps)
760
Q_D(QuantitySpinBox);
761
updateFromCache(false);
763
double step = d->singleStep * steps;
764
double val = d->unitValue + step;
765
if (val > d->maximum)
767
else if (val < d->minimum)
770
Quantity quant(val, d->unitStr);
772
updateFromCache(true);
777
QSize QuantitySpinBox::sizeForText(const QString& txt) const
779
const QFontMetrics fm(fontMetrics());
780
int h = lineEdit()->sizeHint().height();
781
int w = QtTools::horizontalAdvance(fm, txt);
783
w += 2; // cursor blinking space
786
QStyleOptionSpinBox opt;
787
initStyleOption(&opt);
789
QSize size = style()->sizeFromContents(QStyle::CT_SpinBox, &opt, hint, this);
793
QSize QuantitySpinBox::sizeHint() const
795
Q_D(const QuantitySpinBox);
798
const QFontMetrics fm(fontMetrics());
799
int h = lineEdit()->sizeHint().height();
803
QString fixedContent = QLatin1String(" ");
805
Base::Quantity q(d->quantity);
806
q.setValue(d->maximum);
807
s = textFromValue(q);
810
w = qMax(w, QtTools::horizontalAdvance(fm, s));
812
w += 2; // cursor blinking space
815
QStyleOptionSpinBox opt;
816
initStyleOption(&opt);
818
QSize size = style()->sizeFromContents(QStyle::CT_SpinBox, &opt, hint, this);
822
QSize QuantitySpinBox::minimumSizeHint() const
824
Q_D(const QuantitySpinBox);
827
const QFontMetrics fm(fontMetrics());
828
int h = lineEdit()->minimumSizeHint().height();
832
QString fixedContent = QLatin1String(" ");
834
Base::Quantity q(d->quantity);
835
q.setValue(d->maximum);
836
s = textFromValue(q);
839
w = qMax(w, QtTools::horizontalAdvance(fm, s));
841
w += 2; // cursor blinking space
844
QStyleOptionSpinBox opt;
845
initStyleOption(&opt);
848
QSize size = style()->sizeFromContents(QStyle::CT_SpinBox, &opt, hint, this);
852
void QuantitySpinBox::showEvent(QShowEvent * event)
854
Q_D(QuantitySpinBox);
856
QAbstractSpinBox::showEvent(event);
858
bool selected = lineEdit()->hasSelectedText();
859
updateText(d->quantity);
864
void QuantitySpinBox::hideEvent(QHideEvent * event)
867
QAbstractSpinBox::hideEvent(event);
870
void QuantitySpinBox::closeEvent(QCloseEvent * event)
873
QAbstractSpinBox::closeEvent(event);
876
bool QuantitySpinBox::event(QEvent * event)
878
return QAbstractSpinBox::event(event);
881
void QuantitySpinBox::focusInEvent(QFocusEvent * event)
883
bool hasSel = lineEdit()->hasSelectedText();
884
QAbstractSpinBox::focusInEvent(event);
886
if (event->reason() == Qt::TabFocusReason ||
887
event->reason() == Qt::BacktabFocusReason ||
888
event->reason() == Qt::ShortcutFocusReason) {
890
if (isBound() && getExpression() && lineEdit()->isReadOnly()) {
891
auto helpEvent = new QHelpEvent(QEvent::ToolTip, QPoint( 0, rect().height() ), mapToGlobal( QPoint( 0, rect().height() ) ));
892
QApplication::postEvent(this, helpEvent);
893
lineEdit()->setSelection(0, 0);
902
void QuantitySpinBox::focusOutEvent(QFocusEvent * event)
906
QToolTip::hideText();
907
QAbstractSpinBox::focusOutEvent(event);
910
void QuantitySpinBox::clear()
912
QAbstractSpinBox::clear();
915
void QuantitySpinBox::selectNumber()
917
QString expr = QString::fromLatin1("^([%1%2]?[0-9\\%3]*)\\%4?([0-9]+(%5[%1%2]?[0-9]+)?)")
918
.arg(locale().negativeSign())
919
.arg(locale().positiveSign())
920
.arg(locale().groupSeparator())
921
.arg(locale().decimalPoint())
922
.arg(locale().exponential());
923
auto rmatch = QRegularExpression(expr).match(lineEdit()->text());
924
if (rmatch.hasMatch()) {
925
lineEdit()->setSelection(0, rmatch.capturedLength());
929
QString QuantitySpinBox::textFromValue(const Base::Quantity& value) const
933
QString str = getUserString(value, factor, unitStr);
934
if (qAbs(value.getValue()) >= 1000.0) {
935
str.remove(locale().groupSeparator());
940
Base::Quantity QuantitySpinBox::valueFromText(const QString &text) const
942
Q_D(const QuantitySpinBox);
945
QValidator::State state = QValidator::Acceptable;
946
const App::ObjectIdentifier & path = getPath();
947
Base::Quantity quant = d->validateAndInterpret(copy, state, path);
948
if (state != QValidator::Acceptable) {
950
quant = d->validateAndInterpret(copy, state, path);
956
QValidator::State QuantitySpinBox::validate(QString &text, int &pos) const
958
Q_D(const QuantitySpinBox);
961
QValidator::State state;
962
const App::ObjectIdentifier & path = getPath();
963
d->validateAndInterpret(text, state, path);
967
void QuantitySpinBox::fixup(QString &input) const
969
input.remove(locale().groupSeparator());
973
#include "moc_QuantitySpinBox.cpp"
974
#include "moc_QuantitySpinBox_p.cpp"