diff --git a/src/app/locator/qgsgotolocatorfilter.cpp b/src/app/locator/qgsgotolocatorfilter.cpp index d286a843e553..fedfac8948d0 100644 --- a/src/app/locator/qgsgotolocatorfilter.cpp +++ b/src/app/locator/qgsgotolocatorfilter.cpp @@ -89,15 +89,30 @@ void QgsGotoLocatorFilter::fetchResults( const QString &string, const QgsLocator if ( !match.hasMatch() ) { // Check if the string is a pair of degree minute second - separatorRx = QRegularExpression( QStringLiteral( "^((?:([-+nsew])\\s*)?\\d{1,3}(?:[^0-9.]+[0-5]?\\d)?[^0-9.]+[0-5]?\\d(?:[\\.\\%1]\\d+)?[^0-9.,]*[-+nsew]?)[,\\s]+((?:([-+nsew])\\s*)?\\d{1,3}(?:[^0-9.]+[0-5]?\\d)?[^0-9.]+[0-5]?\\d(?:[\\.\\%1]\\d+)?[^0-9.,]*[-+nsew]?)$" ) - .arg( locale.decimalPoint() ) ); + const QString dmsRx = QStringLiteral( "\\d{1,3}(?:[^0-9.]+[0-5]?\\d)?[^0-9.]+[0-5]?\\d(?:[\\.\\%1]\\d+)?" ).arg( locale.decimalPoint() ); + separatorRx = QRegularExpression( QStringLiteral( + "^(" + "(\\s*%1[^0-9.,]*[-+NSEWnsew]?)[,\\s]+(%1[^0-9.,]*[-+NSEWnsew]?)" + ")|(" + "((?:([-+NSEWnsew])\\s*)%1[^0-9.,]*)[,\\s]+((?:([-+NSEWnsew])\\s*)%1[^0-9.,]*)" + ")$" + ) + .arg( dmsRx ) ); match = separatorRx.match( string.trimmed() ); if ( match.hasMatch() ) { posIsWgs84 = true; bool isEasting = false; - firstNumber = QgsCoordinateUtils::dmsToDecimal( match.captured( 1 ), &firstOk, &isEasting ); - secondNumber = QgsCoordinateUtils::dmsToDecimal( match.captured( 3 ), &secondOk ); + if ( !match.captured( 1 ).isEmpty() ) + { + firstNumber = QgsCoordinateUtils::dmsToDecimal( match.captured( 2 ), &firstOk, &isEasting ); + secondNumber = QgsCoordinateUtils::dmsToDecimal( match.captured( 3 ), &secondOk ); + } + else + { + firstNumber = QgsCoordinateUtils::dmsToDecimal( match.captured( 5 ), &firstOk, &isEasting ); + secondNumber = QgsCoordinateUtils::dmsToDecimal( match.captured( 7 ), &secondOk ); + } // normalize to northing (i.e. Y) first if ( isEasting ) std::swap( firstNumber, secondNumber ); diff --git a/tests/src/app/testqgsapplocatorfilters.cpp b/tests/src/app/testqgsapplocatorfilters.cpp index 5a243d8ce0ac..b72e74d73a7a 100644 --- a/tests/src/app/testqgsapplocatorfilters.cpp +++ b/tests/src/app/testqgsapplocatorfilters.cpp @@ -32,6 +32,24 @@ #include #include + +struct Result +{ + Result( QString displayString, const QgsPointXY &point, double scale = 0 ) + : displayString( displayString ) + , point( point ) + , scale( scale ) + {} + + QString displayString; + QgsPointXY point; + double scale = 0; +}; + +typedef QList Results; + +Q_DECLARE_METATYPE( Results ) + /** * \ingroup UnitTests * This is a unit test for the field calculator @@ -40,6 +58,7 @@ class TestQgsAppLocatorFilters : public QObject { Q_OBJECT + public: private slots: void initTestCase(); // will be called before the first testfunction is executed. void cleanupTestCase(); // will be called after the last testfunction was executed. @@ -52,6 +71,7 @@ class TestQgsAppLocatorFilters : public QObject void testSearchAllLayers(); void testSearchAllLayersPrioritizeExactMatch(); void testGoto(); + void testGoto_data(); private: QgisApp *mQgisApp = nullptr; @@ -356,77 +376,49 @@ QList TestQgsAppLocatorFilters::gatherResults( QgsLocatorFilte return results; } -void TestQgsAppLocatorFilters::testGoto() +void TestQgsAppLocatorFilters::testGoto_data() { - QgsGotoLocatorFilter filter; - - // simple goto - QList results = gatherResults( &filter, QStringLiteral( "4 5" ), QgsLocatorContext() ); - QCOMPARE( results.count(), 2 ); - QCOMPARE( results.at( 0 ).displayString, QObject::tr( "Go to 4 5 (Map CRS, )" ) ); - QCOMPARE( results.at( 0 ).userData().toMap()[QStringLiteral( "point" )].value(), QgsPointXY( 4, 5 ) ); - QCOMPARE( results.at( 1 ).displayString, QObject::tr( "Go to 4°N 5°E (EPSG:4326 - WGS 84)" ) ); - QCOMPARE( results.at( 1 ).userData().toMap()[QStringLiteral( "point" )].value(), QgsPointXY( 5, 4 ) ); - - // locale-specific goto - results = gatherResults( &filter, QStringLiteral( "1,234.56 789.012" ), QgsLocatorContext() ); - QCOMPARE( results.count(), 1 ); - QCOMPARE( results.at( 0 ).displayString, QObject::tr( "Go to 1,234.56 789.012 (Map CRS, )" ) ); - QCOMPARE( results.at( 0 ).userData().toMap()[QStringLiteral( "point" )].value(), QgsPointXY( 1234.56, 789.012 ) ); - - // decimal degree with suffixes - results = gatherResults( &filter, QStringLiteral( "12.345N, 67.890W" ), QgsLocatorContext() ); - QCOMPARE( results.count(), 1 ); - QCOMPARE( results.at( 0 ).displayString, QObject::tr( "Go to 12.345°N -67.89°E (EPSG:4326 - WGS 84)" ) ); - QCOMPARE( results.at( 0 ).userData().toMap()[QStringLiteral( "point" )].value(), QgsPointXY( -67.890, 12.345 ) ); - - results = gatherResults( &filter, QStringLiteral( "12.345 e, 67.890 s" ), QgsLocatorContext() ); - QCOMPARE( results.count(), 1 ); - QCOMPARE( results.at( 0 ).displayString, QObject::tr( "Go to -67.89°N 12.345°E (EPSG:4326 - WGS 84)" ) ); - QCOMPARE( results.at( 0 ).userData().toMap()[QStringLiteral( "point" )].value(), QgsPointXY( 12.345, -67.890 ) ); - - // degree/minuste/second coordinates goto - // easting northing - results = gatherResults( &filter, QStringLiteral( "40deg 1' 0\" E 11deg 55' 0\" S" ), QgsLocatorContext() ); - QCOMPARE( results.count(), 1 ); - QCOMPARE( results.at( 0 ).displayString, QObject::tr( "Go to -11.91666667°N 40.01666667°E (EPSG:4326 - WGS 84)" ) ); - QCOMPARE( results.at( 0 ).userData().toMap()[QStringLiteral( "point" )].value(), QgsPointXY( 40.0166666667, -11.9166666667 ) ); - - // northing easting - results = gatherResults( &filter, QStringLiteral( "14°49′48″N 01°48′45″E" ), QgsLocatorContext() ); - QCOMPARE( results.count(), 1 ); - QCOMPARE( results.at( 0 ).displayString, QObject::tr( "Go to 14.83°N 1.8125°E (EPSG:4326 - WGS 84)" ) ); - QCOMPARE( results.at( 0 ).userData().toMap()[QStringLiteral( "point" )].value(), QgsPointXY( 1.8125, 14.83 ) ); - - // northing, esting (comma separated) - results = gatherResults( &filter, QStringLiteral( "14°49′48″N, 01°48′45″E" ), QgsLocatorContext() ); - QCOMPARE( results.count(), 1 ); - QCOMPARE( results.at( 0 ).displayString, QObject::tr( "Go to 14.83°N 1.8125°E (EPSG:4326 - WGS 84)" ) ); - QCOMPARE( results.at( 0 ).userData().toMap()[QStringLiteral( "point" )].value(), QgsPointXY( 1.8125, 14.83 ) ); + qRegisterMetaType( "Results" ); + + QTest::addColumn( "string" ); + QTest::addColumn( "expected" ); + + QTest::newRow( "simple" ) << QStringLiteral( "4 5" ) << Results( { { QObject::tr( "Go to 4 5 (Map CRS, )" ), QgsPointXY( 4, 5 ) }, { QObject::tr( "Go to 4°N 5°E (EPSG:4326 - WGS 84)" ), QgsPointXY( 5, 4 ) } } ); + + QTest::newRow( "locale" ) << QStringLiteral( "1,234.56 789.012" ) << Results( { { QObject::tr( "Go to 1,234.56 789.012 (Map CRS, )" ), QgsPointXY( 1234.56, 789.012 ) } } ); + + QTest::newRow( "nort-west" ) << QStringLiteral( "12.345N, 67.890W" ) << Results( { { QObject::tr( "Go to 12.345°N -67.89°E (EPSG:4326 - WGS 84)" ), QgsPointXY( -67.890, 12.345 ) } } ); + QTest::newRow( "east-south" ) << QStringLiteral( "12.345 e, 67.890 s" ) << Results( { { QObject::tr( "Go to -67.89°N 12.345°E (EPSG:4326 - WGS 84)" ), QgsPointXY( 12.345, -67.890 ) } } ); + QTest::newRow( "degree-suffix" ) << QStringLiteral( "40deg 1' 0\" E 11deg 55' 0\" S" ) << Results( { { QObject::tr( "Go to -11.91666667°N 40.01666667°E (EPSG:4326 - WGS 84)" ), QgsPointXY( 40.0166666667, -11.9166666667 ) } } ); + QTest::newRow( "north-east------------" ) << QStringLiteral( "14°49′48″N 01°48′45″E" ) << Results( { { QObject::tr( "Go to 14.83°N 1.8125°E (EPSG:4326 - WGS 84)" ), QgsPointXY( 1.8125, 14.83 ) } } ); + QTest::newRow( "north-east-space------" ) << QStringLiteral( "14°49′48″ N 01°48′45″ E" ) << Results( { { QObject::tr( "Go to 14.83°N 1.8125°E (EPSG:4326 - WGS 84)" ), QgsPointXY( 1.8125, 14.83 ) } } ); + QTest::newRow( "north-east-comma------" ) << QStringLiteral( "14°49′48″N, 01°48′45″E" ) << Results( { { QObject::tr( "Go to 14.83°N 1.8125°E (EPSG:4326 - WGS 84)" ), QgsPointXY( 1.8125, 14.83 ) } } ); + QTest::newRow( "north-east-comma-space" ) << QStringLiteral( "14°49′48″ N, 01°48′45″ E" ) << Results( { { QObject::tr( "Go to 14.83°N 1.8125°E (EPSG:4326 - WGS 84)" ), QgsPointXY( 1.8125, 14.83 ) } } ); + QTest::newRow( "north-east-front------" ) << QStringLiteral( "N 14°49′48″ E 01°48′45″" ) << Results( { { QObject::tr( "Go to 14.83°N 1.8125°E (EPSG:4326 - WGS 84)" ), QgsPointXY( 1.8125, 14.83 ) } } ); + QTest::newRow( "north-east-front-comma" ) << QStringLiteral( "N 14°49′48″, E 01°48′45″" ) << Results( { { QObject::tr( "Go to 14.83°N 1.8125°E (EPSG:4326 - WGS 84)" ), QgsPointXY( 1.8125, 14.83 ) } } ); + QTest::newRow( "osm.leaflet.OL" ) << QStringLiteral( "https://www.openstreetmap.org/#map=15/44.5546/6.4936" ) << Results( { { QObject::tr( "Go to 44.5546°N 6.4936°E at scale 1:22569 (EPSG:4326 - WGS 84)" ), QgsPointXY( 6.4936, 44.5546 ), 22569.0 } } ); + QTest::newRow( "gmaps1" ) << QStringLiteral( "https://www.google.com/maps/@44.5546,6.4936,15.25z" ) << Results( { { QObject::tr( "Go to 44.5546°N 6.4936°E at scale 1:22569 (EPSG:4326 - WGS 84)" ), QgsPointXY( 6.4936, 44.5546 ), 22569.0 } } ); + QTest::newRow( "gmaps2" ) << QStringLiteral( "https://www.google.com/maps/@7.8750,81.0149,574195m/data=!3m1!1e3" ) << Results( { { QObject::tr( "Go to 7.875°N 81.0149°E at scale 1:6.49572e+07 (EPSG:4326 - WGS 84)" ), QgsPointXY( 81.0149, 7.8750 ) } } ); + QTest::newRow( "gmaps3" ) << QStringLiteral( "https://www.google.com/maps/@27.7132,85.3288,3a,75y,278.89h,90t/data=!3m8!1e1!3m6!1sAF1QipMrXuXozGc9x9bxx5uPl_3ys4H-rNVqMLr6EYLA!2e10!3e11!6shttps:%2F%2Flh5.googleusercontent.com%2Fp%2FAF1QipMrXuXozGc9x9bxx5uPl_3ys4H-rNVqMLr6EYLA%3Dw203-h100-k-no-pi2.869903-ya293.58762-ro-1.9255565-fo100!7i3840!8i1920" ) << Results( { { QObject::tr( "Go to 27.7132°N 85.3288°E at scale 1:282 (EPSG:4326 - WGS 84)" ), QgsPointXY( 85.3288, 27.7132 ), 282.0 } } ); +} - // OSM/Leaflet/OpenLayers - results = gatherResults( &filter, QStringLiteral( "https://www.openstreetmap.org/#map=15/44.5546/6.4936" ), QgsLocatorContext() ); - QCOMPARE( results.count(), 1 ); - QCOMPARE( results.at( 0 ).displayString, QObject::tr( "Go to 44.5546°N 6.4936°E at scale 1:22569 (EPSG:4326 - WGS 84)" ) ); - QCOMPARE( results.at( 0 ).userData().toMap()[QStringLiteral( "point" )].value(), QgsPointXY( 6.4936, 44.5546 ) ); - QCOMPARE( results.at( 0 ).userData().toMap()[QStringLiteral( "scale" )].toDouble(), 22569.0 ); +void TestQgsAppLocatorFilters::testGoto() +{ + QFETCH( QString, string ); + QFETCH( Results, expected ); - // Google Maps - results = gatherResults( &filter, QStringLiteral( "https://www.google.com/maps/@44.5546,6.4936,15.25z" ), QgsLocatorContext() ); - QCOMPARE( results.count(), 1 ); - QCOMPARE( results.at( 0 ).displayString, QObject::tr( "Go to 44.5546°N 6.4936°E at scale 1:22569 (EPSG:4326 - WGS 84)" ) ); - QCOMPARE( results.at( 0 ).userData().toMap()[QStringLiteral( "point" )].value(), QgsPointXY( 6.4936, 44.5546 ) ); - QCOMPARE( results.at( 0 ).userData().toMap()[QStringLiteral( "scale" )].toDouble(), 22569.0 ); + QgsGotoLocatorFilter filter; - results = gatherResults( &filter, QStringLiteral( "https://www.google.com/maps/@7.8750,81.0149,574195m/data=!3m1!1e3" ), QgsLocatorContext() ); - QCOMPARE( results.count(), 1 ); - QCOMPARE( results.at( 0 ).userData().toMap()[QStringLiteral( "point" )].value(), QgsPointXY( 81.0149, 7.8750 ) ); + QList results = gatherResults( &filter, string, QgsLocatorContext() ); + QCOMPARE( results.count(), expected.count() ); - results = gatherResults( &filter, QStringLiteral( "https://www.google.com/maps/@27.7132,85.3288,3a,75y,278.89h,90t/data=!3m8!1e1!3m6!1sAF1QipMrXuXozGc9x9bxx5uPl_3ys4H-rNVqMLr6EYLA!2e10!3e11!6shttps:%2F%2Flh5.googleusercontent.com%2Fp%2FAF1QipMrXuXozGc9x9bxx5uPl_3ys4H-rNVqMLr6EYLA%3Dw203-h100-k-no-pi2.869903-ya293.58762-ro-1.9255565-fo100!7i3840!8i1920" ), QgsLocatorContext() ); - QCOMPARE( results.count(), 1 ); - QCOMPARE( results.at( 0 ).displayString, QObject::tr( "Go to 27.7132°N 85.3288°E at scale 1:282 (EPSG:4326 - WGS 84)" ) ); - QCOMPARE( results.at( 0 ).userData().toMap()[QStringLiteral( "point" )].value(), QgsPointXY( 85.3288, 27.7132 ) ); - QCOMPARE( results.at( 0 ).userData().toMap()[QStringLiteral( "scale" )].toDouble(), 282.0 ); + for ( int i = 0; i < results.count(); i++ ) + { + QCOMPARE( results.at( i ).displayString, expected.at( i ).displayString ); + QCOMPARE( results.at( i ).userData().toMap()[QStringLiteral( "point" )].value(), expected.at( i ).point ); + if ( expected.at( i ).scale > 0 ) + QCOMPARE( results.at( 0 ).userData().toMap()[QStringLiteral( "scale" )].toDouble(), expected.at( i ).scale ); + } } QGSTEST_MAIN( TestQgsAppLocatorFilters )