28#include <QJsonDocument>
30#include <QJsonParseError>
35#include "moc_qgsarcgisvectortileservicedataprovider.cpp"
37using namespace Qt::StringLiterals;
41QString QgsArcGisVectorTileServiceDataProvider::ARCGIS_VT_SERVICE_DATA_PROVIDER_KEY = u
"arcgisvectortileservice"_s;
42QString QgsArcGisVectorTileServiceDataProvider::ARCGIS_VT_SERVICE_DATA_PROVIDER_DESCRIPTION = QObject::tr(
"ArcGIS Vector Tile Service data provider" );
45QgsArcGisVectorTileServiceDataProvider::QgsArcGisVectorTileServiceDataProvider(
const QString &uri,
const ProviderOptions &providerOptions,
Qgis::DataProviderReadFlags flags )
46 : QgsXyzVectorTileDataProviderBase( uri, providerOptions, flags )
48 mIsValid = setupArcgisVectorTileServiceConnection();
54 mLayerMetadata.setIdentifier( mArcgisLayerConfiguration.value( u
"serviceUri"_s ).toString() );
55 const QString parentIdentifier = mArcgisLayerConfiguration.value( u
"serviceItemId"_s ).toString();
56 if ( !parentIdentifier.isEmpty() )
58 mLayerMetadata.setParentIdentifier( parentIdentifier );
60 mLayerMetadata.setType( u
"dataset"_s );
61 mLayerMetadata.setTitle( mArcgisLayerConfiguration.value( u
"name"_s ).toString() );
62 const QString copyright = mArcgisLayerConfiguration.value( u
"copyrightText"_s ).toString();
63 if ( !copyright.isEmpty() )
64 mLayerMetadata.setRights( QStringList() << copyright );
65 mLayerMetadata.addLink(
QgsAbstractMetadataBase::Link( tr(
"Source" ), u
"WWW:LINK"_s, mArcgisLayerConfiguration.value( u
"serviceUri"_s ).toString() ) );
68QgsArcGisVectorTileServiceDataProvider::QgsArcGisVectorTileServiceDataProvider(
const QgsArcGisVectorTileServiceDataProvider &other )
69 : QgsXyzVectorTileDataProviderBase( other )
71 mIsValid = other.mIsValid;
72 mExtent = other.mExtent;
73 mMatrixSet = other.mMatrixSet;
74 mSourcePath = other.mSourcePath;
75 mArcgisLayerConfiguration = other.mArcgisLayerConfiguration;
76 mArcgisStyleConfiguration = other.mArcgisStyleConfiguration;
78 mLayerMetadata = other.mLayerMetadata;
96QString QgsArcGisVectorTileServiceDataProvider::name()
const
100 return ARCGIS_VT_SERVICE_DATA_PROVIDER_KEY;
103QString QgsArcGisVectorTileServiceDataProvider::description()
const
107 return ARCGIS_VT_SERVICE_DATA_PROVIDER_DESCRIPTION;
114 return new QgsArcGisVectorTileServiceDataProvider( *
this );
117QString QgsArcGisVectorTileServiceDataProvider::sourcePath()
const
124bool QgsArcGisVectorTileServiceDataProvider::isValid()
const
131QgsRectangle QgsArcGisVectorTileServiceDataProvider::extent()
const
152QgsLayerMetadata QgsArcGisVectorTileServiceDataProvider::layerMetadata()
const
156 return mLayerMetadata;
159QVariantMap QgsArcGisVectorTileServiceDataProvider::styleDefinition()
const
163 return mArcgisStyleConfiguration;
166QString QgsArcGisVectorTileServiceDataProvider::styleUrl()
const
171 return mArcgisLayerConfiguration.value( u
"serviceUri"_s ).toString() +
'/' + mArcgisLayerConfiguration.value( u
"defaultStyles"_s ).toString();
174QString QgsArcGisVectorTileServiceDataProvider::htmlMetadata()
const
178 if ( !mTileMapUrl.isEmpty() )
179 metadata += u
"<tr><td class=\"highlight\">"_s % tr(
"Tilemap" ) % u
"</td><td><a href=\"%1\">%1</a>"_s.arg( mTileMapUrl ) % u
"</td></tr>\n"_s;
184bool QgsArcGisVectorTileServiceDataProvider::setupArcgisVectorTileServiceConnection()
190 QString tileServiceUri = dsUri.param( u
"url"_s );
192 QUrl url( tileServiceUri );
196 query.addQueryItem( u
"f"_s, u
"pjson"_s );
197 url.setQuery( query );
199 QNetworkRequest request = QNetworkRequest( url );
204 switch ( networkRequest.
get( request ) )
216 const QByteArray raw = content.
content();
220 const QJsonDocument doc = QJsonDocument::fromJson( raw, &err );
226 mArcgisLayerConfiguration = doc.object().toVariantMap();
227 if ( mArcgisLayerConfiguration.contains( u
"error"_s ) )
232 if ( !mArcgisLayerConfiguration.value( u
"tiles"_s ).isValid() )
235 const QString sourceUri = mArcgisLayerConfiguration.value( u
"sources"_s ).toMap().value( u
"esri"_s ).toMap().value( u
"url"_s ).toString();
236 if ( !sourceUri.isEmpty() )
238 QUrl sourceUrl = url.resolved( sourceUri );
239 if ( sourceUrl.toString().endsWith(
'/' ) )
241 const QString sourceUrlString = sourceUrl.toString();
242 sourceUrl = QUrl( sourceUrlString.left( sourceUrlString.size() - 1 ) );
247 query.addQueryItem( u
"f"_s, u
"pjson"_s );
248 sourceUrl.setQuery( query );
250 QNetworkRequest request = QNetworkRequest( sourceUrl );
255 switch ( networkRequest.
get( request ) )
267 const QByteArray raw = content.
content();
271 const QJsonDocument doc = QJsonDocument::fromJson( raw, &err );
277 sourceUrl.setQuery( QUrlQuery() );
278 tileServiceUri = sourceUrl.toString();
281 mArcgisStyleConfiguration = mArcgisLayerConfiguration;
282 mArcgisLayerConfiguration = doc.object().toVariantMap();
283 if ( mArcgisLayerConfiguration.contains( u
"error"_s ) )
292 const QString tileMapEndpoint = mArcgisLayerConfiguration.value( u
"tileMap"_s ).toString();
293 if ( !tileMapEndpoint.isEmpty() )
295 mTileMapUrl = tileServiceUri +
'/' + tileMapEndpoint;
296 QUrl tilemapUrl( mTileMapUrl );
297 tilemapUrl.setQuery( query );
299 QNetworkRequest tileMapRequest = QNetworkRequest( tilemapUrl );
303 switch ( tileMapNetworkRequest.
get( tileMapRequest ) )
315 const QByteArray tileMapRaw = tileMapContent.
content();
317 const QJsonDocument tileMapDoc = QJsonDocument::fromJson( tileMapRaw, &err );
318 if ( !tileMapDoc.isNull() )
320 tileMap = tileMapDoc.object().toVariantMap();
324 mSourcePath = tileServiceUri +
'/' + mArcgisLayerConfiguration.value( u
"tiles"_s ).toList().value( 0 ).toString();
327 QgsDebugError( u
"Invalid format of URL for XYZ source: "_s + tileServiceUri );
331 mArcgisLayerConfiguration.insert( u
"serviceUri"_s, tileServiceUri );
333 mMatrixSet.fromEsriJson( mArcgisLayerConfiguration, tileMap );
334 mCrs = mMatrixSet.crs();
337 if ( dsUri.hasParam( u
"zmin"_s ) )
338 mMatrixSet.dropMatricesOutsideZoomRange( dsUri.param( u
"zmin"_s ).toInt(), 99 );
340 if ( dsUri.hasParam( u
"zmax"_s ) )
341 mMatrixSet.dropMatricesOutsideZoomRange( 0, dsUri.param( u
"zmax"_s ).toInt() );
343 const QVariantMap fullExtent = mArcgisLayerConfiguration.value( u
"fullExtent"_s ).toMap();
344 if ( !fullExtent.isEmpty() )
347 fullExtentRect( fullExtent.value( u
"xmin"_s ).toDouble(), fullExtent.value( u
"ymin"_s ).toDouble(), fullExtent.value( u
"xmax"_s ).toDouble(), fullExtent.value( u
"ymax"_s ).toDouble() );
353 mExtent = extentTransform.transformBoundingBox( fullExtentRect );
357 QgsDebugError( u
"Could not transform layer fullExtent to layer CRS"_s );
366 mExtent = extentTransform.transformBoundingBox(
QgsRectangle( -20037508.3427892, -20037508.3427892, 20037508.3427892, 20037508.3427892 ) );
370 QgsDebugError( u
"Could not transform layer extent to layer CRS"_s );
382QgsArcGisVectorTileServiceDataProviderMetadata::QgsArcGisVectorTileServiceDataProviderMetadata()
383 :
QgsProviderMetadata( QgsArcGisVectorTileServiceDataProvider::ARCGIS_VT_SERVICE_DATA_PROVIDER_KEY, QgsArcGisVectorTileServiceDataProvider::ARCGIS_VT_SERVICE_DATA_PROVIDER_DESCRIPTION )
386QIcon QgsArcGisVectorTileServiceDataProviderMetadata::icon()
const
398 return new QgsArcGisVectorTileServiceDataProvider( uri, options, flags );
401QVariantMap QgsArcGisVectorTileServiceDataProviderMetadata::decodeUri(
const QString &uri )
const
406 QVariantMap uriComponents;
407 uriComponents.insert( u
"type"_s, u
"xyz"_s );
408 uriComponents.insert( u
"serviceType"_s, u
"arcgis"_s );
409 uriComponents.insert( u
"url"_s, dsUri.
param( u
"url"_s ) );
412 uriComponents.insert( u
"zmin"_s, dsUri.
param( u
"zmin"_s ) );
414 uriComponents.insert( u
"zmax"_s, dsUri.
param( u
"zmax"_s ) );
418 if ( dsUri.
hasParam( u
"styleUrl"_s ) )
419 uriComponents.insert( u
"styleUrl"_s, dsUri.
param( u
"styleUrl"_s ) );
422 if ( !authcfg.isEmpty() )
423 uriComponents.insert( u
"authcfg"_s, authcfg );
425 return uriComponents;
428QString QgsArcGisVectorTileServiceDataProviderMetadata::encodeUri(
const QVariantMap &parts )
const
431 dsUri.
setParam( u
"type"_s, u
"xyz"_s );
432 dsUri.
setParam( u
"serviceType"_s, u
"arcgis"_s );
433 dsUri.
setParam( u
"url"_s, parts.value( u
"url"_s ).toString() );
435 if ( parts.contains( u
"zmin"_s ) )
436 dsUri.
setParam( u
"zmin"_s, parts[u
"zmin"_s].toString() );
437 if ( parts.contains( u
"zmax"_s ) )
438 dsUri.
setParam( u
"zmax"_s, parts[u
"zmax"_s].toString() );
442 if ( parts.contains( u
"styleUrl"_s ) )
443 dsUri.
setParam( u
"styleUrl"_s, parts[u
"styleUrl"_s].toString() );
445 if ( parts.contains( u
"authcfg"_s ) )
451QString QgsArcGisVectorTileServiceDataProviderMetadata::absoluteToRelativeUri(
const QString &uri,
const QgsReadWriteContext & )
const
458QString QgsArcGisVectorTileServiceDataProviderMetadata::relativeToAbsoluteUri(
const QString &uri,
const QgsReadWriteContext & )
const
465QList<Qgis::LayerType> QgsArcGisVectorTileServiceDataProviderMetadata::supportedLayerTypes()
const
@ ReadLayerMetadata
Provider can read layer metadata from data store. See QgsDataProvider::layerMetadata().
@ AlwaysUseTileMatrixSetFromProvider
Vector tile layer must always use the tile matrix set from the data provider, and should never store,...
QFlags< DataProviderFlag > DataProviderFlags
Data provider flags.
@ FastExtent2D
Provider's 2D extent retrieval via QgsDataProvider::extent() is always guaranteed to be trivial/fast ...
QFlags< DataProviderReadFlag > DataProviderReadFlags
Flags which control data provider construction.
QFlags< VectorTileProviderCapability > VectorTileProviderCapabilities
Vector tile data provider capabilities.
@ VectorTile
Vector tile layer. Added in QGIS 3.14.
QFlags< VectorTileProviderFlag > VectorTileProviderFlags
Vector tile data provider flags.
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
static QgsCoordinateReferenceSystem convertSpatialReference(const QVariantMap &spatialReferenceMap)
Converts a spatial reference JSON definition to a QgsCoordinateReferenceSystem value.
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, RequestFlags requestFlags=QgsBlockingNetworkRequest::RequestFlags())
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(), post(), head() or put() request has been mad...
Represents a coordinate reference system (CRS).
Custom exception class for Coordinate Reference System related exceptions.
Stores the component parts of a 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.
void setEncodedUri(const QByteArray &uri)
Sets the complete encoded uri.
void setAuthConfigId(const QString &authcfg)
Sets the authentication configuration ID for the URI.
QgsHttpHeaders httpHeaders() const
Returns http headers.
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.
Encapsulates a network reply within a container which is inexpensive to copy and safe to pass between...
QByteArray content() const
Returns the reply content.
A container for the context for various read/write operations on objects.
A rectangle specified with double values.
Base class for vector tile layer data providers.
Encapsulates properties of a vector tile matrix set, including tile origins and scaling information.
static bool checkXYZUrlTemplate(const QString &url)
Checks whether the URL template string is correct (contains {x}, {y} / {-y}, {z} placeholders).
#define QgsDebugError(str)
#define QgsSetRequestInitiatorClass(request, _class)
#define QGIS_PROTECT_QOBJECT_THREAD_ACCESS
Setting options for creating vector data providers.