Skip to content

Commit 0eeea76

Browse files
authored
Merge pull request #6237 from elpaso/commas-dots-fieldvalidator
[bugfix][attrtable] Convert comma to dot for floating point input
2 parents f3f0eb0 + cc1625c commit 0eeea76

File tree

7 files changed

+116
-5
lines changed

7 files changed

+116
-5
lines changed

python/gui/qgsfieldvalidator.sip.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ class QgsFieldValidator : QValidator
1919
QgsFieldValidator( QObject *parent, const QgsField &field, const QString &defaultValue, const QString &dateFormat = "yyyy-MM-dd" );
2020
~QgsFieldValidator();
2121

22-
virtual State validate( QString &s /Constrained/, int &i /In,Out/ ) const;
22+
virtual State validate( QString &s /Constrained,In,Out/, int &i /In,Out/ ) const;
2323

2424
virtual void fixup( QString &s /Constrained/ ) const;
2525

scripts/sipify.pl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -343,9 +343,9 @@ sub fix_annotations {
343343
$line =~ s/SIP_VIRTUALERRORHANDLER\(\s*(\w+)\s*\)/\/VirtualErrorHandler=$1\//;
344344

345345
# combine multiple annotations
346-
# https://regex101.com/r/uvCt4M/3
346+
# https://regex101.com/r/uvCt4M/4
347347
do {no warnings 'uninitialized';
348-
$line =~ s/\/(\w+(=\w+)?)\/\s*\/(\w+(=\w+)?)\//\/$1,$3\//;
348+
$line =~ s/\/([\w,]+(=\w+)?)\/\s*\/([\w,]+(=\w+)?)\//\/$1,$3\//;
349349
(! $3) or dbg_info("combine multiple annotations -- works only for 2");
350350
};
351351

src/gui/qgsfieldvalidator.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,6 @@ QgsFieldValidator::QgsFieldValidator( QObject *parent, const QgsField &field, co
8484
mValidator = nullptr;
8585
}
8686

87-
QgsSettings settings;
8887
mNullValue = QgsApplication::nullRepresentation();
8988
}
9089

@@ -113,6 +112,12 @@ QValidator::State QgsFieldValidator::validate( QString &s, int &i ) const
113112
// delegate to the child validator if any
114113
if ( mValidator )
115114
{
115+
// force to use the '.' as a decimal point or in case we are using QDoubleValidator
116+
// we can get a valid number with a comma depending on current locale
117+
// ... but this will fail subsequently when converted from string to double and
118+
// becomes a NULL!
119+
if ( mField.type() == QVariant::Double )
120+
s = s.replace( ',', '.' );
116121
QValidator::State result = mValidator->validate( s, i );
117122
return result;
118123
}

src/gui/qgsfieldvalidator.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ class GUI_EXPORT QgsFieldValidator : public QValidator
3838
QgsFieldValidator( QObject *parent, const QgsField &field, const QString &defaultValue, const QString &dateFormat = "yyyy-MM-dd" );
3939
~QgsFieldValidator() override;
4040

41-
State validate( QString &s SIP_CONSTRAINED, int &i SIP_INOUT ) const override;
41+
State validate( QString &s SIP_CONSTRAINED SIP_INOUT, int &i SIP_INOUT ) const override;
4242
void fixup( QString &s SIP_CONSTRAINED ) const override;
4343

4444
QString dateFormat() const { return mDateFormat; }

tests/src/python/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ ADD_PYTHON_TEST(PyQgsAuthManagerProxy test_authmanager_proxy.py)
196196
ADD_PYTHON_TEST(PyQgsAuthSettingsWidget test_authsettingswidget.py)
197197
ADD_PYTHON_TEST(PyQgsAuxiliaryStorage test_qgsauxiliarystorage.py)
198198
ADD_PYTHON_TEST(PyQgsAuthManagerOgr test_authmanager_ogr.py)
199+
ADD_PYTHON_TEST(PyQgsFieldValidator test_qgsfieldvalidator.py)
199200

