mirror of
https://github.com/qgis/QGIS.git
synced 2025-02-28 00:17:30 -05:00
[FEATURE][locator] Add a goto locator
This commit is contained in:
parent
0bb9174c2a
commit
44fd606595
@ -15,10 +15,16 @@
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include <QToolButton>
|
||||
#include <QClipboard>
|
||||
#include <QMap>
|
||||
#include <QString>
|
||||
#include <QToolButton>
|
||||
#include <QUrl>
|
||||
|
||||
#include "qgsapplication.h"
|
||||
#include "qgscoordinatereferencesystem.h"
|
||||
#include "qgscoordinatetransform.h"
|
||||
#include "qgscoordinateutils.h"
|
||||
#include "qgsinbuiltlocatorfilters.h"
|
||||
#include "qgsproject.h"
|
||||
#include "qgslayertree.h"
|
||||
@ -702,3 +708,205 @@ void QgsBookmarkLocatorFilter::triggerResult( const QgsLocatorResult &result )
|
||||
QModelIndex index = qvariant_cast<QModelIndex>( result.userData );
|
||||
QgisApp::instance()->zoomToBookmarkIndex( index );
|
||||
}
|
||||
|
||||
//
|
||||
// QgsGotoLocatorFilter
|
||||
//
|
||||
|
||||
QgsGotoLocatorFilter::QgsGotoLocatorFilter( QObject *parent )
|
||||
: QgsLocatorFilter( parent )
|
||||
{}
|
||||
|
||||
QgsGotoLocatorFilter *QgsGotoLocatorFilter::clone() const
|
||||
{
|
||||
return new QgsGotoLocatorFilter();
|
||||
}
|
||||
|
||||
void QgsGotoLocatorFilter::fetchResults( const QString &string, const QgsLocatorContext &, QgsFeedback *feedback )
|
||||
{
|
||||
if ( feedback->isCanceled() )
|
||||
return;
|
||||
|
||||
const QgsCoordinateReferenceSystem currentCrs = QgisApp::instance()->mapCanvas()->mapSettings().destinationCrs();
|
||||
const QgsCoordinateReferenceSystem wgs84Crs( QStringLiteral( "EPSG:4326" ) );
|
||||
|
||||
// Coordinates such as 106.8468,-6.3804
|
||||
QStringList coordinates = string.split( ' ' );
|
||||
if ( coordinates.size() != 2 )
|
||||
{
|
||||
coordinates = string.split( ',' );
|
||||
}
|
||||
|
||||
if ( coordinates.size() == 2 )
|
||||
{
|
||||
bool okX = false;
|
||||
bool okY = false;
|
||||
double posX = coordinates.at( 0 ).toDouble( &okX );
|
||||
double posY = coordinates.at( 1 ).toDouble( &okY );
|
||||
|
||||
if ( okX && okY )
|
||||
{
|
||||
QVariantMap data;
|
||||
QgsPointXY point( posX, posY );
|
||||
data.insert( QStringLiteral( "point" ), point );
|
||||
|
||||
bool withinWgs84 = wgs84Crs.bounds().contains( point );
|
||||
if ( currentCrs != wgs84Crs )
|
||||
{
|
||||
QgsLocatorResult result;
|
||||
result.filter = this;
|
||||
result.displayString = tr( "Go to %1 %2 (Map CRS, %3)" ).arg( QString::number( point.x(), 'g', 10 ), QString::number( point.y(), 'g', 10 ), currentCrs.userFriendlyIdentifier() );
|
||||
result.userData = data;
|
||||
result.score = 0.9;
|
||||
emit resultFetched( result );
|
||||
}
|
||||
|
||||
if ( withinWgs84 )
|
||||
{
|
||||
if ( currentCrs != wgs84Crs )
|
||||
{
|
||||
QgsCoordinateTransform transform( wgs84Crs, currentCrs, QgsProject::instance()->transformContext() );
|
||||
QgsPointXY transformedPoint;
|
||||
try
|
||||
{
|
||||
transformedPoint = transform.transform( point );
|
||||
}
|
||||
catch ( const QgsException &e )
|
||||
{
|
||||
Q_UNUSED( e )
|
||||
return;
|
||||
}
|
||||
data[QStringLiteral( "point" )] = transformedPoint;
|
||||
}
|
||||
|
||||
QgsLocatorResult result;
|
||||
result.filter = this;
|
||||
result.displayString = tr( "Go to %1° %2° (%3)" ).arg( QString::number( point.x(), 'g', 10 ), QString::number( point.y(), 'g', 10 ), wgs84Crs.userFriendlyIdentifier() );
|
||||
result.userData = data;
|
||||
result.score = 1.0;
|
||||
emit resultFetched( result );
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
QMap<int, double> scales;
|
||||
scales[0] = 739571909;
|
||||
scales[1] = 369785954;
|
||||
scales[2] = 184892977;
|
||||
scales[3] = 92446488;
|
||||
scales[4] = 46223244;
|
||||
scales[5] = 23111622;
|
||||
scales[6] = 11555811;
|
||||
scales[7] = 5777905;
|
||||
scales[8] = 2888952;
|
||||
scales[9] = 1444476;
|
||||
scales[10] = 722238;
|
||||
scales[11] = 361119;
|
||||
scales[12] = 180559;
|
||||
scales[13] = 90279;
|
||||
scales[14] = 45139;
|
||||
scales[15] = 22569;
|
||||
scales[16] = 11284;
|
||||
scales[17] = 5642;
|
||||
scales[18] = 2821;
|
||||
scales[19] = 1500;
|
||||
scales[20] = 1000;
|
||||
|
||||
QUrl url( string );
|
||||
if ( url.isValid() )
|
||||
{
|
||||
double scale = 0.0;
|
||||
bool okX = false;
|
||||
bool okY = false;
|
||||
double posX = 0.0;
|
||||
double posY = 0.0;
|
||||
if ( url.hasFragment() )
|
||||
{
|
||||
// Check for OSM/Leaflet/OpenLayers pattern (e.g. http://www.openstreetmap.org/#map=6/46.423/4.746)
|
||||
QStringList fragments = url.fragment().split( '&' );
|
||||
for ( const QString &fragment : fragments )
|
||||
{
|
||||
if ( fragment.startsWith( QStringLiteral( "map=" ) ) )
|
||||
{
|
||||
QStringList params = fragment.mid( 4 ).split( '/' );
|
||||
if ( params.size() >= 3 )
|
||||
{
|
||||
if ( scales.contains( params.at( 0 ).toInt() ) )
|
||||
{
|
||||
scale = scales.value( params.at( 0 ).toInt() );
|
||||
}
|
||||
posX = params.at( 2 ).toDouble( &okX );
|
||||
posY = params.at( 1 ).toDouble( &okY );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( !okX && !okY && string.indexOf( QStringLiteral( "google.com/maps/" ) ) != -1 )
|
||||
{
|
||||
QRegularExpression locationRx( QStringLiteral( "\\/@([0-9\\-\\.\\,]*)z" ) );
|
||||
QRegularExpressionMatch match = locationRx.match( string );
|
||||
if ( match.hasMatch() )
|
||||
{
|
||||
QStringList params = match.captured( 1 ).split( ',' );
|
||||
if ( params.size() == 3 )
|
||||
{
|
||||
if ( scales.contains( params.at( 2 ).toInt() ) )
|
||||
{
|
||||
scale = scales.value( params.at( 2 ).toInt() );
|
||||
}
|
||||
posX = params.at( 1 ).toDouble( &okX );
|
||||
posY = params.at( 0 ).toDouble( &okY );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( okX && okY )
|
||||
{
|
||||
QVariantMap data;
|
||||
if ( scale > 0.0 )
|
||||
{
|
||||
data.insert( QStringLiteral( "scale" ), scale );
|
||||
}
|
||||
|
||||
QgsPointXY point( posX, posY );
|
||||
bool withinWgs84 = wgs84Crs.bounds().contains( point );
|
||||
if ( withinWgs84 && currentCrs != wgs84Crs )
|
||||
{
|
||||
QgsCoordinateTransform transform( wgs84Crs, currentCrs, QgsProject::instance()->transformContext() );
|
||||
QgsPointXY transformedPoint = transform.transform( point );
|
||||
data.insert( QStringLiteral( "point" ), transformedPoint );
|
||||
}
|
||||
else
|
||||
{
|
||||
data.insert( QStringLiteral( "point" ), point );
|
||||
}
|
||||
|
||||
QgsLocatorResult result;
|
||||
result.filter = this;
|
||||
result.displayString = tr( "Go to %1° %2° %3(%4)" ).arg( QString::number( point.x(), 'g', 10 ), QString::number( point.y(), 'g', 10 ),
|
||||
scale > 0.0 ? tr( "at scale 1:%1 " ).arg( scale ) : QString(),
|
||||
wgs84Crs.userFriendlyIdentifier() );
|
||||
result.userData = data;
|
||||
result.score = 1.0;
|
||||
emit resultFetched( result );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QgsGotoLocatorFilter::triggerResult( const QgsLocatorResult &result )
|
||||
{
|
||||
QVariantMap data = result.userData.toMap();
|
||||
QgsMapCanvas *mapCanvas = QgisApp::instance()->mapCanvas();
|
||||
mapCanvas->setCenter( data[QStringLiteral( "point" )].value<QgsPointXY>() );
|
||||
if ( data.contains( QStringLiteral( "scale" ) ) )
|
||||
{
|
||||
mapCanvas->zoomScale( data[QStringLiteral( "scale" )].toDouble() );
|
||||
}
|
||||
else
|
||||
{
|
||||
mapCanvas->refresh();
|
||||
}
|
||||
}
|
||||
|
@ -219,6 +219,25 @@ class APP_EXPORT QgsSettingsLocatorFilter : public QgsLocatorFilter
|
||||
QMap<QString, QString> settingsPage( const QString &type, const QString &page );
|
||||
};
|
||||
|
||||
class APP_EXPORT QgsGotoLocatorFilter : public QgsLocatorFilter
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
|
||||
QgsGotoLocatorFilter( QObject *parent = nullptr );
|
||||
QgsGotoLocatorFilter *clone() const override;
|
||||
virtual QString name() const override { return QStringLiteral( "goto" ); }
|
||||
virtual QString displayName() const override { return tr( "Go to" ); }
|
||||
virtual Priority priority() const override { return Medium; }
|
||||
QString prefix() const override { return QStringLiteral( "goto" ); }
|
||||
|
||||
void fetchResults( const QString &string, const QgsLocatorContext &context, QgsFeedback *feedback ) override;
|
||||
void triggerResult( const QgsLocatorResult &result ) override;
|
||||
|
||||
};
|
||||
|
||||
#endif // QGSINBUILTLOCATORFILTERS_H
|
||||
|
||||
|
||||
|
@ -3839,6 +3839,7 @@ void QgisApp::createStatusBar()
|
||||
mLocatorWidget->locator()->registerFilter( new QgsExpressionCalculatorLocatorFilter() );
|
||||
mLocatorWidget->locator()->registerFilter( new QgsBookmarkLocatorFilter() );
|
||||
mLocatorWidget->locator()->registerFilter( new QgsSettingsLocatorFilter() );
|
||||
mLocatorWidget->locator()->registerFilter( new QgsGotoLocatorFilter() );
|
||||
}
|
||||
|
||||
void QgisApp::setIconSizes( int size )
|
||||
|
@ -29,7 +29,8 @@ const QList<QString> QgsLocator::CORE_FILTERS = QList<QString>() << QStringLiter
|
||||
<< QStringLiteral( "calculator" )
|
||||
<< QStringLiteral( "bookmarks" )
|
||||
<< QStringLiteral( "optionpages" )
|
||||
<< QStringLiteral( "edit_features" );
|
||||
<< QStringLiteral( "edit_features" )
|
||||
<< QStringLiteral( "goto" );
|
||||
|
||||
QgsLocator::QgsLocator( QObject *parent )
|
||||
: QObject( parent )
|
||||
|
@ -39,6 +39,7 @@ class TestQgsAppLocatorFilters : public QObject
|
||||
void testSearchActiveLayer();
|
||||
void testSearchAllLayers();
|
||||
void testSearchAllLayersPrioritizeExactMatch();
|
||||
void testGoto();
|
||||
|
||||
private:
|
||||
QgisApp *mQgisApp = nullptr;
|
||||
@ -272,5 +273,32 @@ QList<QgsLocatorResult> TestQgsAppLocatorFilters::gatherResults( QgsLocatorFilte
|
||||
return results;
|
||||
}
|
||||
|
||||
void TestQgsAppLocatorFilters::testGoto()
|
||||
{
|
||||
QgsGotoLocatorFilter filter;
|
||||
|
||||
// goto X,Y
|
||||
QList< QgsLocatorResult > 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>(), QgsPointXY( 4, 5 ) );
|
||||
QCOMPARE( results.at( 1 ).displayString, QObject::tr( "Go to 4° 5° (EPSG:4326 - WGS 84)" ) );
|
||||
QCOMPARE( results.at( 1 ).userData.toMap()[QStringLiteral( "point" )].value<QgsPointXY>(), QgsPointXY( 4, 5 ) );
|
||||
|
||||
// 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 6.4936° 44.5546° at scale 1:22569 (EPSG:4326 - WGS 84)" ) );
|
||||
QCOMPARE( results.at( 0 ).userData.toMap()[QStringLiteral( "point" )].value<QgsPointXY>(), QgsPointXY( 6.4936, 44.5546 ) );
|
||||
QCOMPARE( results.at( 0 ).userData.toMap()[QStringLiteral( "scale" )].toDouble(), 22569.0 );
|
||||
|
||||
// Google Maps
|
||||
results = gatherResults( &filter, QStringLiteral( "https://www.google.com/maps/@44.5546,6.4936,15z" ), QgsLocatorContext() );
|
||||
QCOMPARE( results.count(), 1 );
|
||||
QCOMPARE( results.at( 0 ).displayString, QObject::tr( "Go to 6.4936° 44.5546° at scale 1:22569 (EPSG:4326 - WGS 84)" ) );
|
||||
QCOMPARE( results.at( 0 ).userData.toMap()[QStringLiteral( "point" )].value<QgsPointXY>(), QgsPointXY( 6.4936, 44.5546 ) );
|
||||
QCOMPARE( results.at( 0 ).userData.toMap()[QStringLiteral( "scale" )].toDouble(), 22569.0 );
|
||||
}
|
||||
|
||||
QGSTEST_MAIN( TestQgsAppLocatorFilters )
|
||||
#include "testqgsapplocatorfilters.moc"
|
||||
|
Loading…
x
Reference in New Issue
Block a user