From db10e7d4ec0c8f9a7da6d60e8795b2bf2b97782e Mon Sep 17 00:00:00 2001 From: Alessandro Pasotti Date: Mon, 21 Feb 2022 17:15:01 +0100 Subject: [PATCH 1/2] Advanced digitizing: be nice with non-dot locales Fix #47465 --- src/gui/qgsadvanceddigitizingdockwidget.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/gui/qgsadvanceddigitizingdockwidget.cpp b/src/gui/qgsadvanceddigitizingdockwidget.cpp index a4daf970bd9..b3b0d0988af 100644 --- a/src/gui/qgsadvanceddigitizingdockwidget.cpp +++ b/src/gui/qgsadvanceddigitizingdockwidget.cpp @@ -616,9 +616,23 @@ double QgsAdvancedDigitizingDockWidget::parseUserInput( const QString &inputValu QgsExpression expr( inputValue ); const QVariant result = expr.evaluate(); if ( expr.hasEvalError() ) + { ok = false; + // Be nice with non-dot locales + if ( QLocale().decimalPoint() != QChar( '.' ) && inputValue.contains( QLocale().decimalPoint() ) ) + { + QgsExpression exprC( QString( inputValue ).replace( QLocale().decimalPoint(), QChar( '.' ) ) ); + const QVariant resultC = exprC.evaluate(); + if ( ! exprC.hasEvalError() ) + { + value = resultC.toDouble( &ok ); + } + } + } else + { value = result.toDouble( &ok ); + } return value; } } From 52dd15b764528a462b7fcb752139b6e5d7e7ef84 Mon Sep 17 00:00:00 2001 From: Alessandro Pasotti Date: Tue, 22 Feb 2022 10:29:47 +0100 Subject: [PATCH 2/2] Add test case for QgsAdvancedDigitizingDockWidget --- src/gui/qgsadvanceddigitizingdockwidget.cpp | 20 +++- src/gui/qgsadvanceddigitizingdockwidget.h | 4 +- tests/src/gui/CMakeLists.txt | 1 + .../testqgsadvanceddigitizingdockwidget.cpp | 107 ++++++++++++++++++ 4 files changed, 128 insertions(+), 4 deletions(-) create mode 100644 tests/src/gui/testqgsadvanceddigitizingdockwidget.cpp diff --git a/src/gui/qgsadvanceddigitizingdockwidget.cpp b/src/gui/qgsadvanceddigitizingdockwidget.cpp index b3b0d0988af..5c2529b500f 100644 --- a/src/gui/qgsadvanceddigitizingdockwidget.cpp +++ b/src/gui/qgsadvanceddigitizingdockwidget.cpp @@ -618,10 +618,24 @@ double QgsAdvancedDigitizingDockWidget::parseUserInput( const QString &inputValu if ( expr.hasEvalError() ) { ok = false; - // Be nice with non-dot locales - if ( QLocale().decimalPoint() != QChar( '.' ) && inputValue.contains( QLocale().decimalPoint() ) ) + QString inputValueC { inputValue }; + + // First: try removing group separator + if ( inputValue.contains( QLocale().groupSeparator() ) ) { - QgsExpression exprC( QString( inputValue ).replace( QLocale().decimalPoint(), QChar( '.' ) ) ); + inputValueC.remove( QLocale().groupSeparator() ); + QgsExpression exprC( inputValueC ); + const QVariant resultC = exprC.evaluate(); + if ( ! exprC.hasEvalError() ) + { + value = resultC.toDouble( &ok ); + } + } + + // Second: be nice with non-dot locales + if ( !ok && QLocale().decimalPoint() != QChar( '.' ) && inputValueC.contains( QLocale().decimalPoint() ) ) + { + QgsExpression exprC( inputValueC .replace( QLocale().decimalPoint(), QChar( '.' ) ) ); const QVariant resultC = exprC.evaluate(); if ( ! exprC.hasEvalError() ) { diff --git a/src/gui/qgsadvanceddigitizingdockwidget.h b/src/gui/qgsadvanceddigitizingdockwidget.h index c5752ed622d..326916e1793 100644 --- a/src/gui/qgsadvanceddigitizingdockwidget.h +++ b/src/gui/qgsadvanceddigitizingdockwidget.h @@ -960,13 +960,15 @@ class GUI_EXPORT QgsAdvancedDigitizingDockWidget : public QgsDockWidget, private // Snap indicator QgsPointLocator::Match mSnapMatch; - private: + #ifdef SIP_RUN //! event filter for line edits in the dock UI (angle/distance/x/y line edits) bool eventFilter( QObject *obj, QEvent *event ); #endif //! Convenient method to convert a 2D Point to a QgsPoint QgsPoint pointXYToPoint( const QgsPointXY &point ) const; + + friend class TestQgsAdvancedDigitizingDockWidget; }; Q_DECLARE_OPERATORS_FOR_FLAGS( QgsAdvancedDigitizingDockWidget::CadCapacities ) diff --git a/tests/src/gui/CMakeLists.txt b/tests/src/gui/CMakeLists.txt index 0a0a64b11a4..c50909a8171 100644 --- a/tests/src/gui/CMakeLists.txt +++ b/tests/src/gui/CMakeLists.txt @@ -24,6 +24,7 @@ endif() #ADD_QGIS_TEST(histogramtest testqgsrasterhistogram.cpp) set(TESTS + testqgsadvanceddigitizingdockwidget.cpp testqgsannotationitemguiregistry.cpp testqgsmaptoolzoom.cpp testqgsmaptooledit.cpp diff --git a/tests/src/gui/testqgsadvanceddigitizingdockwidget.cpp b/tests/src/gui/testqgsadvanceddigitizingdockwidget.cpp new file mode 100644 index 00000000000..d4fdf38d525 --- /dev/null +++ b/tests/src/gui/testqgsadvanceddigitizingdockwidget.cpp @@ -0,0 +1,107 @@ +/*************************************************************************** + testqgsadvanceddigitizingdockwidget.cpp + -------------------------------------- + Date : February 2022 + Copyright : (C) 2022 Alessandro Pasotti + Email : elpaso at itopen dot it + *************************************************************************** + * * + * 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 +#include + +#include "qgstest.h" +#include "qgsapplication.h" +#include "qgsmapcanvas.h" +#include "qgsadvanceddigitizingdockwidget.h" + +class TestQgsAdvancedDigitizingDockWidget : public QObject +{ + Q_OBJECT + public: + TestQgsAdvancedDigitizingDockWidget() = default; + + 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 parseUserInput(); + +}; + +void TestQgsAdvancedDigitizingDockWidget::initTestCase() +{ + QgsApplication::init(); + QgsApplication::initQgis(); + QgsApplication::showSettings(); +} + +void TestQgsAdvancedDigitizingDockWidget::cleanupTestCase() +{ + QgsApplication::exitQgis(); +} + +void TestQgsAdvancedDigitizingDockWidget::init() +{ +} + +void TestQgsAdvancedDigitizingDockWidget::cleanup() +{ +} + +void TestQgsAdvancedDigitizingDockWidget::parseUserInput() +{ + QgsProject::instance()->clear(); + QgsMapCanvas canvas; + QgsAdvancedDigitizingDockWidget widget{ &canvas }; + + bool ok; + double result; + + QLocale::setDefault( QLocale::English ); + + result = widget.parseUserInput( QStringLiteral( "1.2345" ), ok ); + QCOMPARE( result, 1.2345 ); + QVERIFY( ok ); + + result = widget.parseUserInput( QStringLiteral( "1,234.5" ), ok ); + QCOMPARE( result, 1234.5 ); + QVERIFY( ok ); + + result = widget.parseUserInput( QStringLiteral( "1,200.6/2" ), ok ); + QCOMPARE( result, 600.3 ); + QVERIFY( ok ); + + result = widget.parseUserInput( QStringLiteral( "1200.6/2" ), ok ); + QCOMPARE( result, 600.3 ); + QVERIFY( ok ); + + QLocale::setDefault( QLocale::Italian ); + + result = widget.parseUserInput( QStringLiteral( "1,2345" ), ok ); + QCOMPARE( result, 1.2345 ); + QVERIFY( ok ); + + result = widget.parseUserInput( QStringLiteral( "1.234,5" ), ok ); + QCOMPARE( result, 1234.5 ); + QVERIFY( ok ); + + result = widget.parseUserInput( QStringLiteral( "1.200,6/2" ), ok ); + QCOMPARE( result, 600.3 ); + QVERIFY( ok ); + + result = widget.parseUserInput( QStringLiteral( "1200,6/2" ), ok ); + QCOMPARE( result, 600.3 ); + QVERIFY( ok ); + +} + +QGSTEST_MAIN( TestQgsAdvancedDigitizingDockWidget ) +#include "testqgsadvanceddigitizingdockwidget.moc"