Skip to content
Permalink
Browse files

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

  • Loading branch information
wonder-sk committed May 2, 2020
1 parent 27b5dae commit ac8b956640a855c20aea526cf9c79aae0c5fa9cc
@@ -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
@@ -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() );
@@ -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
@@ -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"

0 comments on commit ac8b956

Please sign in to comment.
You can’t perform that action at this time.