Ignore position of thousands seperators when editing scale combo box

... be more permissive about the conversion from string to number
after a value is entered in the combo box (fix #12385)
This commit is contained in:
Nyall Dawson 2015-03-17 17:41:13 +11:00
parent c98ae01c49
commit a4d17c0e9b
7 changed files with 212 additions and 13 deletions

View File

@ -134,6 +134,26 @@ class QGis
//! Returns the conversion factor between the specified units
static double fromUnitToUnitFactor( QGis::UnitType fromUnit, QGis::UnitType toUnit );
/** Converts a string to a double in a permissive way, eg allowing for incorrect
* numbers of digits between thousand seperators
* @param string string to convert
* @param ok will be set to true if conversion was successful
* @returns string converted to double if possible
* @note added in version 2.9
* @see permissiveToInt
*/
static double permissiveToDouble( QString string, bool& ok );
/** Converts a string to an integer in a permissive way, eg allowing for incorrect
* numbers of digits between thousand seperators
* @param string string to convert
* @param ok will be set to true if conversion was successful
* @returns string converted to int if possible
* @note added in version 2.9
* @see permissiveToDouble
*/
static int permissiveToInt( QString string, bool& ok );
//! User defined event types
enum UserEvent
{

View File

@ -23,6 +23,7 @@
#include <QColor>
#include <QDate>
#include <QTime>
#include <QLocale>
#include <QDateTime>
#include "qgsconfig.h"
#include "qgslogger.h"
@ -184,6 +185,20 @@ double QGis::fromUnitToUnitFactor( QGis::UnitType fromUnit, QGis::UnitType toUni
return 1.0;
}
double QGis::permissiveToDouble( QString string, bool &ok )
{
//remove any thousands seperators
string.remove( QLocale::system().groupSeparator() );
return QLocale::system().toDouble( string, &ok );
}
int QGis::permissiveToInt( QString string, bool &ok )
{
//remove any thousands seperators
string.remove( QLocale::system().groupSeparator() );
return QLocale::system().toInt( string, &ok );
}
void *qgsMalloc( size_t size )
{
if ( size == 0 || long( size ) < 0 )

View File

@ -251,6 +251,26 @@ class CORE_EXPORT QGis
//! Returns the conversion factor between the specified units
static double fromUnitToUnitFactor( QGis::UnitType fromUnit, QGis::UnitType toUnit );
/** Converts a string to a double in a permissive way, eg allowing for incorrect
* numbers of digits between thousand seperators
* @param string string to convert
* @param ok will be set to true if conversion was successful
* @returns string converted to double if possible
* @note added in version 2.9
* @see permissiveToInt
*/
static double permissiveToDouble( QString string, bool& ok );
/** Converts a string to an integer in a permissive way, eg allowing for incorrect
* numbers of digits between thousand seperators
* @param string string to convert
* @param ok will be set to true if conversion was successful
* @returns string converted to int if possible
* @note added in version 2.9
* @see permissiveToDouble
*/
static int permissiveToInt( QString string, bool& ok );
//! User defined event types
enum UserEvent
{

View File

@ -206,27 +206,29 @@ double QgsScaleComboBox::toDouble( QString scaleString, bool * returnOk )
bool ok = false;
QString scaleTxt( scaleString );
double scale = QLocale::system().toDouble( scaleTxt, &ok );
double scale = QGis::permissiveToDouble( scaleTxt, ok );
if ( ok )
{
// Create a text version and set that text and rescan
// Idea is to get the same rounding.
scaleTxt = toString( scale );
}
// It is now either X:Y or not valid
ok = false;
QStringList txtList = scaleTxt.split( ':' );
if ( 2 == txtList.size() )
else
{
bool okX = false;
bool okY = false;
int x = QLocale::system().toInt( txtList[ 0 ], &okX );
int y = QLocale::system().toInt( txtList[ 1 ], &okY );
if ( okX && okY )
// It is now either X:Y or not valid
QStringList txtList = scaleTxt.split( ':' );
if ( 2 == txtList.size() )
{
// Scale is fraction of x and y
scale = ( double )x / ( double )y;
ok = true;
bool okX = false;
bool okY = false;
int x = QGis::permissiveToInt( txtList[ 0 ], okX );
int y = QGis::permissiveToInt( txtList[ 1 ], okY );
if ( okX && okY )
{
// Scale is fraction of x and y
scale = ( double )x / ( double )y;
ok = true;
}
}
}

View File

@ -76,6 +76,7 @@ ENDMACRO (ADD_QGIS_TEST)
#############################################################
# Tests:
ADD_QGIS_TEST(qgistest testqgis.cpp)
ADD_QGIS_TEST(clippertest testqgsclipper.cpp)
ADD_QGIS_TEST(distanceareatest testqgsdistancearea.cpp)
ADD_QGIS_TEST(applicationtest testqgsapplication.cpp)

123
tests/src/core/testqgis.cpp Normal file
View File

@ -0,0 +1,123 @@
/***************************************************************************
testqgis.cpp
------------
Date : March 2015
Copyright : (C) 2015 by Nyall Dawson
Email : nyall.dawson@gmail.com
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include <QtTest/QtTest>
#include <QObject>
#include <QString>
#include <QApplication>
//qgis includes...
#include <qgis.h>
/** \ingroup UnitTests
* Includes unit tests for the QGis namespace
*/
class TestQGis : public QObject
{
Q_OBJECT
private slots:
void initTestCase();// will be called before the first testfunction is executed.
void cleanupTestCase();// will be called after the last testfunction was executed.
void init() {}// will be called before each testfunction is executed.
void cleanup() {}// will be called after every testfunction.
void permissiveToDouble();
void permissiveToInt();
private:
QString mReport;
};
//runs before all tests
void TestQGis::initTestCase()
{
mReport = "<h1>QGis Tests</h1>\n";
}
//runs after all tests
void TestQGis::cleanupTestCase()
{
QString myReportFile = QDir::tempPath() + QDir::separator() + "qgistest.html";
QFile myFile( myReportFile );
if ( myFile.open( QIODevice::WriteOnly | QIODevice::Append ) )
{
QTextStream myQTextStream( &myFile );
myQTextStream << mReport;
myFile.close();
}
}
void TestQGis::permissiveToDouble()
{
//good inputs
bool ok = false;
double result = QGis::permissiveToDouble( QString( "1000" ), ok );
QVERIFY( ok );
QCOMPARE( result, 1000.0 );
ok = false;
result = QGis::permissiveToDouble( QString( "1%01000" ).arg( QLocale::system().groupSeparator() ), ok );
QVERIFY( ok );
QCOMPARE( result, 1000.0 );
ok = false;
result = QGis::permissiveToDouble( QString( "5.5" ), ok );
QVERIFY( ok );
QCOMPARE( result, 5.5 );
ok = false;
result = QGis::permissiveToDouble( QString( "1%01000.5" ).arg( QLocale::system().groupSeparator() ), ok );
QVERIFY( ok );
QCOMPARE( result, 1000.5 );
//bad input
ok = false;
result = QGis::permissiveToDouble( QString( "a" ), ok );
QVERIFY( !ok );
//messy input (invalid thousand seperator position), should still be converted
ok = false;
result = QGis::permissiveToDouble( QString( "10%0100" ).arg( QLocale::system().groupSeparator() ), ok );
QVERIFY( ok );
QCOMPARE( result, 1000.0 );
ok = false;
result = QGis::permissiveToDouble( QString( "10%0100.5" ).arg( QLocale::system().groupSeparator() ), ok );
QVERIFY( ok );
QCOMPARE( result, 1000.5 );
}
void TestQGis::permissiveToInt()
{
//good inputs
bool ok = false;
int result = QGis::permissiveToInt( QString( "1000" ), ok );
QVERIFY( ok );
QCOMPARE( result, 1000 );
ok = false;
result = QGis::permissiveToInt( QString( "1%01000" ).arg( QLocale::system().groupSeparator() ), ok );
QVERIFY( ok );
QCOMPARE( result, 1000 );
//bad input
ok = false;
result = QGis::permissiveToInt( QString( "a" ), ok );
QVERIFY( !ok );
//messy input (invalid thousand seperator position), should still be converted
ok = false;
result = QGis::permissiveToInt( QString( "10%0100" ).arg( QLocale::system().groupSeparator() ), ok );
QVERIFY( ok );
QCOMPARE( result, 1000 );
}
QTEST_MAIN( TestQGis )
#include "testqgis.moc"

View File

@ -88,6 +88,24 @@ void TestQgsScaleComboBox::basic()
QCOMPARE( s->scaleString(), QString( "1:%1" ).arg( QLocale::system().toString( 42 ) ) );
QCOMPARE( s->scale(), ( double ) 1.0 / ( double ) 42.0 );
// Testing conversion from number to "1:x,000"
l->setText( "" );
QString str = QString( "1%01000%01000" ).arg( QLocale::system().groupSeparator() );
QTest::keyClicks( l, str );
QTest::keyClick( l, Qt::Key_Return );
QCOMPARE( s->scaleString(), QString( "1:%1" ).arg( str ) );
QCOMPARE( s->scale(), ( double ) 1.0 / ( double ) 1000000.0 );
// Testing conversion from number to "1:x,000" with wonky seperators
//(eg four digits between thousands, which should be fixed automatically)
l->setText( "" );
str = QString( "1%010000%01000" ).arg( QLocale::system().groupSeparator() );
QString fixedStr = QString( "10%01000%01000" ).arg( QLocale::system().groupSeparator() );
QTest::keyClicks( l, str );
QTest::keyClick( l, Qt::Key_Return );
QCOMPARE( s->scaleString(), QString( "1:%1" ).arg( fixedStr ) );
QCOMPARE( s->scale(), ( double ) 1.0 / ( double ) 10000000.0 );
// Testing rounding and conversion from illegal
l->setText( "" );