Allow relative paths to vector tile layers in projects (fixes #36023)

This commit is contained in:
Martin Dobias 2020-05-02 23:25:15 +02:00
parent 27b5dae4bf
commit ac8b956640
4 changed files with 105 additions and 0 deletions

View File

@ -92,6 +92,11 @@ Constructs a new vector tile layer
virtual void setTransformContext( const QgsCoordinateTransformContext &transformContext );
virtual QString encodedSource( const QString &source, const QgsReadWriteContext &context ) const ${SIP_FINAL};
virtual QString decodedSource( const QString &source, const QString &provider, const QgsReadWriteContext &context ) const ${SIP_FINAL};
QString sourceType() const;
%Docstring

View File

@ -212,6 +212,67 @@ void QgsVectorTileLayer::setTransformContext( const QgsCoordinateTransformContex
Q_UNUSED( transformContext )
}
QString QgsVectorTileLayer::encodedSource( const QString &source, const QgsReadWriteContext &context ) const
{
QgsDataSourceUri dsUri;
dsUri.setEncodedUri( source );
QString sourceType = dsUri.param( QStringLiteral( "type" ) );
QString sourcePath = dsUri.param( QStringLiteral( "url" ) );
if ( sourceType == QStringLiteral( "xyz" ) )
{
QUrl sourceUrl( sourcePath );
if ( sourceUrl.isLocalFile() )
{
// relative path will become "file:./x.txt"
QString relSrcUrl = context.pathResolver().writePath( sourceUrl.toLocalFile() );
dsUri.removeParam( QStringLiteral( "url" ) ); // needed because setParam() would insert second "url" key
dsUri.setParam( QStringLiteral( "url" ), QUrl::fromLocalFile( relSrcUrl ).toString() );
return dsUri.encodedUri();
}
}
else if ( sourceType == QStringLiteral( "mbtiles" ) )
{
sourcePath = context.pathResolver().writePath( sourcePath );
dsUri.removeParam( QStringLiteral( "url" ) ); // needed because setParam() would insert second "url" key
dsUri.setParam( QStringLiteral( "url" ), sourcePath );
return dsUri.encodedUri();
}
return source;
}
QString QgsVectorTileLayer::decodedSource( const QString &source, const QString &provider, const QgsReadWriteContext &context ) const
{
Q_UNUSED( provider )
QgsDataSourceUri dsUri;
dsUri.setEncodedUri( source );
QString sourceType = dsUri.param( QStringLiteral( "type" ) );
QString sourcePath = dsUri.param( QStringLiteral( "url" ) );
if ( sourceType == QStringLiteral( "xyz" ) )
{
QUrl sourceUrl( sourcePath );
if ( sourceUrl.isLocalFile() ) // file-based URL? convert to relative path
{
QString absSrcUrl = context.pathResolver().readPath( sourceUrl.toLocalFile() );
dsUri.removeParam( QStringLiteral( "url" ) ); // needed because setParam() would insert second "url" key
dsUri.setParam( QStringLiteral( "url" ), QUrl::fromLocalFile( absSrcUrl ).toString() );
return dsUri.encodedUri();
}
}
else if ( sourceType == QStringLiteral( "mbtiles" ) )
{
sourcePath = context.pathResolver().readPath( sourcePath );
dsUri.removeParam( QStringLiteral( "url" ) ); // needed because setParam() would insert second "url" key
dsUri.setParam( QStringLiteral( "url" ), sourcePath );
return dsUri.encodedUri();
}
return source;
}
QByteArray QgsVectorTileLayer::getRawTile( QgsTileXYZ tileID )
{
QgsTileRange tileRange( tileID.column(), tileID.column(), tileID.row(), tileID.row() );

View File

@ -104,6 +104,9 @@ class CORE_EXPORT QgsVectorTileLayer : public QgsMapLayer
virtual void setTransformContext( const QgsCoordinateTransformContext &transformContext ) override;
QString encodedSource( const QString &source, const QgsReadWriteContext &context ) const FINAL;
QString decodedSource( const QString &source, const QString &provider, const QgsReadWriteContext &context ) const FINAL;
// new methods
//! Returns type of the data source

View File

@ -55,6 +55,7 @@ class TestQgsVectorTileLayer : public QObject
void test_basic();
void test_render();
void test_labeling();
void test_relativePaths();
};
@ -181,6 +182,41 @@ void TestQgsVectorTileLayer::test_labeling()
QVERIFY( res );
}
void TestQgsVectorTileLayer::test_relativePaths()
{
QgsReadWriteContext contextRel;
contextRel.setPathResolver( QgsPathResolver( "/home/qgis/project.qgs" ) );
QgsReadWriteContext contextAbs;
QString srcXyzLocal = "type=xyz&url=file:///home/qgis/%7Bz%7D/%7Bx%7D/%7By%7D.pbf";
QString srcXyzRemote = "type=xyz&url=http://www.example.com/%7Bz%7D/%7Bx%7D/%7By%7D.pbf";
QString srcMbtiles = "type=mbtiles&url=/home/qgis/test/map.mbtiles";
QgsVectorTileLayer layer;
// encode source: converting absolute paths to relative
QString srcXyzLocalRel = layer.encodedSource( srcXyzLocal, contextRel );
QCOMPARE( srcXyzLocalRel, QStringLiteral( "type=xyz&url=file:./%7Bz%7D/%7Bx%7D/%7By%7D.pbf" ) );
QString srcMbtilesRel = layer.encodedSource( srcMbtiles, contextRel );
QCOMPARE( srcMbtilesRel, QStringLiteral( "type=mbtiles&url=./test/map.mbtiles" ) );
QCOMPARE( layer.encodedSource( srcXyzRemote, contextRel ), srcXyzRemote );
// encode source: keeping absolute paths
QCOMPARE( layer.encodedSource( srcXyzLocal, contextAbs ), srcXyzLocal );
QCOMPARE( layer.encodedSource( srcXyzRemote, contextAbs ), srcXyzRemote );
QCOMPARE( layer.encodedSource( srcMbtiles, contextAbs ), srcMbtiles );
// decode source: converting relative paths to absolute
QCOMPARE( layer.decodedSource( srcXyzLocalRel, QString(), contextRel ), srcXyzLocal );
QCOMPARE( layer.decodedSource( srcMbtilesRel, QString(), contextRel ), srcMbtiles );
QCOMPARE( layer.decodedSource( srcXyzRemote, QString(), contextRel ), srcXyzRemote );
// decode source: keeping absolute paths
QCOMPARE( layer.decodedSource( srcXyzLocal, QString(), contextAbs ), srcXyzLocal );
QCOMPARE( layer.decodedSource( srcXyzRemote, QString(), contextAbs ), srcXyzRemote );
QCOMPARE( layer.decodedSource( srcMbtiles, QString(), contextAbs ), srcMbtiles );
}
QGSTEST_MAIN( TestQgsVectorTileLayer )
#include "testqgsvectortilelayer.moc"