Skip to content

Commit ac8b956

Browse files
committedMay 4, 2020
Allow relative paths to vector tile layers in projects (fixes #36023)
1 parent 27b5dae commit ac8b956

File tree

4 files changed

+105
-0
lines changed

4 files changed

+105
-0
lines changed
 

‎python/core/auto_generated/vectortile/qgsvectortilelayer.sip.in

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,11 @@ Constructs a new vector tile layer
9292

9393
virtual void setTransformContext( const QgsCoordinateTransformContext &transformContext );
9494

95+
virtual QString encodedSource( const QString &source, const QgsReadWriteContext &context ) const ${SIP_FINAL};
96+
97+
virtual QString decodedSource( const QString &source, const QString &provider, const QgsReadWriteContext &context ) const ${SIP_FINAL};
98+
99+
95100

96101
QString sourceType() const;
97102
%Docstring

‎src/core/vectortile/qgsvectortilelayer.cpp

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,67 @@ void QgsVectorTileLayer::setTransformContext( const QgsCoordinateTransformContex
212212
Q_UNUSED( transformContext )
213213
}
214214

215+
QString QgsVectorTileLayer::encodedSource( const QString &source, const QgsReadWriteContext &context ) const
216+
{
217+
QgsDataSourceUri dsUri;
218+
dsUri.setEncodedUri( source );
219+
220+
QString sourceType = dsUri.param( QStringLiteral( "type" ) );
221+
QString sourcePath = dsUri.param( QStringLiteral( "url" ) );
222+
if ( sourceType == QStringLiteral( "xyz" ) )
223+
{
224+
QUrl sourceUrl( sourcePath );
225+
if ( sourceUrl.isLocalFile() )
226+
{
227+
// relative path will become "file:./x.txt"
228+
QString relSrcUrl = context.pathResolver().writePath( sourceUrl.toLocalFile() );
229+
dsUri.removeParam( QStringLiteral( "url" ) ); // needed because setParam() would insert second "url" key
230+
dsUri.setParam( QStringLiteral( "url" ), QUrl::fromLocalFile( relSrcUrl ).toString() );
231+
return dsUri.encodedUri();
232+
}
233+
}
234+
else if ( sourceType == QStringLiteral( "mbtiles" ) )
235+
{
236+
sourcePath = context.pathResolver().writePath( sourcePath );
237+
dsUri.removeParam( QStringLiteral( "url" ) ); // needed because setParam() would insert second "url" key
238+
dsUri.setParam( QStringLiteral( "url" ), sourcePath );
239+
return dsUri.encodedUri();
240+
}
241+
242+
return source;
243+
}
244+
245+
QString QgsVectorTileLayer::decodedSource( const QString &source, const QString &provider, const QgsReadWriteContext &context ) const
246+
{
247+
Q_UNUSED( provider )
248+
249+
QgsDataSourceUri dsUri;
250+
dsUri.setEncodedUri( source );
251+
252+
QString sourceType = dsUri.param( QStringLiteral( "type" ) );
253+
QString sourcePath = dsUri.param( QStringLiteral( "url" ) );
254+
if ( sourceType == QStringLiteral( "xyz" ) )
255+
{
256+
QUrl sourceUrl( sourcePath );
257+
if ( sourceUrl.isLocalFile() ) // file-based URL? convert to relative path
258+
{
259+
QString absSrcUrl = context.pathResolver().readPath( sourceUrl.toLocalFile() );
260+
dsUri.removeParam( QStringLiteral( "url" ) ); // needed because setParam() would insert second "url" key
261+
dsUri.setParam( QStringLiteral( "url" ), QUrl::fromLocalFile( absSrcUrl ).toString() );
262+
return dsUri.encodedUri();
263+
}
264+
}
265+
else if ( sourceType == QStringLiteral( "mbtiles" ) )
266+
{
267+
sourcePath = context.pathResolver().readPath( sourcePath );
268+
dsUri.removeParam( QStringLiteral( "url" ) ); // needed because setParam() would insert second "url" key
269+
dsUri.setParam( QStringLiteral( "url" ), sourcePath );
270+
return dsUri.encodedUri();
271+
}
272+
273+
return source;
274+
}
275+
215276
QByteArray QgsVectorTileLayer::getRawTile( QgsTileXYZ tileID )
216277
{
217278
QgsTileRange tileRange( tileID.column(), tileID.column(), tileID.row(), tileID.row() );

‎src/core/vectortile/qgsvectortilelayer.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,9 @@ class CORE_EXPORT QgsVectorTileLayer : public QgsMapLayer
104104

105105
virtual void setTransformContext( const QgsCoordinateTransformContext &transformContext ) override;
106106

107+
QString encodedSource( const QString &source, const QgsReadWriteContext &context ) const FINAL;
108+
QString decodedSource( const QString &source, const QString &provider, const QgsReadWriteContext &context ) const FINAL;
109+
107110
// new methods
108111

109112
//! Returns type of the data source

‎tests/src/core/testqgsvectortilelayer.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ class TestQgsVectorTileLayer : public QObject
5555
void test_basic();
5656
void test_render();
5757
void test_labeling();
58+
void test_relativePaths();
5859
};
5960

6061

@@ -181,6 +182,41 @@ void TestQgsVectorTileLayer::test_labeling()
181182
QVERIFY( res );
182183
}
183184

