Skip to content

Commit

Permalink
Accept dot and comma as decimal point on input
Browse files Browse the repository at this point in the history
  • Loading branch information
elpaso committed Jun 9, 2018
1 parent 2628075 commit ec20ff7
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 33 deletions.
10 changes: 2 additions & 8 deletions src/gui/qgsfieldvalidator.cpp
Expand Up @@ -56,7 +56,7 @@ QgsFieldValidator::QgsFieldValidator( QObject *parent, const QgsField &field, co
{
if ( mField.length() > 0 && mField.precision() > 0 )
{
QString re = QStringLiteral( "-?\\d{0,%1}(\\.\\d{0,%2})?" ).arg( mField.length() - mField.precision() ).arg( mField.precision() );
QString re = QStringLiteral( "-?\\d{0,%1}([\\.,]\\d{0,%2})?" ).arg( mField.length() - mField.precision() ).arg( mField.precision() );
mValidator = new QRegExpValidator( QRegExp( re ), parent );
}
else if ( mField.length() > 0 && mField.precision() == 0 )
Expand All @@ -66,7 +66,7 @@ QgsFieldValidator::QgsFieldValidator( QObject *parent, const QgsField &field, co
}
else if ( mField.precision() > 0 )
{
QString re = QStringLiteral( "-?\\d*(\\.\\d{0,%1})?" ).arg( mField.precision() );
QString re = QStringLiteral( "-?\\d*([\\.,]\\d{0,%1})?" ).arg( mField.precision() );
mValidator = new QRegExpValidator( QRegExp( re ), parent );
}
else
Expand Down Expand Up @@ -112,12 +112,6 @@ QValidator::State QgsFieldValidator::validate( QString &s, int &i ) const
// delegate to the child validator if any
if ( mValidator )
{
// force to use the '.' as a decimal point or in case we are using QDoubleValidator
// we can get a valid number with a comma depending on current locale
// ... but this will fail subsequently when converted from string to double and
// becomes a NULL!
if ( mField.type() == QVariant::Double )
s = s.replace( ',', '.' );
QValidator::State result = mValidator->validate( s, i );
return result;
}
Expand Down
76 changes: 51 additions & 25 deletions tests/src/python/test_qgsfieldvalidator.py
Expand Up @@ -14,7 +14,7 @@

import qgis # NOQA

from qgis.PyQt.QtCore import QVariant
from qgis.PyQt.QtCore import QVariant, QLocale
from qgis.PyQt.QtGui import QValidator
from qgis.core import QgsVectorLayer
from qgis.gui import QgsFieldValidator
Expand All @@ -39,45 +39,41 @@ def tearDown(self):
"""Run after each test."""
pass

def test_validator(self):
# Test the double
"""
def _fld_checker(self, field):
"""
Expected results from validate
QValidator::Invalid 0 The string is clearly invalid.
QValidator::Intermediate 1 The string is a plausible intermediate value.
QValidator::Acceptable 2 The string is acceptable as a final result; i.e. it is valid.
"""
DECIMAL_SEPARATOR = QLocale().decimalPoint()
OTHER_SEPARATOR = ',' if DECIMAL_SEPARATOR == '.' else '.'

double_field = self.vl.fields()[self.vl.fields().indexFromName('double_field')]
self.assertEqual(double_field.precision(), 0) # this is what the provider reports :(
self.assertEqual(double_field.length(), 0) # not set
self.assertEqual(double_field.type(), QVariant.Double)

validator = QgsFieldValidator(None, double_field, '0.0', '')
validator = QgsFieldValidator(None, field, '0.0', '')

def _test(value, expected):
ret = validator.validate(value, 0)
self.assertEqual(ret[0], expected, value)
self.assertEqual(ret[0], expected, "%s != %s" % (ret[0], expected))
if value:
self.assertEqual(validator.validate('-' + value, 0)[0], expected, '-' + value)
# Check the decimal comma separator has been properly transformed
if expected != QValidator.Invalid:
self.assertEqual(ret[1], value.replace(',', '.'))

# Valid
_test('0.1234', QValidator.Acceptable)
_test('0,1234', QValidator.Acceptable)
_test('12345.1234e+123', QValidator.Acceptable)
_test('12345.1234e-123', QValidator.Acceptable)
_test('12345,1234e+123', QValidator.Acceptable)
_test('12345,1234e-123', QValidator.Acceptable)
_test('', QValidator.Acceptable)

# Out of range
_test('12345.1234e+823', QValidator.Intermediate)
_test('12345.1234e-823', QValidator.Intermediate)
_test('12345,1234e+823', QValidator.Intermediate)
_test('12345,1234e-823', QValidator.Intermediate)
# If precision is > 0, regexp validator is used (and it does not support sci notation)
if field.precision() == 0:
_test('12345.1234e+123', QValidator.Acceptable)
_test('12345.1234e-123', QValidator.Acceptable)
_test('12345,1234e+123', QValidator.Acceptable)
_test('12345,1234e-123', QValidator.Acceptable)
_test('', QValidator.Acceptable)

# Out of range
_test('12345.1234e+823', QValidator.Intermediate)
_test('12345.1234e-823', QValidator.Intermediate)
_test('12345,1234e+823', QValidator.Intermediate)
_test('12345,1234e-823', QValidator.Intermediate)

# Invalid
_test('12345-1234', QValidator.Invalid)
Expand All @@ -97,9 +93,39 @@ def _test(value, expected):

# Invalid
_test('12345-1234', QValidator.Invalid)
_test('12345.1234', QValidator.Invalid)
_test('12345%s1234' % DECIMAL_SEPARATOR, QValidator.Invalid)
_test('onetwothree', QValidator.Invalid)

def test_doubleValidator(self):
"""Test the double with default (system) locale"""
field = self.vl.fields()[self.vl.fields().indexFromName('double_field')]
self.assertEqual(field.precision(), 0) # this is what the provider reports :(
self.assertEqual(field.length(), 0) # not set
self.assertEqual(field.type(), QVariant.Double)
self._fld_checker(field)

def test_doubleValidatorCommaLocale(self):
"""Test the double with german locale"""
QLocale.setDefault(QLocale(QLocale.German, QLocale.Germany))
assert QLocale().decimalPoint() == ','
field = self.vl.fields()[self.vl.fields().indexFromName('double_field')]
self._fld_checker(field)

def test_doubleValidatorDotLocale(self):
"""Test the double with english locale"""
QLocale.setDefault(QLocale(QLocale.English))
assert QLocale().decimalPoint() == '.'
field = self.vl.fields()[self.vl.fields().indexFromName('double_field')]
self._fld_checker(field)

def test_precision(self):
"""Test different precision"""
QLocale.setDefault(QLocale(QLocale.English))
assert QLocale().decimalPoint() == '.'
field = self.vl.fields()[self.vl.fields().indexFromName('double_field')]
field.setPrecision(4)
self._fld_checker(field)


if __name__ == '__main__':
unittest.main()

0 comments on commit ec20ff7

Please sign in to comment.