QGIS API Documentation  3.22.4-Białowieża (ce8e65e95e)
qgsvectortilelayer.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsvectortilelayer.cpp
3  --------------------------------------
4  Date : March 2020
5  Copyright : (C) 2020 by Martin Dobias
6  Email : wonder dot sk at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include "qgsvectortilelayer.h"
17 
18 #include "qgslogger.h"
20 #include "qgsmbtiles.h"
23 #include "qgsvectortilelabeling.h"
24 #include "qgsvectortileloader.h"
25 #include "qgsvectortileutils.h"
27 
28 #include "qgsdatasourceuri.h"
32 #include "qgsjsonutils.h"
33 #include "qgspainting.h"
34 #include "qgsmaplayerfactory.h"
35 
36 #include <QUrl>
37 #include <QUrlQuery>
38 
39 QgsVectorTileLayer::QgsVectorTileLayer( const QString &uri, const QString &baseName, const LayerOptions &options )
41  , mTransformContext( options.transformContext )
42 {
43  mDataSource = uri;
44 
45  setValid( loadDataSource() );
46 
47  // set a default renderer
51 }
52 
53 void QgsVectorTileLayer::setDataSourcePrivate( const QString &dataSource, const QString &baseName, const QString &, const QgsDataProvider::ProviderOptions &, QgsDataProvider::ReadFlags )
54 {
55  mDataSource = dataSource;
56  mLayerName = baseName;
57  mDataProvider.reset();
58 
59  setValid( loadDataSource() );
60 }
61 
62 bool QgsVectorTileLayer::loadDataSource()
63 {
64  QgsDataSourceUri dsUri;
65  dsUri.setEncodedUri( mDataSource );
66 
67  mSourceType = dsUri.param( QStringLiteral( "type" ) );
68  mSourcePath = dsUri.param( QStringLiteral( "url" ) );
69  if ( mSourceType == QLatin1String( "xyz" ) && dsUri.param( QStringLiteral( "serviceType" ) ) == QLatin1String( "arcgis" ) )
70  {
71  if ( !setupArcgisVectorTileServiceConnection( mSourcePath, dsUri ) )
72  return false;
73  }
74  else if ( mSourceType == QLatin1String( "xyz" ) )
75  {
76  if ( !QgsVectorTileUtils::checkXYZUrlTemplate( mSourcePath ) )
77  {
78  QgsDebugMsg( QStringLiteral( "Invalid format of URL for XYZ source: " ) + mSourcePath );
79  return false;
80  }
81 
82  // online tiles
83  mSourceMinZoom = 0;
84  mSourceMaxZoom = 14;
85 
86  if ( dsUri.hasParam( QStringLiteral( "zmin" ) ) )
87  mSourceMinZoom = dsUri.param( QStringLiteral( "zmin" ) ).toInt();
88  if ( dsUri.hasParam( QStringLiteral( "zmax" ) ) )
89  mSourceMaxZoom = dsUri.param( QStringLiteral( "zmax" ) ).toInt();
90 
91  setExtent( QgsRectangle( -20037508.3427892, -20037508.3427892, 20037508.3427892, 20037508.3427892 ) );
92  }
93  else if ( mSourceType == QLatin1String( "mbtiles" ) )
94  {
95  QgsMbTiles reader( mSourcePath );
96  if ( !reader.open() )
97  {
98  QgsDebugMsg( QStringLiteral( "failed to open MBTiles file: " ) + mSourcePath );
99  return false;
100  }
101 
102  const QString format = reader.metadataValue( QStringLiteral( "format" ) );
103  if ( format != QLatin1String( "pbf" ) )
104  {
105  QgsDebugMsg( QStringLiteral( "Cannot open MBTiles for vector tiles. Format = " ) + format );
106  return false;
107  }
108 
109  QgsDebugMsgLevel( QStringLiteral( "name: " ) + reader.metadataValue( QStringLiteral( "name" ) ), 2 );
110  bool minZoomOk, maxZoomOk;
111  const int minZoom = reader.metadataValue( QStringLiteral( "minzoom" ) ).toInt( &minZoomOk );
112  const int maxZoom = reader.metadataValue( QStringLiteral( "maxzoom" ) ).toInt( &maxZoomOk );
113  if ( minZoomOk )
114  mSourceMinZoom = minZoom;
115  if ( maxZoomOk )
116  mSourceMaxZoom = maxZoom;
117  QgsDebugMsgLevel( QStringLiteral( "zoom range: %1 - %2" ).arg( mSourceMinZoom ).arg( mSourceMaxZoom ), 2 );
118 
119  QgsRectangle r = reader.extent();
120  QgsCoordinateTransform ct( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:4326" ) ),
121  QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:3857" ) ), transformContext() );
122  ct.setBallparkTransformsAreAppropriate( true );
123  r = ct.transformBoundingBox( r );
124  setExtent( r );
125  }
126  else
127  {
128  QgsDebugMsg( QStringLiteral( "Unknown source type: " ) + mSourceType );
129  return false;
130  }
131 
132  setCrs( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:3857" ) ) );
133 
134  const QgsDataProvider::ProviderOptions providerOptions { mTransformContext };
135  const QgsDataProvider::ReadFlags flags;
136  mDataProvider.reset( new QgsVectorTileDataProvider( providerOptions, flags ) );
137  mProviderKey = mDataProvider->name();
138 
139  return true;
140 }
141 
142 bool QgsVectorTileLayer::setupArcgisVectorTileServiceConnection( const QString &uri, const QgsDataSourceUri &dataSourceUri )
143 {
144  QUrl url( uri );
145  // some services don't default to json format, while others do... so let's explicitly request it!
146  // (refs https://github.com/qgis/QGIS/issues/4231)
147  QUrlQuery query;
148  query.addQueryItem( QStringLiteral( "f" ), QStringLiteral( "pjson" ) );
149  url.setQuery( query );
150 
151  QNetworkRequest request = QNetworkRequest( url );
152 
153  QgsSetRequestInitiatorClass( request, QStringLiteral( "QgsVectorTileLayer" ) )
154 
155  QgsBlockingNetworkRequest networkRequest;
156  switch ( networkRequest.get( request ) )
157  {
159  break;
160 
164  return false;
165  }
166 
167  const QgsNetworkReplyContent content = networkRequest.reply();
168  const QByteArray raw = content.content();
169 
170  // Parse data
171  QJsonParseError err;
172  const QJsonDocument doc = QJsonDocument::fromJson( raw, &err );
173  if ( doc.isNull() )
174  {
175  return false;
176  }
177  mArcgisLayerConfiguration = doc.object().toVariantMap();
178  if ( mArcgisLayerConfiguration.contains( QStringLiteral( "error" ) ) )
179  {
180  return false;
181  }
182 
183  mArcgisLayerConfiguration.insert( QStringLiteral( "serviceUri" ), uri );
184  mSourcePath = uri + '/' + mArcgisLayerConfiguration.value( QStringLiteral( "tiles" ) ).toList().value( 0 ).toString();
185  if ( !QgsVectorTileUtils::checkXYZUrlTemplate( mSourcePath ) )
186  {
187  QgsDebugMsg( QStringLiteral( "Invalid format of URL for XYZ source: " ) + mSourcePath );
188  return false;
189  }
190 
191  // if hardcoded zoom limits aren't specified, take them from the server
192  if ( !dataSourceUri.hasParam( QStringLiteral( "zmin" ) ) )
193  mSourceMinZoom = 0;
194  else
195  mSourceMinZoom = dataSourceUri.param( QStringLiteral( "zmin" ) ).toInt();
196 
197  if ( !dataSourceUri.hasParam( QStringLiteral( "zmax" ) ) )
198  mSourceMaxZoom = mArcgisLayerConfiguration.value( QStringLiteral( "maxzoom" ) ).toInt();
199  else
200  mSourceMaxZoom = dataSourceUri.param( QStringLiteral( "zmax" ) ).toInt();
201 
202  setExtent( QgsRectangle( -20037508.3427892, -20037508.3427892, 20037508.3427892, 20037508.3427892 ) );
203 
204  return true;
205 }
206 
208 
209 
211 {
212  const QgsVectorTileLayer::LayerOptions options( mTransformContext );
213  QgsVectorTileLayer *layer = new QgsVectorTileLayer( source(), name(), options );
214  layer->setRenderer( renderer() ? renderer()->clone() : nullptr );
215  return layer;
216 }
217 
219 {
220  return mDataProvider.get();
221 }
222 
224 {
225  return mDataProvider.get();
226 }
227 
229 {
230  return new QgsVectorTileLayerRenderer( this, rendererContext );
231 }
232 
233 bool QgsVectorTileLayer::readXml( const QDomNode &layerNode, QgsReadWriteContext &context )
234 {
235  setValid( loadDataSource() );
236 
237  QString errorMsg;
238  if ( !readSymbology( layerNode, errorMsg, context ) )
239  return false;
240 
241  readStyleManager( layerNode );
242  return true;
243 }
244 
245 bool QgsVectorTileLayer::writeXml( QDomNode &layerNode, QDomDocument &doc, const QgsReadWriteContext &context ) const
246 {
247  QDomElement mapLayerNode = layerNode.toElement();
248  mapLayerNode.setAttribute( QStringLiteral( "type" ), QgsMapLayerFactory::typeToString( QgsMapLayerType::VectorTileLayer ) );
249 
250  // add provider node
251  if ( mDataProvider )
252  {
253  QDomElement provider = doc.createElement( QStringLiteral( "provider" ) );
254  const QDomText providerText = doc.createTextNode( providerType() );
255  provider.appendChild( providerText );
256  mapLayerNode.appendChild( provider );
257  }
258 
259  writeStyleManager( layerNode, doc );
260 
261  QString errorMsg;
262  return writeSymbology( layerNode, doc, errorMsg, context );
263 }
264 
265 bool QgsVectorTileLayer::readSymbology( const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories )
266 {
267  const QDomElement elem = node.toElement();
268 
269  readCommonStyle( elem, context, categories );
270 
271  const QDomElement elemRenderer = elem.firstChildElement( QStringLiteral( "renderer" ) );
272  if ( elemRenderer.isNull() )
273  {
274  errorMessage = tr( "Missing <renderer> tag" );
275  return false;
276  }
277  const QString rendererType = elemRenderer.attribute( QStringLiteral( "type" ) );
278 
279  if ( categories.testFlag( Symbology ) )
280  {
281  QgsVectorTileRenderer *r = nullptr;
282  if ( rendererType == QLatin1String( "basic" ) )
284  else
285  {
286  errorMessage = tr( "Unknown renderer type: " ) + rendererType;
287  return false;
288  }
289 
290  r->readXml( elemRenderer, context );
291  setRenderer( r );
292  }
293 
294  if ( categories.testFlag( Labeling ) )
295  {
296  setLabeling( nullptr );
297  const QDomElement elemLabeling = elem.firstChildElement( QStringLiteral( "labeling" ) );
298  if ( !elemLabeling.isNull() )
299  {
300  const QString labelingType = elemLabeling.attribute( QStringLiteral( "type" ) );
301  QgsVectorTileLabeling *labeling = nullptr;
302  if ( labelingType == QLatin1String( "basic" ) )
304  else
305  {
306  errorMessage = tr( "Unknown labeling type: " ) + rendererType;
307  }
308 
309  if ( labeling )
310  {
311  labeling->readXml( elemLabeling, context );
313  }
314  }
315  }
316 
317  if ( categories.testFlag( Symbology ) )
318  {
319  // get and set the blend mode if it exists
320  const QDomNode blendModeNode = node.namedItem( QStringLiteral( "blendMode" ) );
321  if ( !blendModeNode.isNull() )
322  {
323  const QDomElement e = blendModeNode.toElement();
324  setBlendMode( QgsPainting::getCompositionMode( static_cast< QgsPainting::BlendMode >( e.text().toInt() ) ) );
325  }
326  }
327 
328  // get and set the layer transparency
329  if ( categories.testFlag( Rendering ) )
330  {
331  const QDomNode layerOpacityNode = node.namedItem( QStringLiteral( "layerOpacity" ) );
332  if ( !layerOpacityNode.isNull() )
333  {
334  const QDomElement e = layerOpacityNode.toElement();
335  setOpacity( e.text().toDouble() );
336  }
337  }
338 
339  return true;
340 }
341 
342 bool QgsVectorTileLayer::writeSymbology( QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
343 {
344  Q_UNUSED( errorMessage )
345  QDomElement elem = node.toElement();
346 
347  writeCommonStyle( elem, doc, context, categories );
348 
349  if ( mRenderer )
350  {
351  QDomElement elemRenderer = doc.createElement( QStringLiteral( "renderer" ) );
352  elemRenderer.setAttribute( QStringLiteral( "type" ), mRenderer->type() );
353  if ( categories.testFlag( Symbology ) )
354  {
355  mRenderer->writeXml( elemRenderer, context );
356  }
357  elem.appendChild( elemRenderer );
358  }
359 
360  if ( mLabeling && categories.testFlag( Labeling ) )
361  {
362  QDomElement elemLabeling = doc.createElement( QStringLiteral( "labeling" ) );
363  elemLabeling.setAttribute( QStringLiteral( "type" ), mLabeling->type() );
364  mLabeling->writeXml( elemLabeling, context );
365  elem.appendChild( elemLabeling );
366  }
367 
368  if ( categories.testFlag( Symbology ) )
369  {
370  // add the blend mode field
371  QDomElement blendModeElem = doc.createElement( QStringLiteral( "blendMode" ) );
372  const QDomText blendModeText = doc.createTextNode( QString::number( QgsPainting::getBlendModeEnum( blendMode() ) ) );
373  blendModeElem.appendChild( blendModeText );
374  node.appendChild( blendModeElem );
375  }
376 
377  // add the layer opacity
378  if ( categories.testFlag( Rendering ) )
379  {
380  QDomElement layerOpacityElem = doc.createElement( QStringLiteral( "layerOpacity" ) );
381  const QDomText layerOpacityText = doc.createTextNode( QString::number( opacity() ) );
382  layerOpacityElem.appendChild( layerOpacityText );
383  node.appendChild( layerOpacityElem );
384  }
385 
386  return true;
387 }
388 
390 {
391  if ( mDataProvider )
392  mDataProvider->setTransformContext( transformContext );
393 
394  mTransformContext = transformContext;
396 }
397 
398 QString QgsVectorTileLayer::loadDefaultStyle( bool &resultFlag )
399 {
400  QString error;
401  QStringList warnings;
402  resultFlag = loadDefaultStyle( error, warnings );
403  return error;
404 }
405 
406 bool QgsVectorTileLayer::loadDefaultStyle( QString &error, QStringList &warnings )
407 {
408  QgsDataSourceUri dsUri;
409  dsUri.setEncodedUri( mDataSource );
410 
411  QString styleUrl;
412  if ( !dsUri.param( QStringLiteral( "styleUrl" ) ).isEmpty() )
413  {
414  styleUrl = dsUri.param( QStringLiteral( "styleUrl" ) );
415  }
416  else if ( mSourceType == QLatin1String( "xyz" ) && dsUri.param( QStringLiteral( "serviceType" ) ) == QLatin1String( "arcgis" ) )
417  {
418  // for ArcMap VectorTileServices we default to the defaultStyles URL from the layer configuration
419  styleUrl = mArcgisLayerConfiguration.value( QStringLiteral( "serviceUri" ) ).toString()
420  + '/' + mArcgisLayerConfiguration.value( QStringLiteral( "defaultStyles" ) ).toString();
421  }
422 
423  if ( !styleUrl.isEmpty() )
424  {
425  QNetworkRequest request = QNetworkRequest( QUrl( styleUrl ) );
426 
427  QgsSetRequestInitiatorClass( request, QStringLiteral( "QgsVectorTileLayer" ) );
428 
429  QgsBlockingNetworkRequest networkRequest;
430  switch ( networkRequest.get( request ) )
431  {
433  break;
434 
438  error = QObject::tr( "Error retrieving default style" );
439  return false;
440  }
441 
442  const QgsNetworkReplyContent content = networkRequest.reply();
443  const QVariantMap styleDefinition = QgsJsonUtils::parseJson( content.content() ).toMap();
444 
446  // convert automatically from pixel sizes to millimeters, because pixel sizes
447  // are a VERY edge case in QGIS and don't play nice with hidpi map renders or print layouts
449  //assume source uses 96 dpi
450  context.setPixelSizeConversionFactor( 25.4 / 96.0 );
451 
452  if ( styleDefinition.contains( QStringLiteral( "sprite" ) ) )
453  {
454  // retrieve sprite definition
455  QString spriteUriBase;
456  if ( styleDefinition.value( QStringLiteral( "sprite" ) ).toString().startsWith( QLatin1String( "http" ) ) )
457  {
458  spriteUriBase = styleDefinition.value( QStringLiteral( "sprite" ) ).toString();
459  }
460  else
461  {
462  spriteUriBase = styleUrl + '/' + styleDefinition.value( QStringLiteral( "sprite" ) ).toString();
463  }
464 
465  for ( int resolution = 2; resolution > 0; resolution-- )
466  {
467  QUrl spriteUrl = QUrl( spriteUriBase );
468  spriteUrl.setPath( spriteUrl.path() + QStringLiteral( "%1.json" ).arg( resolution > 1 ? QStringLiteral( "@%1x" ).arg( resolution ) : QString() ) );
469  QNetworkRequest request = QNetworkRequest( spriteUrl );
470  QgsSetRequestInitiatorClass( request, QStringLiteral( "QgsVectorTileLayer" ) )
471  QgsBlockingNetworkRequest networkRequest;
472  switch ( networkRequest.get( request ) )
473  {
475  {
476  const QgsNetworkReplyContent content = networkRequest.reply();
477  const QVariantMap spriteDefinition = QgsJsonUtils::parseJson( content.content() ).toMap();
478 
479  // retrieve sprite images
480  QUrl spriteUrl = QUrl( spriteUriBase );
481  spriteUrl.setPath( spriteUrl.path() + QStringLiteral( "%1.png" ).arg( resolution > 1 ? QStringLiteral( "@%1x" ).arg( resolution ) : QString() ) );
482  QNetworkRequest request = QNetworkRequest( spriteUrl );
483  QgsSetRequestInitiatorClass( request, QStringLiteral( "QgsVectorTileLayer" ) )
484  QgsBlockingNetworkRequest networkRequest;
485  switch ( networkRequest.get( request ) )
486  {
488  {
489  const QgsNetworkReplyContent imageContent = networkRequest.reply();
490  const QImage spriteImage( QImage::fromData( imageContent.content() ) );
491  context.setSprites( spriteImage, spriteDefinition );
492  break;
493  }
494 
498  break;
499  }
500 
501  break;
502  }
503 
507  break;
508  }
509 
510  if ( !context.spriteDefinitions().isEmpty() )
511  break;
512  }
513  }
514 
515  QgsMapBoxGlStyleConverter converter;
516  if ( converter.convert( styleDefinition, &context ) != QgsMapBoxGlStyleConverter::Success )
517  {
518  warnings = converter.warnings();
519  error = converter.errorMessage();
520  return false;
521  }
522 
523  setRenderer( converter.renderer() );
524  setLabeling( converter.labeling() );
525  warnings = converter.warnings();
526  return true;
527  }
528  else
529  {
530  bool resultFlag = false;
531  error = QgsMapLayer::loadDefaultStyle( resultFlag );
532  return resultFlag;
533  }
534 }
535 
536 QString QgsVectorTileLayer::loadDefaultMetadata( bool &resultFlag )
537 {
538  QgsDataSourceUri dsUri;
539  dsUri.setEncodedUri( mDataSource );
540  if ( mSourceType == QLatin1String( "xyz" ) && dsUri.param( QStringLiteral( "serviceType" ) ) == QLatin1String( "arcgis" ) )
541  {
542  // populate default metadata
544  metadata.setIdentifier( mArcgisLayerConfiguration.value( QStringLiteral( "serviceUri" ) ).toString() );
545  const QString parentIdentifier = mArcgisLayerConfiguration.value( QStringLiteral( "serviceItemId" ) ).toString();
546  if ( !parentIdentifier.isEmpty() )
547  {
548  metadata.setParentIdentifier( parentIdentifier );
549  }
550  metadata.setType( QStringLiteral( "dataset" ) );
551  metadata.setTitle( mArcgisLayerConfiguration.value( QStringLiteral( "name" ) ).toString() );
552  const QString copyright = mArcgisLayerConfiguration.value( QStringLiteral( "copyrightText" ) ).toString();
553  if ( !copyright.isEmpty() )
554  metadata.setRights( QStringList() << copyright );
555  metadata.addLink( QgsAbstractMetadataBase::Link( tr( "Source" ), QStringLiteral( "WWW:LINK" ), mArcgisLayerConfiguration.value( QStringLiteral( "serviceUri" ) ).toString() ) );
556 
558 
559  resultFlag = true;
560  return QString();
561  }
562  else
563  {
564  QgsMapLayer::loadDefaultMetadata( resultFlag );
565  resultFlag = true;
566  return QString();
567  }
568 }
569 
570 QString QgsVectorTileLayer::encodedSource( const QString &source, const QgsReadWriteContext &context ) const
571 {
572  QgsDataSourceUri dsUri;
573  dsUri.setEncodedUri( source );
574 
575  const QString sourceType = dsUri.param( QStringLiteral( "type" ) );
576  QString sourcePath = dsUri.param( QStringLiteral( "url" ) );
577  if ( sourceType == QLatin1String( "xyz" ) )
578  {
579  const QUrl sourceUrl( sourcePath );
580  if ( sourceUrl.isLocalFile() )
581  {
582  // relative path will become "file:./x.txt"
583  const QString relSrcUrl = context.pathResolver().writePath( sourceUrl.toLocalFile() );
584  dsUri.removeParam( QStringLiteral( "url" ) ); // needed because setParam() would insert second "url" key
585  dsUri.setParam( QStringLiteral( "url" ), QUrl::fromLocalFile( relSrcUrl ).toString() );
586  return dsUri.encodedUri();
587  }
588  }
589  else if ( sourceType == QLatin1String( "mbtiles" ) )
590  {
592  dsUri.removeParam( QStringLiteral( "url" ) ); // needed because setParam() would insert second "url" key
593  dsUri.setParam( QStringLiteral( "url" ), sourcePath );
594  return dsUri.encodedUri();
595  }
596 
597  return source;
598 }
599 
600 QString QgsVectorTileLayer::decodedSource( const QString &source, const QString &provider, const QgsReadWriteContext &context ) const
601 {
602  Q_UNUSED( provider )
603 
604  QgsDataSourceUri dsUri;
605  dsUri.setEncodedUri( source );
606 
607  const QString sourceType = dsUri.param( QStringLiteral( "type" ) );
608  QString sourcePath = dsUri.param( QStringLiteral( "url" ) );
609  if ( sourceType == QLatin1String( "xyz" ) )
610  {
611  const QUrl sourceUrl( sourcePath );
612  if ( sourceUrl.isLocalFile() ) // file-based URL? convert to relative path
613  {
614  const QString absSrcUrl = context.pathResolver().readPath( sourceUrl.toLocalFile() );
615  dsUri.removeParam( QStringLiteral( "url" ) ); // needed because setParam() would insert second "url" key
616  dsUri.setParam( QStringLiteral( "url" ), QUrl::fromLocalFile( absSrcUrl ).toString() );
617  return dsUri.encodedUri();
618  }
619  }
620  else if ( sourceType == QLatin1String( "mbtiles" ) )
621  {
623  dsUri.removeParam( QStringLiteral( "url" ) ); // needed because setParam() would insert second "url" key
624  dsUri.setParam( QStringLiteral( "url" ), sourcePath );
625  return dsUri.encodedUri();
626  }
627 
628  return source;
629 }
630 
632 {
633  const QgsLayerMetadataFormatter htmlFormatter( metadata() );
634 
635  QString info = QStringLiteral( "<html><head></head>\n<body>\n" );
636 
637  info += generalHtmlMetadata();
638 
639  info += QStringLiteral( "<h1>" ) + tr( "Information from provider" ) + QStringLiteral( "</h1>\n<hr>\n" ) %
640  QStringLiteral( "<table class=\"list-view\">\n" );
641 
642  info += QStringLiteral( "<tr><td class=\"highlight\">" ) % tr( "Source type" ) % QStringLiteral( "</td><td>" ) % sourceType() % QStringLiteral( "</td></tr>\n" );
643 
644  info += QStringLiteral( "<tr><td class=\"highlight\">" ) % tr( "Zoom levels" ) % QStringLiteral( "</td><td>" ) % QStringLiteral( "%1 - %2" ).arg( sourceMinZoom() ).arg( sourceMaxZoom() ) % QStringLiteral( "</td></tr>\n" );
645 
646  info += QLatin1String( "</table>\n<br>" );
647 
648  // CRS
649  info += crsHtmlMetadata();
650 
651  // Identification section
652  info += QStringLiteral( "<h1>" ) % tr( "Identification" ) % QStringLiteral( "</h1>\n<hr>\n" ) %
653  htmlFormatter.identificationSectionHtml() %
654  QStringLiteral( "<br>\n" ) %
655 
656  // extent section
657  QStringLiteral( "<h1>" ) % tr( "Extent" ) % QStringLiteral( "</h1>\n<hr>\n" ) %
658  htmlFormatter.extentSectionHtml( ) %
659  QStringLiteral( "<br>\n" ) %
660 
661  // Start the Access section
662  QStringLiteral( "<h1>" ) % tr( "Access" ) % QStringLiteral( "</h1>\n<hr>\n" ) %
663  htmlFormatter.accessSectionHtml( ) %
664  QStringLiteral( "<br>\n" ) %
665 
666 
667  // Start the contacts section
668  QStringLiteral( "<h1>" ) % tr( "Contacts" ) % QStringLiteral( "</h1>\n<hr>\n" ) %
669  htmlFormatter.contactsSectionHtml( ) %
670  QStringLiteral( "<br><br>\n" ) %
671 
672  // Start the links section
673  QStringLiteral( "<h1>" ) % tr( "References" ) % QStringLiteral( "</h1>\n<hr>\n" ) %
674  htmlFormatter.linksSectionHtml( ) %
675  QStringLiteral( "<br>\n" ) %
676 
677  // Start the history section
678  QStringLiteral( "<h1>" ) % tr( "History" ) % QStringLiteral( "</h1>\n<hr>\n" ) %
679  htmlFormatter.historySectionHtml( ) %
680  QStringLiteral( "<br>\n" ) %
681 
682  QStringLiteral( "\n</body>\n</html>\n" );
683 
684  return info;
685 }
686 
688 {
689  const QgsTileMatrix tileMatrix = QgsTileMatrix::fromWebMercator( tileID.zoomLevel() );
690  const QgsTileRange tileRange( tileID.column(), tileID.column(), tileID.row(), tileID.row() );
691 
692  QgsDataSourceUri dsUri;
693  dsUri.setEncodedUri( mDataSource );
694  const QString authcfg = dsUri.authConfigId();
695  const QString referer = dsUri.param( QStringLiteral( "referer" ) );
696 
697  QList<QgsVectorTileRawData> rawTiles = QgsVectorTileLoader::blockingFetchTileRawData( mSourceType, mSourcePath, tileMatrix, QPointF(), tileRange, authcfg, referer );
698  if ( rawTiles.isEmpty() )
699  return QByteArray();
700  return rawTiles.first().data;
701 }
702 
704 {
705  mRenderer.reset( r );
706  triggerRepaint();
707 }
708 
710 {
711  return mRenderer.get();
712 }
713 
715 {
716  mLabeling.reset( labeling );
717  triggerRepaint();
718 }
719 
721 {
722  return mLabeling.get();
723 }
724 
725 
726 
727 //
728 // QgsVectorTileDataProvider
729 //
731 QgsVectorTileDataProvider::QgsVectorTileDataProvider(
732  const ProviderOptions &options,
733  QgsDataProvider::ReadFlags flags )
734  : QgsDataProvider( QString(), options, flags )
735 {}
736 
738 {
739  return QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:3857" ) );
740 }
741 
742 QString QgsVectorTileDataProvider::name() const
743 {
744  return QStringLiteral( "vectortile" );
745 }
746 
747 QString QgsVectorTileDataProvider::description() const
748 {
749  return QString();
750 }
751 
752 QgsRectangle QgsVectorTileDataProvider::extent() const
753 {
754  return QgsRectangle();
755 }
756 
757 bool QgsVectorTileDataProvider::isValid() const
758 {
759  return true;
760 }
void setType(const QString &type)
Sets the type (nature) of the resource.
void setParentIdentifier(const QString &parentIdentifier)
Sets a reference, URI, URL or some other mechanism to identify the parent resource that this resource...
void setTitle(const QString &title)
Sets the human readable title (name) of the resource, typically displayed in search results.
void setIdentifier(const QString &identifier)
Sets the reference, URI, URL or some other mechanism to identify the resource.
void addLink(const QgsAbstractMetadataBase::Link &link)
Adds an individual link to the existing links.
A thread safe class for performing blocking (sync) network requests, with full support for QGIS proxy...
ErrorCode get(QNetworkRequest &request, bool forceRefresh=false, QgsFeedback *feedback=nullptr)
Performs a "get" operation on the specified request.
@ NetworkError
A network error occurred.
@ ServerExceptionError
An exception was raised by the server.
@ NoError
No error was encountered.
@ TimeoutError
Timeout was reached before a reply was received.
QgsNetworkReplyContent reply() const
Returns the content of the network reply, after a get() or post() request has been made.
This class represents a coordinate reference system (CRS).
Contains information about the context in which a coordinate transform is executed.
Class for doing transforms between two map coordinate systems.
Abstract base class for spatial data provider implementations.
Class for storing the component parts of a RDBMS data source URI (e.g.
QByteArray encodedUri() const
Returns the complete encoded URI as a byte array.
bool hasParam(const QString &key) const
Returns true if a parameter with the specified key exists.
int removeParam(const QString &key)
Removes a generic parameter by key.
void setEncodedUri(const QByteArray &uri)
Sets the complete encoded uri.
QString param(const QString &key) const
Returns a generic parameter value corresponding to the specified key.
void setParam(const QString &key, const QString &value)
Sets a generic parameter value on the URI.
QString authConfigId() const
Returns any associated authentication configuration ID stored in the URI.
static QVariant parseJson(const std::string &jsonString)
Converts JSON jsonString to a QVariant, in case of parsing error an invalid QVariant is returned.
Class for metadata formatter.
QString linksSectionHtml() const
Formats the "Links" section according to a metadata object.
QString extentSectionHtml(const bool showSpatialExtent=true) const
Formats the "Extents" section according to a metadata object (extent and temporal).
QString contactsSectionHtml() const
Formats the "Contacts" section according to a metadata object.
QString identificationSectionHtml() const
Formats the "Identification" section according to a metadata object.
QString historySectionHtml() const
Formats the "History" section according to a metadata object.
QString accessSectionHtml() const
Formats the "Access" section according to a metadata object.
A structured metadata store for a map layer.
void setRights(const QStringList &rights)
Sets a list of rights (attribution or copyright strings) associated with the resource.
Context for a MapBox GL style conversion operation.
void setPixelSizeConversionFactor(double sizeConversionFactor)
Sets the pixel size conversion factor, used to scale the original pixel sizes when converting styles.
void setSprites(const QImage &image, const QVariantMap &definitions)
Sets the sprite image and definitions JSON to use during conversion.
void setTargetUnit(QgsUnitTypes::RenderUnit targetUnit)
Sets the target unit type.
QVariantMap spriteDefinitions() const
Returns the sprite definitions to use during conversion.
Handles conversion of MapBox GL styles to QGIS vector tile renderers and labeling settings.
QgsVectorTileRenderer * renderer() const
Returns a new instance of a vector tile renderer representing the converted style,...
QgsVectorTileLabeling * labeling() const
Returns a new instance of a vector tile labeling representing the converted style,...
Result convert(const QVariantMap &style, QgsMapBoxGlStyleConversionContext *context=nullptr)
Converts a JSON style map, and returns the resultant status of the conversion.
@ Success
Conversion was successful.
QString errorMessage() const
Returns a descriptive error message if an error was encountered during the style conversion,...
QStringList warnings() const
Returns a list of user-friendly warnings generated during the conversion, e.g.
static QString typeToString(QgsMapLayerType type)
Converts a map layer type to a string value.
Base class for utility classes that encapsulate information necessary for rendering of map layers.
Base class for all map layer types.
Definition: qgsmaplayer.h:73
QString name
Definition: qgsmaplayer.h:76
void readStyleManager(const QDomNode &layerNode)
Read style manager's configuration (if any). To be called by subclasses.
void writeStyleManager(QDomNode &layerNode, QDomDocument &doc) const
Write style manager's configuration (if exists). To be called by subclasses.
QString source() const
Returns the source for the layer.
QString providerType() const
Returns the provider type (provider key) for this layer.
void setBlendMode(QPainter::CompositionMode blendMode)
Set the blending mode used for rendering a layer.
QgsMapLayer::LayerFlags flags() const
Returns the flags for this layer.
virtual QString loadDefaultStyle(bool &resultFlag)
Retrieve the default style for this layer if one exists (either as a .qml file on disk or as a record...
QString mLayerName
Name of the layer - used for display.
Definition: qgsmaplayer.h:1928
void triggerRepaint(bool deferredUpdate=false)
Will advise the map canvas (and any other interested party) that this layer requires to be repainted.
QString crsHtmlMetadata() const
Returns a HTML fragment containing the layer's CRS metadata, for use in the htmlMetadata() method.
QgsLayerMetadata metadata
Definition: qgsmaplayer.h:78
QPainter::CompositionMode blendMode() const
Returns the current blending mode for a layer.
virtual void setOpacity(double opacity)
Sets the opacity for the layer, where opacity is a value between 0 (totally transparent) and 1....
virtual void setMetadata(const QgsLayerMetadata &metadata)
Sets the layer's metadata store.
QString mProviderKey
Data provider key (name of the data provider)
Definition: qgsmaplayer.h:1966
QgsCoordinateTransformContext transformContext() const
Returns the layer data provider coordinate transform context or a default transform context if the la...
virtual QgsError error() const
Gets current status error.
virtual void setExtent(const QgsRectangle &rect)
Sets the extent.
QString mDataSource
Data source description string, varies by layer type.
Definition: qgsmaplayer.h:1925
virtual QString loadDefaultMetadata(bool &resultFlag)
Retrieve the default metadata for this layer if one exists (either as a .qmd file on disk or as a rec...
void setValid(bool valid)
Sets whether layer is valid or not.
void readCommonStyle(const QDomElement &layerElement, const QgsReadWriteContext &context, StyleCategories categories=AllStyleCategories)
Read style data common to all layer types.
double opacity
Definition: qgsmaplayer.h:82
@ Symbology
Symbology.
Definition: qgsmaplayer.h:158
@ Rendering
Rendering: scale visibility, simplify method, opacity.
Definition: qgsmaplayer.h:167
@ Labeling
Labeling.
Definition: qgsmaplayer.h:160
QString generalHtmlMetadata() const
Returns an HTML fragment containing general metadata information, for use in the htmlMetadata() metho...
void writeCommonStyle(QDomElement &layerElement, QDomDocument &document, const QgsReadWriteContext &context, StyleCategories categories=AllStyleCategories) const
Write style data common to all layer types.
void invalidateWgs84Extent()
Invalidates the WGS84 extent.
void setCrs(const QgsCoordinateReferenceSystem &srs, bool emitSignal=true)
Sets layer's spatial reference system.
Utility class for reading and writing MBTiles files (which are SQLite3 databases).
Definition: qgsmbtiles.h:39
Encapsulates a network reply within a container which is inexpensive to copy and safe to pass between...
QByteArray content() const
Returns the reply content.
static QgsPainting::BlendMode getBlendModeEnum(QPainter::CompositionMode blendMode)
Returns a BlendMode corresponding to a QPainter::CompositionMode.
Definition: qgspainting.cpp:80
static QPainter::CompositionMode getCompositionMode(QgsPainting::BlendMode blendMode)
Returns a QPainter::CompositionMode corresponding to a BlendMode.
Definition: qgspainting.cpp:20
BlendMode
Blending modes enum defining the available composition modes that can be used when rendering a layer.
Definition: qgspainting.h:37
QString writePath(const QString &filename) const
Prepare a filename to save it to the project file.
QString readPath(const QString &filename) const
Turn filename read from the project file to an absolute path.
The class is used as a container of context for various read/write operations on other objects.
const QgsPathResolver & pathResolver() const
Returns path resolver for conversion between relative and absolute paths.
A rectangle specified with double values.
Definition: qgsrectangle.h:42
Contains information about the context of a rendering operation.
Defines a matrix of tiles for a single zoom level: it is defined by its size (width *.
Definition: qgstiles.h:104
static QgsTileMatrix fromWebMercator(int zoomLevel)
Returns a tile matrix for the usual web mercator.
Definition: qgstiles.cpp:22
Range of tiles in a tile matrix to be rendered.
Definition: qgstiles.h:67
Stores coordinates of a tile in a tile matrix set.
Definition: qgstiles.h:34
int zoomLevel() const
Returns tile's zoom level (Z)
Definition: qgstiles.h:47
int column() const
Returns tile's column index (X)
Definition: qgstiles.h:43
int row() const
Returns tile's row index (Y)
Definition: qgstiles.h:45
@ RenderMillimeters
Millimeters.
Definition: qgsunittypes.h:169
Basic labeling configuration for vector tile layers.
The default vector tile renderer implementation.
static QList< QgsVectorTileBasicRendererStyle > simpleStyleWithRandomColors()
Returns a list of styles to render all layers, using random colors.
Base class for labeling configuration classes for vector tile layers.
virtual void readXml(const QDomElement &elem, const QgsReadWriteContext &context)=0
Reads labeling properties from given XML element.
This class provides map rendering functionality for vector tile layers.
Implements a map layer that is dedicated to rendering of vector tiles.
QgsVectorTileLayer(const QString &path=QString(), const QString &baseName=QString(), const QgsVectorTileLayer::LayerOptions &options=QgsVectorTileLayer::LayerOptions())
Constructs a new vector tile layer.
QByteArray getRawTile(QgsTileXYZ tileID)
Fetches raw tile data for the give tile coordinates.
bool readXml(const QDomNode &layerNode, QgsReadWriteContext &context) override
Called by readLayerXML(), used by children to read state specific to them from project files.
bool writeSymbology(QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsReadWriteContext &context, StyleCategories categories=AllStyleCategories) const override
Write the style for the layer into the document provided.
void setRenderer(QgsVectorTileRenderer *r)
Sets renderer for the map layer.
QString decodedSource(const QString &source, const QString &provider, const QgsReadWriteContext &context) const FINAL
Called by readLayerXML(), used by derived classes to decode provider's specific data source from proj...
QString sourceType() const
Returns type of the data source.
bool writeXml(QDomNode &layerNode, QDomDocument &doc, const QgsReadWriteContext &context) const override
Called by writeLayerXML(), used by children to write state specific to them to project files.
void setLabeling(QgsVectorTileLabeling *labeling)
Sets labeling for the map layer.
QgsVectorTileLabeling * labeling() const
Returns currently assigned labeling.
~QgsVectorTileLayer() override
bool readSymbology(const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context, StyleCategories categories=AllStyleCategories) override
Read the symbology for the current layer from the DOM node supplied.
int sourceMinZoom() const
Returns minimum zoom level at which source has any valid tiles (negative = unconstrained)
QgsMapLayerRenderer * createMapRenderer(QgsRenderContext &rendererContext) override
Returns new instance of QgsMapLayerRenderer that will be used for rendering of given context.
QString loadDefaultStyle(bool &resultFlag) override
Retrieve the default style for this layer if one exists (either as a .qml file on disk or as a record...
QString htmlMetadata() const override
Obtain a formatted HTML string containing assorted metadata for this layer.
QString encodedSource(const QString &source, const QgsReadWriteContext &context) const FINAL
Called by writeLayerXML(), used by derived classes to encode provider's specific data source to proje...
int sourceMaxZoom() const
Returns maximum zoom level at which source has any valid tiles (negative = unconstrained)
QgsVectorTileRenderer * renderer() const
Returns currently assigned renderer.
QgsDataProvider * dataProvider() override
Returns the layer's data provider, it may be nullptr.
QString loadDefaultMetadata(bool &resultFlag) override
Retrieve the default metadata for this layer if one exists (either as a .qmd file on disk or as a rec...
QString sourcePath() const
Returns URL/path of the data source (syntax different to each data source type)
void setTransformContext(const QgsCoordinateTransformContext &transformContext) override
Sets the coordinate transform context to transformContext.
QgsVectorTileLayer * clone() const override
Returns a new instance equivalent to this one except for the id which is still unique.
static QList< QgsVectorTileRawData > blockingFetchTileRawData(const QString &sourceType, const QString &sourcePath, const QgsTileMatrix &tileMatrix, const QPointF &viewCenter, const QgsTileRange &range, const QString &authid, const QString &referer)
Returns raw tile data for the specified range of tiles. Blocks the caller until all tiles are fetched...
Abstract base class for all vector tile renderer implementations.
virtual void readXml(const QDomElement &elem, const QgsReadWriteContext &context)=0
Reads renderer's properties from given XML element.
static bool checkXYZUrlTemplate(const QString &url)
Checks whether the URL template string is correct (contains {x}, {y} / {-y}, {z} placeholders)
QgsMapLayerType
Types of layers that can be added to a map.
Definition: qgis.h:47
@ VectorTileLayer
Added in 3.14.
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
#define QgsSetRequestInitiatorClass(request, _class)
const QgsCoordinateReferenceSystem & crs
Setting options for creating vector data providers.
Setting options for loading vector tile layers.