185+
void TestQgsVectorTileLayer::test_relativePaths()
186+
{
187+
QgsReadWriteContext contextRel;
188+
contextRel.setPathResolver( QgsPathResolver( "/home/qgis/project.qgs" ) );
189+
QgsReadWriteContext contextAbs;
190+
191+
QString srcXyzLocal = "type=xyz&url=file:///home/qgis/%7Bz%7D/%7Bx%7D/%7By%7D.pbf";
192+
QString srcXyzRemote = "type=xyz&url=http://www.example.com/%7Bz%7D/%7Bx%7D/%7By%7D.pbf";
193+
QString srcMbtiles = "type=mbtiles&url=/home/qgis/test/map.mbtiles";
194+
195+
QgsVectorTileLayer layer;
196+
197+
// encode source: converting absolute paths to relative
198+
QString srcXyzLocalRel = layer.encodedSource( srcXyzLocal, contextRel );
199+
QCOMPARE( srcXyzLocalRel, QStringLiteral( "type=xyz&url=file:./%7Bz%7D/%7Bx%7D/%7By%7D.pbf" ) );
200+
QString srcMbtilesRel = layer.encodedSource( srcMbtiles, contextRel );
201+
QCOMPARE( srcMbtilesRel, QStringLiteral( "type=mbtiles&url=./test/map.mbtiles" ) );
202+
QCOMPARE( layer.encodedSource( srcXyzRemote, contextRel ), srcXyzRemote );
203+
204+
// encode source: keeping absolute paths
205+
QCOMPARE( layer.encodedSource( srcXyzLocal, contextAbs ), srcXyzLocal );
206+
QCOMPARE( layer.encodedSource( srcXyzRemote, contextAbs ), srcXyzRemote );
207+
QCOMPARE( layer.encodedSource( srcMbtiles, contextAbs ), srcMbtiles );
208+
209+
// decode source: converting relative paths to absolute
210+
QCOMPARE( layer.decodedSource( srcXyzLocalRel, QString(), contextRel ), srcXyzLocal );
211+
QCOMPARE( layer.decodedSource( srcMbtilesRel, QString(), contextRel ), srcMbtiles );
212+
QCOMPARE( layer.decodedSource( srcXyzRemote, QString(), contextRel ), srcXyzRemote );
213+
214+
// decode source: keeping absolute paths
215+
QCOMPARE( layer.decodedSource( srcXyzLocal, QString(), contextAbs ), srcXyzLocal );
216+
QCOMPARE( layer.decodedSource( srcXyzRemote, QString(), contextAbs ), srcXyzRemote );
217+
QCOMPARE( layer.decodedSource( srcMbtiles, QString(), contextAbs ), srcMbtiles );
218+
}
219+
184220

185221
QGSTEST_MAIN( TestQgsVectorTileLayer )
186222
#include "testqgsvectortilelayer.moc"

0 commit comments

Comments
 (0)