Fix parsing of geo coordinates in locale encoding (+ extend unit test)

Summary:
QString::toDouble in Qt5 no longer first tries the system locale

In tests also prefer QLocale::toString over "%L1", in some Qt versionns
(e.g. 5.6) the L might only work when QLocale::setDefault has been
explicitely called.

Test Plan:
Unit tests haven been improved and are all passing.
marble --latlon "46,09898 7,78307" in German locale works now as expected

Reviewers: rahn, nienhueser, #marble

Reviewed By: nienhueser, #marble

Differential Revision: https://phabricator.kde.org/D1994
parent c8d1c5b0
......@@ -42,6 +42,12 @@ class LonLatParser
private:
enum DirPosition { PrefixDir, PostfixDir };
/**
* Parses the double value from the input string in system locale
* if it contains the system locale decimalpoint char,
* otherwise parses it in the C locale.
*/
static double parseDouble(const QString& input);
static QString createDecimalPointExp();
static QString regExp( const QString& string );
static void getLocaleList( QStringList& localeList, const QString& localeListString,
......@@ -255,8 +261,8 @@ bool LonLatParser::parse( const QString& string )
const QRegExp regex = QRegExp( numberCapExp );
if( regex.exactMatch(input) ) {
m_lon = regex.cap(2).toDouble();
m_lat = regex.cap(1).toDouble();
m_lon = parseDouble(regex.cap(2));
m_lat = parseDouble(regex.cap(1));
return true;
}
......@@ -427,6 +433,16 @@ bool LonLatParser::tryMatchFromD( const QString& input, DirPosition dirPosition
return true;
}
double LonLatParser::parseDouble(const QString& input)
{
// Decide by decimalpoint if system locale or C locale should be tried.
// Otherwise if first trying with a system locale when the string is in C locale,
// the "." might be misinterpreted as thousands group separator and thus a wrong
// value yielded
QLocale locale = QLocale::system();
return input.contains(locale.decimalPoint()) ? locale.toDouble(input) : input.toDouble();
}
QString LonLatParser::createDecimalPointExp()
{
const QChar decimalPoint = QLocale::system().decimalPoint();
......@@ -521,7 +537,7 @@ qreal LonLatParser::degreeValueFromDMS( const QRegExp& regex, int c, bool isPosH
const bool isNegativeValue = (regex.cap( c++ ) == QLatin1String("-"));
const uint degree = regex.cap( c++ ).toUInt();
const uint minutes = regex.cap( c++ ).toUInt();
const qreal seconds = regex.cap( c ).toDouble();
const qreal seconds = parseDouble(regex.cap( c ));
qreal result = degree + (minutes*MIN2HOUR) + (seconds*SEC2HOUR);
......@@ -537,7 +553,7 @@ qreal LonLatParser::degreeValueFromDM( const QRegExp& regex, int c, bool isPosHe
{
const bool isNegativeValue = (regex.cap( c++ ) == QLatin1String("-"));
const uint degree = regex.cap( c++ ).toUInt();
const qreal minutes = regex.cap( c ).toDouble();
const qreal minutes = parseDouble(regex.cap( c ));
qreal result = degree + (minutes*MIN2HOUR);
......@@ -551,7 +567,7 @@ qreal LonLatParser::degreeValueFromDM( const QRegExp& regex, int c, bool isPosHe
qreal LonLatParser::degreeValueFromD( const QRegExp& regex, int c, bool isPosHemisphere )
{
qreal result = regex.cap( c ).toDouble();
qreal result = parseDouble(regex.cap( c ));
if (! isPosHemisphere)
result *= -1;
......
......@@ -515,6 +515,7 @@ enum SignType {NoSign, PositiveSign, NegativeSign};
enum SphereType {PosSphere, NegSphere};
enum UnitsType {NoUnits, WithUnits};
enum SpacesType {NoSpaces, WithSpaces};
enum LocaleType {CLocale, SystemLocale};
//static QString
//createDegreeString(SignType signType,
......@@ -565,13 +566,18 @@ enum SpacesType {NoSpaces, WithSpaces};
static QString
createDegreeString(SignType signType,
qreal degreeValue,
LocaleType locale,
UnitsType unitsType, SpacesType spacesType)
{
QString string;
// add degree
if (signType != NoSign) string.append(QLatin1Char(signType==PositiveSign?'+':'-'));
string.append(QString::fromLatin1("%L1").arg(degreeValue, 0, 'f', 10));
if (locale == CLocale) {
string.append(QString::number(degreeValue, 'f', 10));
} else {
string.append(QLocale::system().toString(degreeValue, 'f', 10));
}
if (unitsType == WithUnits) string.append(QChar(0xb0));
if (spacesType == WithSpaces) string.append(QLatin1Char(' '));
......@@ -839,6 +845,8 @@ void TestGeoDataCoordinates::testFromStringD_data()
<< NoUnits << WithUnits;
const QVector<SpacesType> spacesTypes = QVector<SpacesType>()
<< NoSpaces << WithSpaces;
const QVector<LocaleType> localeTypes = QVector<LocaleType>()
<< CLocale << SystemLocale;
const QVector<qreal> degreeSamples = QVector<qreal>()
<< qreal(0.0) << qreal(3.14159) << qreal(180.0);
......@@ -859,6 +867,8 @@ void TestGeoDataCoordinates::testFromStringD_data()
(latSphere==PosSphere && latSignType!=NegativeSign) ||
(latSphere==NegSphere && latSignType==NegativeSign);
foreach(const qreal latDegree, degreeSamples) {
// locale
foreach(const LocaleType locale, localeTypes) {
// actual construction
// Create lon & lat values
......@@ -873,11 +883,13 @@ void TestGeoDataCoordinates::testFromStringD_data()
QString string;
string.append(createDegreeString(latSignType,
latDegree,
locale,
unitsType, spacesType));
string.append(QLatin1Char(latSphere==PosSphere?'N':'S'));
string.append(QLatin1Char(' '));
string.append(createDegreeString(lonSignType,
lonDegree,
locale,
unitsType, spacesType));
string.append(QLatin1Char(lonSphere==PosSphere?'E':'W'));
......@@ -887,12 +899,13 @@ void TestGeoDataCoordinates::testFromStringD_data()
.append(QLatin1String(unitsType==WithUnits?"|units":"|no units"))
.append(QLatin1String("|lon:"))
.append(QLatin1Char(lonIsPositive?'+':'-'))
.append(QString::fromLatin1("%L1").arg(lonDegree, 0, 'f', 10)+QChar(0xb0))
.append(QString::number(lonDegree, 'f', 10)+QChar(0xb0))
.append(QLatin1Char(lonSphere==PosSphere?'P':'N'))
.append(QLatin1String("|lat:"))
.append(QLatin1Char(latIsPositive?'+':'-'))
.append(QString::fromLatin1("%L1").arg(latDegree, 0, 'f', 10)+QChar(0xb0))
.append(QString::number(latDegree, 'f', 10)+QChar(0xb0))
.append(QLatin1Char(latSphere==PosSphere?'P':'N'))
.append(QLatin1Char('|')).append(QLatin1Char(locale==CLocale?'C':'L'))
.append(QLatin1Char('|')).append(string).append(QLatin1Char('|'));
QTest::newRow(rowTitle.toLatin1())
<< string
......@@ -906,6 +919,7 @@ void TestGeoDataCoordinates::testFromStringD_data()
}
}
}
}
QTest::newRow("scientific notation") << "0.0,1.0e-2" << qreal(1.0e-2) << qreal(0.0);
QTest::newRow("scientific notation") << "-2.4E0 1.0e-18" << qreal(1e-18) << qreal(-2.4e0);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment