Skip to content

Commit

Permalink
Ignore position of thousands seperators when editing scale combo box
Browse files Browse the repository at this point in the history
... be more permissive about the conversion from string to number
after a value is entered in the combo box (fix #12385)
  • Loading branch information
nyalldawson committed Mar 17, 2015
1 parent c98ae01 commit a4d17c0
Show file tree
Hide file tree
Showing 7 changed files with 212 additions and 13 deletions.
20 changes: 20 additions & 0 deletions python/core/qgis.sip
Expand Up @@ -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
{
Expand Down
15 changes: 15 additions & 0 deletions src/core/qgis.cpp
Expand Up @@ -23,6 +23,7 @@
#include <QColor>
#include <QDate>
#include <QTime>
#include <QLocale>
#include <QDateTime>
#include "qgsconfig.h"
#include "qgslogger.h"
Expand Down Expand Up @@ -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 )
Expand Down
20 changes: 20 additions & 0 deletions src/core/qgis.h
Expand Up @@ -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
{
Expand Down
28 changes: 15 additions & 13 deletions src/gui/qgsscalecombobox.cpp
Expand Up @@ -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;
}
}
}

Expand Down
1 change: 1 addition & 0 deletions tests/src/core/CMakeLists.txt
Expand Up @@ -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)
Expand Down
123 changes: 123 additions & 0 deletions tests/src/core/testqgis.cpp
@@ -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"
18 changes: 18 additions & 0 deletions tests/src/gui/testqgsscalecombobox.cpp
Expand Up @@ -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( "" );
Expand Down

0 comments on commit a4d17c0

Please sign in to comment.