QGIS API Documentation  3.18.1-Zürich (202f1bf7e5)
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 
38 QgsVectorTileLayer::QgsVectorTileLayer( const QString &uri, const QString &baseName )
40 {
41  mDataSource = uri;
42 
43  setValid( loadDataSource() );
44 
45  // set a default renderer
49 }
50 
51 bool QgsVectorTileLayer::loadDataSource()
52 {
53  QgsDataSourceUri dsUri;
54  dsUri.setEncodedUri( mDataSource );
55 
56  mSourceType = dsUri.param( QStringLiteral( "type" ) );
57  mSourcePath = dsUri.param( QStringLiteral( "url" ) );
58  if ( mSourceType == QLatin1String( "xyz" ) && dsUri.param( QStringLiteral( "serviceType" ) ) == QLatin1String( "arcgis" ) )
59  {
60  if ( !setupArcgisVectorTileServiceConnection( mSourcePath, dsUri ) )
61  return false;
62  }
63  else if ( mSourceType == QLatin1String( "xyz" ) )
64  {
65  if ( !QgsVectorTileUtils::checkXYZUrlTemplate( mSourcePath ) )
66  {
67  QgsDebugMsg( QStringLiteral( "Invalid format of URL for XYZ source: " ) + mSourcePath );
68  return false;
69  }
70 
71  // online tiles
72  mSourceMinZoom = 0;
73  mSourceMaxZoom = 14;
74 
75  if ( dsUri.hasParam( QStringLiteral( "zmin" ) ) )
76  mSourceMinZoom = dsUri.param( QStringLiteral( "zmin" ) ).toInt();
77  if ( dsUri.hasParam( QStringLiteral( "zmax" ) ) )
78  mSourceMaxZoom = dsUri.param( QStringLiteral( "zmax" ) ).toInt();
79 
80  setExtent( QgsRectangle( -20037508.3427892, -20037508.3427892, 20037508.3427892, 20037508.3427892 ) );
81  }
82  else if ( mSourceType == QLatin1String( "mbtiles" ) )
83  {
84  QgsMbTiles reader( mSourcePath );
85  if ( !reader.open() )
86  {
87  QgsDebugMsg( QStringLiteral( "failed to open MBTiles file: " ) + mSourcePath );
88  return false;
89  }
90 
91  QString format = reader.metadataValue( QStringLiteral( "format" ) );
92  if ( format != QLatin1String( "pbf" ) )
93  {
94  QgsDebugMsg( QStringLiteral( "Cannot open MBTiles for vector tiles. Format = " ) + format );
95  return false;
96  }
97 
98  QgsDebugMsgLevel( QStringLiteral( "name: " ) + reader.metadataValue( QStringLiteral( "name" ) ), 2 );
99  bool minZoomOk, maxZoomOk;
100  int minZoom = reader.metadataValue( QStringLiteral( "minzoom" ) ).toInt( &minZoomOk );
101  int maxZoom = reader.metadataValue( QStringLiteral( "maxzoom" ) ).toInt( &maxZoomOk );
102  if ( minZoomOk )
103  mSourceMinZoom = minZoom;
104  if ( maxZoomOk )
105  mSourceMaxZoom = maxZoom;
106  QgsDebugMsgLevel( QStringLiteral( "zoom range: %1 - %2" ).arg( mSourceMinZoom ).arg( mSourceMaxZoom ), 2 );
107 
108  QgsRectangle r = reader.extent();
109  QgsCoordinateTransform ct( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:4326" ) ),
110  QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:3857" ) ), transformContext() );
111  r = ct.transformBoundingBox( r );
112  setExtent( r );
113  }
114  else
115  {
116  QgsDebugMsg( QStringLiteral( "Unknown source type: " ) + mSourceType );
117  return false;
118  }
119 
120  setCrs( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:3857" ) ) );
121  return true;
122 }
123 
124 bool QgsVectorTileLayer::setupArcgisVectorTileServiceConnection( const QString &uri, const QgsDataSourceUri &dataSourceUri )
125 {
126  QNetworkRequest request = QNetworkRequest( QUrl( uri ) );
127 
128  QgsSetRequestInitiatorClass( request, QStringLiteral( "QgsVectorTileLayer" ) );
129 
130  QgsBlockingNetworkRequest networkRequest;
131  switch ( networkRequest.get( request ) )
132  {
134  break;
135 
139  return false;
140  }
141 
142  const QgsNetworkReplyContent content = networkRequest.reply();
143  const QByteArray raw = content.content();
144 
145  // Parse data
146  QJsonParseError err;
147  QJsonDocument doc = QJsonDocument::fromJson( raw, &err );
148  if ( doc.isNull() )
149  {
150  return false;
151  }
152  mArcgisLayerConfiguration = doc.object().toVariantMap();
153  if ( mArcgisLayerConfiguration.contains( QStringLiteral( "error" ) ) )
154  {
155  return false;
156  }
157 
158  mArcgisLayerConfiguration.insert( QStringLiteral( "serviceUri" ), uri );
159  mSourcePath = uri + '/' + mArcgisLayerConfiguration.value( QStringLiteral( "tiles" ) ).toList().value( 0 ).toString();
160  if ( !QgsVectorTileUtils::checkXYZUrlTemplate( mSourcePath ) )
161  {
162  QgsDebugMsg( QStringLiteral( "Invalid format of URL for XYZ source: " ) + mSourcePath );
163  return false;
164  }
165 
166  // if hardcoded zoom limits aren't specified, take them from the server
167  if ( !dataSourceUri.hasParam( QStringLiteral( "zmin" ) ) )
168  mSourceMinZoom = 0;
169  else
170  mSourceMinZoom = dataSourceUri.param( QStringLiteral( "zmin" ) ).toInt();
171 
172  if ( !dataSourceUri.hasParam( QStringLiteral( "zmax" ) ) )
173  mSourceMaxZoom = mArcgisLayerConfiguration.value( QStringLiteral( "maxzoom" ) ).toInt();
174  else
175  mSourceMaxZoom = dataSourceUri.param( QStringLiteral( "zmax" ) ).toInt();
176 
177  setExtent( QgsRectangle( -20037508.3427892, -20037508.3427892, 20037508.3427892, 20037508.3427892 ) );
178 
179  return true;
180 }
181 
183 
184 
186 {
187  QgsVectorTileLayer *layer = new QgsVectorTileLayer( source(), name() );
188  layer->setRenderer( renderer() ? renderer()->clone() : nullptr );
189  return layer;
190 }
191 
193 {
194  return new QgsVectorTileLayerRenderer( this, rendererContext );
195 }
196 
197 bool QgsVectorTileLayer::readXml( const QDomNode &layerNode, QgsReadWriteContext &context )
198 {
199  setValid( loadDataSource() );
200 
201  QString errorMsg;
202  if ( !readSymbology( layerNode, errorMsg, context ) )
203  return false;
204 
205  readStyleManager( layerNode );
206  return true;
207 }
208 
209 bool QgsVectorTileLayer::writeXml( QDomNode &layerNode, QDomDocument &doc, const QgsReadWriteContext &context ) const
210 {
211  QDomElement mapLayerNode = layerNode.toElement();
212  mapLayerNode.setAttribute( QStringLiteral( "type" ), QgsMapLayerFactory::typeToString( QgsMapLayerType::VectorTileLayer ) );
213 
214  writeStyleManager( layerNode, doc );
215 
216  QString errorMsg;
217  return writeSymbology( layerNode, doc, errorMsg, context );
218 }
219 
220 bool QgsVectorTileLayer::readSymbology( const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories )
221 {
222  QDomElement elem = node.toElement();
223 
224  readCommonStyle( elem, context, categories );
225 
226  const QDomElement elemRenderer = elem.firstChildElement( QStringLiteral( "renderer" ) );
227  if ( elemRenderer.isNull() )
228  {
229  errorMessage = tr( "Missing <renderer> tag" );
230  return false;
231  }
232  const QString rendererType = elemRenderer.attribute( QStringLiteral( "type" ) );
233 
234  if ( categories.testFlag( Symbology ) )
235  {
236  QgsVectorTileRenderer *r = nullptr;
237  if ( rendererType == QLatin1String( "basic" ) )
239  else
240  {
241  errorMessage = tr( "Unknown renderer type: " ) + rendererType;
242  return false;
243  }
244 
245  r->readXml( elemRenderer, context );
246  setRenderer( r );
247  }
248 
249  if ( categories.testFlag( Labeling ) )
250  {
251  setLabeling( nullptr );
252  const QDomElement elemLabeling = elem.firstChildElement( QStringLiteral( "labeling" ) );
253  if ( !elemLabeling.isNull() )
254  {
255  const QString labelingType = elemLabeling.attribute( QStringLiteral( "type" ) );
256  QgsVectorTileLabeling *labeling = nullptr;
257  if ( labelingType == QLatin1String( "basic" ) )
259  else
260  {
261  errorMessage = tr( "Unknown labeling type: " ) + rendererType;
262  }
263 
264  if ( labeling )
265  {
266  labeling->readXml( elemLabeling, context );
268  }
269  }
270  }
271 
272  if ( categories.testFlag( Symbology ) )
273  {
274  // get and set the blend mode if it exists
275  QDomNode blendModeNode = node.namedItem( QStringLiteral( "blendMode" ) );
276  if ( !blendModeNode.isNull() )
277  {
278  QDomElement e = blendModeNode.toElement();
279  setBlendMode( QgsPainting::getCompositionMode( static_cast< QgsPainting::BlendMode >( e.text().toInt() ) ) );
280  }
281  }
282 
283  // get and set the layer transparency
284  if ( categories.testFlag( Rendering ) )
285  {
286  QDomNode layerOpacityNode = node.namedItem( QStringLiteral( "layerOpacity" ) );
287  if ( !layerOpacityNode.isNull() )
288  {
289  QDomElement e = layerOpacityNode.toElement();
290  setOpacity( e.text().toDouble() );
291  }
292  }
293 
294  return true;
295 }
296 
297 bool QgsVectorTileLayer::writeSymbology( QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
298 {
299  Q_UNUSED( errorMessage )
300  QDomElement elem = node.toElement();
301 
302  writeCommonStyle( elem, doc, context, categories );
303 
304  if ( mRenderer )
305  {
306  QDomElement elemRenderer = doc.createElement( QStringLiteral( "renderer" ) );
307  elemRenderer.setAttribute( QStringLiteral( "type" ), mRenderer->type() );
308  if ( categories.testFlag( Symbology ) )
309  {
310  mRenderer->writeXml( elemRenderer, context );
311  }
312  elem.appendChild( elemRenderer );
313  }
314 
315  if ( mLabeling && categories.testFlag( Labeling ) )
316  {
317  QDomElement elemLabeling = doc.createElement( QStringLiteral( "labeling" ) );
318  elemLabeling.setAttribute( QStringLiteral( "type" ), mLabeling->type() );
319  mLabeling->writeXml( elemLabeling, context );
320  elem.appendChild( elemLabeling );
321  }
322 
323  if ( categories.testFlag( Symbology ) )
324  {
325  // add the blend mode field
326  QDomElement blendModeElem = doc.createElement( QStringLiteral( "blendMode" ) );
327  QDomText blendModeText = doc.createTextNode( QString::number( QgsPainting::getBlendModeEnum( blendMode() ) ) );
328  blendModeElem.appendChild( blendModeText );
329  node.appendChild( blendModeElem );
330  }
331 
332  // add the layer opacity
333  if ( categories.testFlag( Rendering ) )
334  {
335  QDomElement layerOpacityElem = doc.createElement( QStringLiteral( "layerOpacity" ) );
336  QDomText layerOpacityText = doc.createTextNode( QString::number( opacity() ) );
337  layerOpacityElem.appendChild( layerOpacityText );
338  node.appendChild( layerOpacityElem );
339  }
340 
341  return true;
342 }
343 
345 {
346  Q_UNUSED( transformContext )
347 }
348 
349 QString QgsVectorTileLayer::loadDefaultStyle( bool &resultFlag )
350 {
351  QString error;
352  QStringList warnings;
353  resultFlag = loadDefaultStyle( error, warnings );
354  return error;
355 }
356 
357 bool QgsVectorTileLayer::loadDefaultStyle( QString &error, QStringList &warnings )
358 {
359  QgsDataSourceUri dsUri;
360  dsUri.setEncodedUri( mDataSource );
361 
362  QString styleUrl;
363  if ( !dsUri.param( QStringLiteral( "styleUrl" ) ).isEmpty() )
364  {
365  styleUrl = dsUri.param( QStringLiteral( "styleUrl" ) );
366  }
367  else if ( mSourceType == QLatin1String( "xyz" ) && dsUri.param( QStringLiteral( "serviceType" ) ) == QLatin1String( "arcgis" ) )
368  {
369  // for ArcMap VectorTileServices we default to the defaultStyles URL from the layer configuration
370  styleUrl = mArcgisLayerConfiguration.value( QStringLiteral( "serviceUri" ) ).toString()
371  + '/' + mArcgisLayerConfiguration.value( QStringLiteral( "defaultStyles" ) ).toString();
372  }
373 
374  if ( !styleUrl.isEmpty() )
375  {
376  QNetworkRequest request = QNetworkRequest( QUrl( styleUrl ) );
377 
378  QgsSetRequestInitiatorClass( request, QStringLiteral( "QgsVectorTileLayer" ) );
379 
380  QgsBlockingNetworkRequest networkRequest;
381  switch ( networkRequest.get( request ) )
382  {
384  break;
385 
389  error = QObject::tr( "Error retrieving default style" );
390  return false;
391  }
392 
393  const QgsNetworkReplyContent content = networkRequest.reply();
394  const QVariantMap styleDefinition = QgsJsonUtils::parseJson( content.content() ).toMap();
395 
397  // convert automatically from pixel sizes to millimeters, because pixel sizes
398  // are a VERY edge case in QGIS and don't play nice with hidpi map renders or print layouts
400  //assume source uses 96 dpi
401  context.setPixelSizeConversionFactor( 25.4 / 96.0 );
402 
403  if ( styleDefinition.contains( QStringLiteral( "sprite" ) ) )
404  {
405  // retrieve sprite definition
406  QString spriteUriBase;
407  if ( styleDefinition.value( QStringLiteral( "sprite" ) ).toString().startsWith( QLatin1String( "http" ) ) )
408  {
409  spriteUriBase = styleDefinition.value( QStringLiteral( "sprite" ) ).toString();
410  }
411  else
412  {
413  spriteUriBase = styleUrl + '/' + styleDefinition.value( QStringLiteral( "sprite" ) ).toString();
414  }
415 
416  for ( int resolution = 2; resolution > 0; resolution-- )
417  {
418  QNetworkRequest request = QNetworkRequest( QUrl( spriteUriBase + QStringLiteral( "%1.json" ).arg( resolution > 1 ? QStringLiteral( "@%1x" ).arg( resolution ) : QString() ) ) );
419  QgsSetRequestInitiatorClass( request, QStringLiteral( "QgsVectorTileLayer" ) );
420  QgsBlockingNetworkRequest networkRequest;
421  switch ( networkRequest.get( request ) )
422  {
424  {
425  const QgsNetworkReplyContent content = networkRequest.reply();
426  const QVariantMap spriteDefinition = QgsJsonUtils::parseJson( content.content() ).toMap();
427 
428  // retrieve sprite images
429  QNetworkRequest request = QNetworkRequest( QUrl( spriteUriBase + QStringLiteral( "%1.png" ).arg( resolution > 1 ? QStringLiteral( "@%1x" ).arg( resolution ) : QString() ) ) );
430 
431  QgsSetRequestInitiatorClass( request, QStringLiteral( "QgsVectorTileLayer" ) );
432 
433  QgsBlockingNetworkRequest networkRequest;
434  switch ( networkRequest.get( request ) )
435  {
437  {
438  const QgsNetworkReplyContent imageContent = networkRequest.reply();
439  QImage spriteImage( QImage::fromData( imageContent.content() ) );
440  context.setSprites( spriteImage, spriteDefinition );
441  break;
442  }
443 
447  break;
448  }
449 
450  break;
451  }
452 
456  break;
457  }
458 
459  if ( !context.spriteDefinitions().isEmpty() )
460  break;
461  }
462  }
463 
464  QgsMapBoxGlStyleConverter converter;
465  if ( converter.convert( styleDefinition, &context ) != QgsMapBoxGlStyleConverter::Success )
466  {
467  warnings = converter.warnings();
468  error = converter.errorMessage();
469  return false;
470  }
471 
472  setRenderer( converter.renderer() );
473  setLabeling( converter.labeling() );
474  warnings = converter.warnings();
475  return true;
476  }
477  else
478  {
479  bool resultFlag = false;
480  error = QgsMapLayer::loadDefaultStyle( resultFlag );
481  return resultFlag;
482  }
483 }
484 
485 QString QgsVectorTileLayer::loadDefaultMetadata( bool &resultFlag )
486 {
487  QgsDataSourceUri dsUri;
488  dsUri.setEncodedUri( mDataSource );
489  if ( mSourceType == QLatin1String( "xyz" ) && dsUri.param( QStringLiteral( "serviceType" ) ) == QLatin1String( "arcgis" ) )
490  {
491  // populate default metadata
493  metadata.setIdentifier( mArcgisLayerConfiguration.value( QStringLiteral( "serviceUri" ) ).toString() );
494  const QString parentIdentifier = mArcgisLayerConfiguration.value( QStringLiteral( "serviceItemId" ) ).toString();
495  if ( !parentIdentifier.isEmpty() )
496  {
497  metadata.setParentIdentifier( parentIdentifier );
498  }
499  metadata.setType( QStringLiteral( "dataset" ) );
500  metadata.setTitle( mArcgisLayerConfiguration.value( QStringLiteral( "name" ) ).toString() );
501  QString copyright = mArcgisLayerConfiguration.value( QStringLiteral( "copyrightText" ) ).toString();
502  if ( !copyright.isEmpty() )
503  metadata.setRights( QStringList() << copyright );
504  metadata.addLink( QgsAbstractMetadataBase::Link( tr( "Source" ), QStringLiteral( "WWW:LINK" ), mArcgisLayerConfiguration.value( QStringLiteral( "serviceUri" ) ).toString() ) );
505 
507 
508  resultFlag = true;
509  return QString();
510  }
511  else
512  {
513  QgsMapLayer::loadDefaultMetadata( resultFlag );
514  resultFlag = true;
515  return QString();
516  }
517 }
518 
519 QString QgsVectorTileLayer::encodedSource( const QString &source, const QgsReadWriteContext &context ) const
520 {
521  QgsDataSourceUri dsUri;
522  dsUri.setEncodedUri( source );
523 
524  QString sourceType = dsUri.param( QStringLiteral( "type" ) );
525  QString sourcePath = dsUri.param( QStringLiteral( "url" ) );
526  if ( sourceType == QLatin1String( "xyz" ) )
527  {
528  QUrl sourceUrl( sourcePath );
529  if ( sourceUrl.isLocalFile() )
530  {
531  // relative path will become "file:./x.txt"
532  QString relSrcUrl = context.pathResolver().writePath( sourceUrl.toLocalFile() );
533  dsUri.removeParam( QStringLiteral( "url" ) ); // needed because setParam() would insert second "url" key
534  dsUri.setParam( QStringLiteral( "url" ), QUrl::fromLocalFile( relSrcUrl ).toString() );
535  return dsUri.encodedUri();
536  }
537  }
538  else if ( sourceType == QLatin1String( "mbtiles" ) )
539  {
541  dsUri.removeParam( QStringLiteral( "url" ) ); // needed because setParam() would insert second "url" key
542  dsUri.setParam( QStringLiteral( "url" ), sourcePath );
543  return dsUri.encodedUri();
544  }
545 
546  return source;
547 }
548 
549 QString QgsVectorTileLayer::decodedSource( const QString &source, const QString &provider, const QgsReadWriteContext &context ) const
550 {
551  Q_UNUSED( provider )
552 
553  QgsDataSourceUri dsUri;
554  dsUri.setEncodedUri( source );
555 
556  QString sourceType = dsUri.param( QStringLiteral( "type" ) );
557  QString sourcePath = dsUri.param( QStringLiteral( "url" ) );
558  if ( sourceType == QLatin1String( "xyz" ) )
559  {
560  QUrl sourceUrl( sourcePath );
561  if ( sourceUrl.isLocalFile() ) // file-based URL? convert to relative path
562  {
563  QString absSrcUrl = context.pathResolver().readPath( sourceUrl.toLocalFile() );
564  dsUri.removeParam( QStringLiteral( "url" ) ); // needed because setParam() would insert second "url" key
565  dsUri.setParam( QStringLiteral( "url" ), QUrl::fromLocalFile( absSrcUrl ).toString() );
566  return dsUri.encodedUri();
567  }
568  }
569  else if ( sourceType == QLatin1String( "mbtiles" ) )
570  {
572  dsUri.removeParam( QStringLiteral( "url" ) ); // needed because setParam() would insert second "url" key
573  dsUri.setParam( QStringLiteral( "url" ), sourcePath );
574  return dsUri.encodedUri();
575  }
576 
577  return source;
578 }
579 
581 {
582  QgsLayerMetadataFormatter htmlFormatter( metadata() );
583 
584  QString info = QStringLiteral( "<html><head></head>\n<body>\n" );
585 
586  info += QStringLiteral( "<h1>" ) + tr( "Information from provider" ) + QStringLiteral( "</h1>\n<hr>\n" ) %
587  QStringLiteral( "<table class=\"list-view\">\n" ) %
588 
589  // name
590  QStringLiteral( "<tr><td class=\"highlight\">" ) % tr( "Name" ) % QStringLiteral( "</td><td>" ) % name() % QStringLiteral( "</td></tr>\n" );
591 
592  info += QStringLiteral( "<tr><td class=\"highlight\">" ) % tr( "URI" ) % QStringLiteral( "</td><td>" ) % source() % QStringLiteral( "</td></tr>\n" );
593  info += QStringLiteral( "<tr><td class=\"highlight\">" ) % tr( "Source type" ) % QStringLiteral( "</td><td>" ) % sourceType() % QStringLiteral( "</td></tr>\n" );
594 
595  const QString url = sourcePath();
596  info += QStringLiteral( "<tr><td class=\"highlight\">" ) % tr( "Source path" ) % QStringLiteral( "</td><td>%1" ).arg( QStringLiteral( "<a href=\"%1\">%2</a>" ).arg( QUrl( url ).toString(), sourcePath() ) ) + QStringLiteral( "</td></tr>\n" );
597 
598  info += QStringLiteral( "<tr><td class=\"highlight\">" ) % tr( "Zoom levels" ) % QStringLiteral( "</td><td>" ) % QStringLiteral( "%1 - %2" ).arg( sourceMinZoom() ).arg( sourceMaxZoom() ) % QStringLiteral( "</td></tr>\n" );
599  info += QLatin1String( "</table>" );
600 
601  // End Provider section
602  info += QLatin1String( "</table>\n<br><br>" );
603 
604  // Identification section
605  info += QStringLiteral( "<h1>" ) % tr( "Identification" ) % QStringLiteral( "</h1>\n<hr>\n" ) %
606  htmlFormatter.identificationSectionHtml() %
607  QStringLiteral( "<br><br>\n" ) %
608 
609  // extent section
610  QStringLiteral( "<h1>" ) % tr( "Extent" ) % QStringLiteral( "</h1>\n<hr>\n" ) %
611  htmlFormatter.extentSectionHtml( ) %
612  QStringLiteral( "<br><br>\n" ) %
613 
614  // Start the Access section
615  QStringLiteral( "<h1>" ) % tr( "Access" ) % QStringLiteral( "</h1>\n<hr>\n" ) %
616  htmlFormatter.accessSectionHtml( ) %
617  QStringLiteral( "<br><br>\n" ) %
618 
619 
620  // Start the contacts section
621  QStringLiteral( "<h1>" ) % tr( "Contacts" ) % QStringLiteral( "</h1>\n<hr>\n" ) %
622  htmlFormatter.contactsSectionHtml( ) %
623  QStringLiteral( "<br><br>\n" ) %
624 
625  // Start the links section
626  QStringLiteral( "<h1>" ) % tr( "References" ) % QStringLiteral( "</h1>\n<hr>\n" ) %
627  htmlFormatter.linksSectionHtml( ) %
628  QStringLiteral( "<br><br>\n" ) %
629 
630  // Start the history section
631  QStringLiteral( "<h1>" ) % tr( "History" ) % QStringLiteral( "</h1>\n<hr>\n" ) %
632  htmlFormatter.historySectionHtml( ) %
633  QStringLiteral( "<br><br>\n" ) %
634 
635  QStringLiteral( "\n</body>\n</html>\n" );
636 
637  return info;
638 }
639 
641 {
642  QgsTileMatrix tileMatrix = QgsTileMatrix::fromWebMercator( tileID.zoomLevel() );
643  QgsTileRange tileRange( tileID.column(), tileID.column(), tileID.row(), tileID.row() );
644 
645  QgsDataSourceUri dsUri;
646  dsUri.setEncodedUri( mDataSource );
647  const QString authcfg = dsUri.authConfigId();
648  const QString referer = dsUri.param( QStringLiteral( "referer" ) );
649 
650  QList<QgsVectorTileRawData> rawTiles = QgsVectorTileLoader::blockingFetchTileRawData( mSourceType, mSourcePath, tileMatrix, QPointF(), tileRange, authcfg, referer );
651  if ( rawTiles.isEmpty() )
652  return QByteArray();
653  return rawTiles.first().data;
654 }
655 
657 {
658  mRenderer.reset( r );
659  triggerRepaint();
660 }
661 
663 {
664  return mRenderer.get();
665 }
666 
668 {
669  mLabeling.reset( labeling );
670  triggerRepaint();
671 }
672 
674 {
675  return mLabeling.get();
676 }
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.
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:85
QString name
Definition: qgsmaplayer.h:88
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.
void setBlendMode(QPainter::CompositionMode blendMode)
Set the blending mode used for rendering a 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...
void triggerRepaint(bool deferredUpdate=false)
Will advise the map canvas (and any other interested party) that this layer requires to be repainted.
QgsLayerMetadata metadata
Definition: qgsmaplayer.h:90
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.
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:1612
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:94
@ Symbology
Symbology.
Definition: qgsmaplayer.h:170
@ Rendering
Rendering: scale visibility, simplify method, opacity.
Definition: qgsmaplayer.h:179
@ Labeling
Labeling.
Definition: qgsmaplayer.h:172
void writeCommonStyle(QDomElement &layerElement, QDomDocument &document, const QgsReadWriteContext &context, StyleCategories categories=AllStyleCategories) const
Write style data common to all layer types.
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:103
static QgsTileMatrix fromWebMercator(int mZoomLevel)
Returns a tile matrix for the usual web mercator.
Definition: qgstiles.cpp:20
Range of tiles in a tile matrix to be rendered.
Definition: qgstiles.h:66
Stores coordinates of a tile in a tile matrix set.
Definition: qgstiles.h:33
int zoomLevel() const
Returns tile's zoom level (Z)
Definition: qgstiles.h:46
int column() const
Returns tile's column index (X)
Definition: qgstiles.h:42
int row() const
Returns tile's row index (Y)
Definition: qgstiles.h:44
@ RenderMillimeters
Millimeters.
Definition: qgsunittypes.h:168
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.
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 docment 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...
QgsVectorTileLayer(const QString &path=QString(), const QString &baseName=QString())
Constructs a new vector tile layer.
int sourceMaxZoom() const
Returns maximum zoom level at which source has any valid tiles (negative = unconstrained)
QgsVectorTileRenderer * renderer() const
Returns currently assigned renderer.
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: qgsmaplayer.h:69
@ VectorTileLayer
Added in 3.14.
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
#define QgsSetRequestInitiatorClass(request, _class)