200201
IF (NOT WIN32)
201202
ADD_PYTHON_TEST(PyQgsLogger test_qgslogger.py)
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
# -*- coding: utf-8 -*-
2+
"""QGIS Unit tests for QgsFieldValidator.
3+
4+
.. note:: This program is free software; you can redistribute it and/or modify
5+
it under the terms of the GNU General Public License as published by
6+
the Free Software Foundation; either version 2 of the License, or
7+
(at your option) any later version.
8+
"""
9+
__author__ = 'Alessandro Pasotti'
10+
__date__ = '31/01/2018'
11+
__copyright__ = 'Copyright 2018, The QGIS Project'
12+
# This will get replaced with a git SHA1 when you do a git archive
13+
__revision__ = '$Format:%H$'
14+
15+
import qgis # NOQA
16+
17+
from qgis.PyQt.QtCore import QVariant
18+
from qgis.PyQt.QtGui import QValidator
19+
from qgis.core import QgsVectorLayer
20+
from qgis.gui import QgsFieldValidator
21+
from qgis.testing import start_app, unittest
22+
from utilities import unitTestDataPath
23+
24+
TEST_DATA_DIR = unitTestDataPath()
25+
26+
27+
start_app()
28+
29+
30+
class TestQgsFieldValidator(unittest.TestCase):
31+
32+
def setUp(self):
33+
"""Run before each test."""
34+
testPath = TEST_DATA_DIR + '/' + 'bug_17878.gpkg|layername=bug_17878'
35+
self.vl = QgsVectorLayer(testPath, "test_data", "ogr")
36+
assert self.vl.isValid()
37+
38+
def tearDown(self):
39+
"""Run after each test."""
40+
pass
41+
42+
def test_validator(self):
43+
# Test the double
44+
"""
45+
Expected results from validate
46+
QValidator::Invalid 0 The string is clearly invalid.
47+
QValidator::Intermediate 1 The string is a plausible intermediate value.
48+
QValidator::Acceptable 2 The string is acceptable as a final result; i.e. it is valid.
49+
"""
50+
51+
double_field = self.vl.fields()[self.vl.fields().indexFromName('double_field')]
52+
self.assertEqual(double_field.precision(), 0) # this is what the provider reports :(
53+
self.assertEqual(double_field.length(), 0) # not set
54+
self.assertEqual(double_field.type(), QVariant.Double)
55+
56+
validator = QgsFieldValidator(None, double_field, '0.0', '')
57+
58+
def _test(value, expected):
59+
ret = validator.validate(value, 0)
60+
self.assertEqual(ret[0], expected, value)
61+
if value:
62+
self.assertEqual(validator.validate('-' + value, 0)[0], expected, '-' + value)
63+
# Check the decimal comma separator has been properly transformed
64+
if expected != QValidator.Invalid:
65+
self.assertEqual(ret[1], value.replace(',', '.'))
66+
67+
# Valid
68+
_test('0.1234', QValidator.Acceptable)
69+
_test('0,1234', QValidator.Acceptable)
70+
_test('12345.1234e+123', QValidator.Acceptable)
71+
_test('12345.1234e-123', QValidator.Acceptable)
72+
_test('12345,1234e+123', QValidator.Acceptable)
73+
_test('12345,1234e-123', QValidator.Acceptable)
74+
_test('', QValidator.Acceptable)
75+
76+
# Out of range
77+
_test('12345.1234e+823', QValidator.Intermediate)
78+
_test('12345.1234e-823', QValidator.Intermediate)
79+
_test('12345,1234e+823', QValidator.Intermediate)
80+
_test('12345,1234e-823', QValidator.Intermediate)
81+
82+
# Invalid
83+
_test('12345-1234', QValidator.Invalid)
84+
_test('onetwothree', QValidator.Invalid)
85+
86+
int_field = self.vl.fields()[self.vl.fields().indexFromName('int_field')]
87+
self.assertEqual(int_field.precision(), 0) # this is what the provider reports :(
88+
self.assertEqual(int_field.length(), 0) # not set
89+
self.assertEqual(int_field.type(), QVariant.Int)
90+
91+
validator = QgsFieldValidator(None, int_field, '0', '')
92+
93+
# Valid
94+
_test('0', QValidator.Acceptable)
95+
_test('1234', QValidator.Acceptable)
96+
_test('', QValidator.Acceptable)
97+
98+
# Invalid
99+
_test('12345-1234', QValidator.Invalid)
100+
_test('12345.1234', QValidator.Invalid)
101+
_test('onetwothree', QValidator.Invalid)
102+
103+
104+
if __name__ == '__main__':
105+
unittest.main()

tests/testdata/bug_17878.gpkg

116 KB
Binary file not shown.

0 commit comments

Comments
 (0)