30#include <QCryptographicHash>
32#include <QImageReader>
33#include <QJsonParseError>
34#include <QRegularExpression>
39#include "moc_qgsarcgisrestquery.cpp"
41using namespace Qt::StringLiterals;
45 if ( url.isEmpty() || !url.isValid() )
50 const QString path = url.path();
55 const QStringList pathSegments = path.split(
'/', Qt::SkipEmptyParts );
60 for (
const QString &
segment : pathSegments | std::ranges::views::reverse )
62 if (
segment.compare(
"FeatureServer"_L1, Qt::CaseInsensitive ) == 0 )
66 if (
segment.compare(
"MapServer"_L1, Qt::CaseInsensitive ) == 0 )
70 if (
segment.compare(
"ImageServer"_L1, Qt::CaseInsensitive ) == 0 )
74 if (
segment.compare(
"SceneServer"_L1, Qt::CaseInsensitive ) == 0 )
91 if ( json.contains( u
"pixelSizeX"_s )
92 || json.contains( u
"bandCount"_s )
93 || json.contains( u
"mensurationCapabilities"_s )
94 || json.value( u
"serviceDataType"_s ).toString().startsWith(
"esriImageService"_L1, Qt::CaseInsensitive ) )
100 if ( json.contains( u
"mapName"_s ) || json.contains( u
"singleFusedMapCache"_s ) )
106 if ( json.contains( u
"hasVersionedData"_s ) || json.contains( u
"syncEnabled"_s ) || json.contains( u
"allowGeometryUpdates"_s ) || json.contains( u
"supportsDisconnectedEditing"_s ) )
112 if ( json.contains( u
"store"_s ) && json.contains( u
"layerType"_s ) )
117 if ( json.contains( u
"layers"_s ) )
119 const QVariantList layersList = json.value( u
"layers"_s ).toList();
120 if ( !layersList.empty() )
122 const QVariantMap firstLayer = layersList.first().toMap();
124 if ( firstLayer.contains( u
"layerType"_s ) || firstLayer.contains( u
"store"_s ) )
134 if ( json.contains( u
"type"_s ) )
136 const QString typeStr = json.value( u
"type"_s ).toString();
137 if ( typeStr.compare(
"Feature Layer"_L1, Qt::CaseInsensitive ) == 0 || typeStr.compare(
"Table"_L1, Qt::CaseInsensitive ) == 0 )
147 const QString &baseurl,
const QString &authcfg, QString &errorTitle, QString &errorText,
const QgsHttpHeaders &requestHeaders,
const QString &urlPrefix,
bool forceRefresh
151 QUrl queryUrl( baseurl );
152 QUrlQuery query( queryUrl );
153 query.addQueryItem( u
"f"_s, u
"json"_s );
154 queryUrl.setQuery( query );
155 return queryServiceJSON( queryUrl, authcfg, errorTitle, errorText, requestHeaders,
nullptr, urlPrefix, forceRefresh );
161 QUrl queryUrl( layerurl );
162 QUrlQuery query( queryUrl );
163 query.addQueryItem( u
"f"_s, u
"json"_s );
164 queryUrl.setQuery( query );
165 return queryServiceJSON( queryUrl, authcfg, errorTitle, errorText, requestHeaders,
nullptr, urlPrefix );
169 const QString &layerurl,
const QString &authcfg, QString &errorTitle, QString &errorText,
const QgsHttpHeaders &requestHeaders,
const QString &urlPrefix,
const QgsRectangle &bbox,
const QString &whereClause
173 QUrl queryUrl( layerurl +
"/query" );
174 QUrlQuery query( queryUrl );
175 query.addQueryItem( u
"f"_s, u
"json"_s );
176 query.addQueryItem( u
"where"_s, whereClause.isEmpty() ? u
"1=1"_s : whereClause );
177 query.addQueryItem( u
"returnIdsOnly"_s, u
"true"_s );
180 query.addQueryItem( u
"geometry"_s, u
"%1,%2,%3,%4"_s.arg( bbox.
xMinimum(), 0,
'f', -1 ).arg( bbox.
yMinimum(), 0,
'f', -1 ).arg( bbox.
xMaximum(), 0,
'f', -1 ).arg( bbox.
yMaximum(), 0,
'f', -1 ) );
181 query.addQueryItem( u
"geometryType"_s, u
"esriGeometryEnvelope"_s );
182 query.addQueryItem( u
"spatialRel"_s, u
"esriSpatialRelEnvelopeIntersects"_s );
184 queryUrl.setQuery( query );
185 return queryServiceJSON( queryUrl, authcfg, errorTitle, errorText, requestHeaders,
nullptr, urlPrefix );
191 QUrl queryUrl( layerurl +
"/query" );
192 QUrlQuery query( queryUrl );
193 query.addQueryItem( u
"f"_s, u
"json"_s );
194 query.addQueryItem( u
"where"_s, whereClause );
195 query.addQueryItem( u
"returnExtentOnly"_s, u
"true"_s );
196 queryUrl.setQuery( query );
199 const QVariantMap res =
queryServiceJSON( queryUrl, authcfg, errorTitle, errorText, requestHeaders,
nullptr, urlPrefix );
202 QgsDebugError( u
"getExtent failed: %1 - %2"_s.arg( errorTitle, errorText ) );
210 const QString &layerurl,
211 const QString &authcfg,
212 const QList<quint32> &objectIds,
215 const QStringList &fetchAttributes,
222 const QString &urlPrefix
226 for (
const int id : objectIds )
228 ids.append( QString::number(
id ) );
230 QUrl queryUrl( layerurl +
"/query" );
231 QUrlQuery query( queryUrl );
232 query.addQueryItem( u
"f"_s, u
"json"_s );
233 query.addQueryItem( u
"objectIds"_s, ids.join(
','_L1 ) );
234 if ( !crs.isEmpty() && crs.contains(
':' ) )
236 const QString wkid = crs.indexOf(
':'_L1 ) >= 0 ? crs.split(
':' )[1] : QString();
237 query.addQueryItem( u
"inSR"_s, wkid );
238 query.addQueryItem( u
"outSR"_s, wkid );
241 query.addQueryItem( u
"returnGeometry"_s, fetchGeometry ? u
"true"_s : u
"false"_s );
244 if ( fetchAttributes.isEmpty() )
247 outFields = fetchAttributes.join(
',' );
248 query.addQueryItem( u
"outFields"_s, outFields );
250 query.addQueryItem( u
"returnM"_s, fetchM ? u
"true"_s : u
"false"_s );
251 query.addQueryItem( u
"returnZ"_s, fetchZ ? u
"true"_s : u
"false"_s );
252 queryUrl.setQuery( query );
253 return queryServiceJSON( queryUrl, authcfg, errorTitle, errorText, requestHeaders, feedback, urlPrefix );
257 const QString &layerurl,
261 const QString &authcfg,
264 const QString &whereClause,
265 const QString &urlPrefix
268 QUrl queryUrl( layerurl +
"/query" );
269 QUrlQuery query( queryUrl );
270 query.addQueryItem( u
"f"_s, u
"json"_s );
271 query.addQueryItem( u
"where"_s, whereClause.isEmpty() ? u
"1=1"_s : whereClause );
272 query.addQueryItem( u
"returnIdsOnly"_s, u
"true"_s );
273 query.addQueryItem( u
"geometry"_s, u
"%1,%2,%3,%4"_s.arg( filterRect.
xMinimum(), 0,
'f', -1 ).arg( filterRect.
yMinimum(), 0,
'f', -1 ).arg( filterRect.
xMaximum(), 0,
'f', -1 ).arg( filterRect.
yMaximum(), 0,
'f', -1 ) );
274 query.addQueryItem( u
"geometryType"_s, u
"esriGeometryEnvelope"_s );
275 query.addQueryItem( u
"spatialRel"_s, u
"esriSpatialRelEnvelopeIntersects"_s );
276 queryUrl.setQuery( query );
277 const QVariantMap objectIdData =
queryServiceJSON( queryUrl, authcfg, errorTitle, errorText, requestHeaders, feedback, urlPrefix );
279 if ( objectIdData.isEmpty() )
281 return QList<quint32>();
285 const QVariantList objectIdsList = objectIdData[u
"objectIds"_s].toList();
286 ids.reserve( objectIdsList.size() );
287 for (
const QVariant &objectId : objectIdsList )
289 ids << objectId.toInt();
295 const QUrl &u,
const QString &authcfg, QString &errorTitle, QString &errorText,
const QgsHttpHeaders &requestHeaders,
QgsFeedback *feedback, QString *contentType,
const QString &urlPrefix,
bool forceRefresh
300 if ( !urlPrefix.isEmpty() )
301 url = QUrl( urlPrefix + url.toString() );
303 QNetworkRequest request( url );
318 errorTitle = u
"Network error"_s;
322 const QString content = networkRequest.
reply().
content();
323 const thread_local QRegularExpression errorRx( u
"Error: <.*?>(.*?)<"_s );
324 const QRegularExpressionMatch match = errorRx.match( content );
325 if ( match.hasMatch() )
327 errorText = match.captured( 1 );
335 *contentType = content.
rawHeader(
"Content-Type" );
340 const QUrl &url,
const QString &authcfg, QString &errorTitle, QString &errorText,
const QgsHttpHeaders &requestHeaders,
QgsFeedback *feedback,
const QString &urlPrefix,
bool forceRefresh
343 const QByteArray reply =
queryService( url, authcfg, errorTitle, errorText, requestHeaders, feedback,
nullptr, urlPrefix, forceRefresh );
344 if ( !errorTitle.isEmpty() )
346 return QVariantMap();
349 return QVariantMap();
353 const QJsonDocument doc = QJsonDocument::fromJson( reply, &err );
356 errorTitle = u
"Parsing error"_s;
357 errorText = err.errorString();
358 QgsDebugError( u
"Parsing error: %1"_s.arg( err.errorString() ) );
359 return QVariantMap();
361 const QVariantMap res = doc.object().toVariantMap();
362 if ( res.contains( u
"error"_s ) )
364 const QVariantMap error = res.value( u
"error"_s ).toMap();
365 errorText = error.value( u
"message"_s ).toString();
366 errorTitle = QObject::tr(
"Error %1" ).arg( error.value( u
"code"_s ).toString() );
367 return QVariantMap();
374 if ( isTestEndpoint )
375 *isTestEndpoint =
false;
377 QUrl modifiedUrl( url );
378 if ( modifiedUrl.toString().contains(
"fake_qgis_http_endpoint"_L1 ) )
380 if ( isTestEndpoint )
381 *isTestEndpoint =
true;
384 QString modifiedUrlString = modifiedUrl.toString();
386 modifiedUrlString = QUrl::fromPercentEncoding( modifiedUrlString.toUtf8() );
387 modifiedUrlString.replace(
"fake_qgis_http_endpoint/"_L1,
"fake_qgis_http_endpoint_"_L1 );
389 modifiedUrlString = modifiedUrlString.mid( u
"http://"_s.size() );
390 QString args = modifiedUrlString.indexOf(
'?' ) >= 0 ? modifiedUrlString.mid( modifiedUrlString.indexOf(
'?' ) ) : QString();
391 if ( modifiedUrlString.size() > 150 )
393 args = QCryptographicHash::hash( args.toUtf8(), QCryptographicHash::Md5 ).toHex();
397 args.replace(
"?"_L1,
"_"_L1 );
398 args.replace(
"&"_L1,
"_"_L1 );
399 args.replace(
"<"_L1,
"_"_L1 );
400 args.replace(
">"_L1,
"_"_L1 );
401 args.replace(
"'"_L1,
"_"_L1 );
402 args.replace(
"\""_L1,
"_"_L1 );
403 args.replace(
" "_L1,
"_"_L1 );
404 args.replace(
":"_L1,
"_"_L1 );
405 args.replace(
"/"_L1,
"_"_L1 );
406 args.replace(
"\n"_L1,
"_"_L1 );
411 if ( modifiedUrlString[1] ==
'/' )
413 modifiedUrlString = modifiedUrlString[0] +
":/" + modifiedUrlString.mid( 2 );
416 modifiedUrlString = modifiedUrlString.mid( 0, modifiedUrlString.indexOf(
'?' ) ) + args;
418 if ( modifiedUrlString.contains(
"tile/" ) )
420 modifiedUrlString = modifiedUrlString.left( modifiedUrlString.indexOf(
"tile/" ) + 4 ) + modifiedUrlString.mid( modifiedUrlString.indexOf(
"tile/" ) + 4 ).replace(
'/',
'_' );
423 QgsDebugMsgLevel( u
"Get %1 (after laundering)"_s.arg( modifiedUrlString ), 2 );
424 modifiedUrl = QUrl::fromLocalFile( modifiedUrlString );
425 if ( !QFile::exists( modifiedUrlString ) )
427 QgsDebugError( u
"Local test file %1 for URL %2 does not exist!!!"_s.arg( modifiedUrlString, url.toString() ) );
434void QgsArcGisRestQueryUtils::adjustBaseUrl( QString &baseUrl,
const QString &name )
436 const QStringList parts = name.split(
'/' );
438 for (
const QString &part : parts )
440 if ( !checkString.isEmpty() )
441 checkString += QString(
'/' );
444 if ( baseUrl.indexOf( QRegularExpression( checkString.replace(
'/',
"\\/"_L1 ) + u
"\\/?$"_s ) ) > -1 )
446 baseUrl = baseUrl.left( baseUrl.length() - checkString.length() - 1 );
454 QString base( baseUrl );
455 bool baseChecked =
false;
456 if ( !base.endsWith(
'/' ) )
459 const QStringList folderList = serviceData.value( u
"folders"_s ).toStringList();
460 for (
const QString &folder : folderList )
464 adjustBaseUrl( base, folder );
467 visitor( folder, base + folder );
473 QString base( baseUrl );
474 bool baseChecked =
false;
475 if ( !base.endsWith(
'/' ) )
478 const QVariantList serviceList = serviceData.value( u
"services"_s ).toList();
479 for (
const QVariant &service : serviceList )
481 const QVariantMap serviceMap = service.toMap();
482 const QString serviceTypeString = serviceMap.value( u
"type"_s ).toString();
485 switch ( serviceType )
502 const QString serviceName = serviceMap.value( u
"name"_s ).toString();
503 const QString displayName = serviceName.split(
'/' ).last();
506 adjustBaseUrl( base, serviceName );
510 visitor( displayName, base + serviceName +
'/' + serviceTypeString, serviceType );
521 const QList<QByteArray> supportedFormats = QImageReader::supportedImageFormats();
522 const QStringList supportedImageFormatTypes = serviceData.value( u
"supportedImageFormatTypes"_s ).toString().isEmpty() ? parentSupportedFormats.split(
',' )
523 : serviceData.value( u
"supportedImageFormatTypes"_s ).toString().split(
',' );
524 QString format = supportedImageFormatTypes.value( 0 );
525 for (
const QString &encoding : supportedImageFormatTypes )
527 for (
const QByteArray &fmt : supportedFormats )
529 if ( encoding.startsWith( fmt, Qt::CaseInsensitive ) )
548 const QVariantList layerInfoList = serviceData.value( u
"layers"_s ).toList();
549 for (
const QVariant &layerInfo : layerInfoList )
551 const QVariantMap layerInfoMap = layerInfo.toMap();
554 details.
layerId = layerInfoMap.value( u
"id"_s ).toString();
555 details.
parentLayerId = layerInfoMap.value( u
"parentLayerId"_s ).toString();
556 details.
name = layerInfoMap.value( u
"name"_s ).toString();
557 details.
description = layerInfoMap.value( u
"description"_s ).toString();
559 const QString geometryType = layerInfoMap.value( u
"geometryType"_s ).toString();
572 if ( geometryType.isEmpty() )
582 details.
url = parentUrl;
592 bool exposedAsVector =
false;
595 exposedAsVector =
true;
599 details.
url = parentUrl +
'/' + details.
layerId;
602 if ( !layerInfoMap.value( u
"subLayerIds"_s ).toList().empty() )
624 details.
url = parentUrl +
'/' + details.
layerId;
627 if ( !layerInfoMap.value( u
"subLayerIds"_s ).toList().empty() )
629 if ( !exposedAsVector )
645 const QVariantList tableInfoList = serviceData.value( u
"tables"_s ).toList();
648 for (
const QVariant &tableInfo : tableInfoList )
650 const QVariantMap tableInfoMap = tableInfo.toMap();
653 details.
layerId = tableInfoMap.value( u
"id"_s ).toString();
654 details.
parentLayerId = tableInfoMap.value( u
"parentLayerId"_s ).toString();
655 details.
name = tableInfoMap.value( u
"name"_s ).toString();
656 details.
description = tableInfoMap.value( u
"description"_s ).toString();
660 details.
url = parentUrl +
'/' + details.
layerId;
663 if ( !tableInfoMap.value( u
"subLayerIds"_s ).toList().empty() )
681 switch ( serviceType )
686 details.
layerId = serviceData.value( u
"id"_s ).toString();
687 details.
name = serviceData.value( u
"name"_s ).toString();
688 details.
description = serviceData.value( u
"description"_s ).toString();
689 const QString geometryType = serviceData.value( u
"geometryType"_s ).toString();
693 details.
url = parentUrl;
704 details.
name = serviceData.value( u
"serviceDescription"_s ).toString();
705 details.
description = serviceData.value( u
"description"_s ).toString();
708 details.
url = parentUrl;
722 details.
name = serviceData.value( u
"name"_s ).toString();
723 details.
description = serviceData.value( u
"description"_s ).toString();
726 details.
url = parentUrl;
737 details.
layerId = serviceData.value( u
"id"_s ).toString();
738 details.
name = serviceData.value( u
"name"_s ).toString();
739 details.
description = serviceData.value( u
"description"_s ).toString();
742 details.
url = parentUrl;
765 details.
url = parentUrl;
782QgsArcGisAsyncQuery::QgsArcGisAsyncQuery( QObject *parent )
786QgsArcGisAsyncQuery::~QgsArcGisAsyncQuery()
789 mReply->deleteLater();
792void QgsArcGisAsyncQuery::start(
const QUrl &url,
const QString &authCfg, QByteArray *result,
bool allowCache,
const QgsHttpHeaders &headers,
const QString &urlPrefix )
796 if ( !urlPrefix.isEmpty() )
797 mUrl = QUrl( urlPrefix + url.toString() );
798 QNetworkRequest request( mUrl );
804 const QString error = tr(
"network request update failed for authentication config" );
805 emit failed( u
"Network"_s, error );
810 request.setAttribute( QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::ManualRedirectPolicy );
813 request.setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache );
814 request.setAttribute( QNetworkRequest::CacheSaveControlAttribute,
true );
818 connect( mReply, &QNetworkReply::finished,
this, &QgsArcGisAsyncQuery::handleReply );
821void QgsArcGisAsyncQuery::handleReply()
823 mReply->deleteLater();
825 if ( mReply->error() != QNetworkReply::NoError )
827 QgsDebugError( u
"Network error: %1"_s.arg( mReply->errorString() ) );
828 emit failed( u
"Network error"_s, mReply->errorString() );
833 const QVariant redirect = mReply->attribute( QNetworkRequest::RedirectionTargetAttribute );
836 QNetworkRequest request = mReply->request();
837 request.setAttribute( QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::ManualRedirectPolicy );
840 request.setUrl( redirect.toUrl() );
842 connect( mReply, &QNetworkReply::finished,
this, &QgsArcGisAsyncQuery::handleReply );
846 *mResult = mReply->readAll();
855QgsArcGisAsyncParallelQuery::QgsArcGisAsyncParallelQuery(
const QString &authcfg,
const QgsHttpHeaders &requestHeaders, QObject *parent )
857 , mAuthCfg( authcfg )
858 , mRequestHeaders( requestHeaders )
861void QgsArcGisAsyncParallelQuery::start(
const QVector<QUrl> &urls, QVector<QByteArray> *results,
bool allowCache )
863 Q_ASSERT( results->size() == urls.size() );
865 mPendingRequests = mResults->size();
866 for (
int i = 0, n = urls.size(); i < n; ++i )
868 QNetworkRequest request( urls[i] );
872 mRequestHeaders.updateNetworkRequest( request );
875 const QString error = tr(
"network request update failed for authentication config" );
876 mErrors.append( error );
881 request.setAttribute( QNetworkRequest::HttpPipeliningAllowedAttribute,
true );
884 request.setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache );
885 request.setAttribute( QNetworkRequest::CacheSaveControlAttribute,
true );
886 request.setRawHeader(
"Connection",
"keep-alive" );
889 reply->setProperty(
"idx", i );
890 connect( reply, &QNetworkReply::finished,
this, &QgsArcGisAsyncParallelQuery::handleReply );
894void QgsArcGisAsyncParallelQuery::handleReply()
896 QNetworkReply *reply = qobject_cast<QNetworkReply *>( QObject::sender() );
897 const QVariant redirect = reply->attribute( QNetworkRequest::RedirectionTargetAttribute );
898 const int idx = reply->property(
"idx" ).toInt();
899 reply->deleteLater();
900 if ( reply->error() != QNetworkReply::NoError )
903 mErrors.append( reply->errorString() );
909 QNetworkRequest request = reply->request();
910 request.setAttribute( QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::ManualRedirectPolicy );
913 request.setUrl( redirect.toUrl() );
915 reply->setProperty(
"idx", idx );
916 connect( reply, &QNetworkReply::finished,
this, &QgsArcGisAsyncParallelQuery::handleReply );
921 ( *mResults )[idx] = reply->readAll();
924 if ( mPendingRequests == 0 )
926 emit finished( mErrors );
ArcGisRestServiceType
Available ArcGIS REST service types.
@ GeocodeServer
GeocodeServer.
@ SceneServer
SceneServer.
@ Unknown
Other unknown/unsupported type.
@ GlobeServer
GlobeServer.
@ ImageServer
ImageServer.
@ FeatureServer
FeatureServer.
QFlags< ArcGisRestServiceCapability > ArcGisRestServiceCapabilities
Available ArcGIS REST service capabilities.
WkbType
The WKB type describes the number of dimensions a geometry has.
static QgsAuthManager * authManager()
Returns the application's authentication manager instance.
static void visitFolderItems(const std::function< void(const QString &folderName, const QString &url)> &visitor, const QVariantMap &serviceData, const QString &baseUrl)
Calls the specified visitor function on all folder items found within the given service data.
static QVariantMap queryServiceJSON(const QUrl &url, const QString &authcfg, QString &errorTitle, QString &errorText, const QgsHttpHeaders &requestHeaders=QgsHttpHeaders(), QgsFeedback *feedback=nullptr, const QString &urlPrefix=QString(), bool forceRefresh=false)
Performs a blocking request to a URL and returns the retrieved JSON content.
static QgsRectangle getExtent(const QString &layerurl, const QString &whereClause, const QString &authcfg, const QgsHttpHeaders &requestHeaders=QgsHttpHeaders(), const QString &urlPrefix=QString())
Retrieves the extent for the features matching a whereClause.
static Qgis::ArcGisRestServiceType sniffServiceTypeFromJson(const QVariantMap &json)
Attempts to resolve the service type from a json definition.
static QVariantMap getObjectIds(const QString &layerurl, const QString &authcfg, QString &errorTitle, QString &errorText, const QgsHttpHeaders &requestHeaders=QgsHttpHeaders(), const QString &urlPrefix=QString(), const QgsRectangle &bbox=QgsRectangle(), const QString &whereClause=QString())
Retrieves all object IDs for the specified layer URL.
static QUrl parseUrl(const QUrl &url, bool *isTestEndpoint=nullptr)
Parses and processes a url.
static QByteArray queryService(const QUrl &url, const QString &authcfg, QString &errorTitle, QString &errorText, const QgsHttpHeaders &requestHeaders=QgsHttpHeaders(), QgsFeedback *feedback=nullptr, QString *contentType=nullptr, const QString &urlPrefix=QString(), bool forceRefresh=false)
Performs a blocking request to a URL and returns the retrieved data.
static QVariantMap getServiceInfo(const QString &baseurl, const QString &authcfg, QString &errorTitle, QString &errorText, const QgsHttpHeaders &requestHeaders=QgsHttpHeaders(), const QString &urlPrefix=QString(), bool forceRefresh=false)
Retrieves JSON service info for the specified base URL.
static QVariantMap getLayerInfo(const QString &layerurl, const QString &authcfg, QString &errorTitle, QString &errorText, const QgsHttpHeaders &requestHeaders=QgsHttpHeaders(), const QString &urlPrefix=QString())
Retrieves JSON layer info for the specified layer URL.
static Qgis::ArcGisRestServiceType sniffServiceTypeFromUrl(const QUrl &url)
Attempts to resolve the service type from a url.
static void addLayerItems(const std::function< void(const LayerItemDetails &details)> &visitor, const QVariantMap &serviceData, const QString &parentUrl, const QString &parentSupportedFormats, Qgis::ArcGisRestServiceType serviceType)
Calls the specified visitor function on all layer items found within the given service data.
static void visitServiceItems(const std::function< void(const QString &serviceName, const QString &url, Qgis::ArcGisRestServiceType serviceType)> &visitor, const QVariantMap &serviceData, const QString &baseUrl)
Calls the specified visitor function on all service items found within the given service data.
static QList< quint32 > getObjectIdsByExtent(const QString &layerurl, const QgsRectangle &filterRect, QString &errorTitle, QString &errorText, const QString &authcfg, const QgsHttpHeaders &requestHeaders=QgsHttpHeaders(), QgsFeedback *feedback=nullptr, const QString &whereClause=QString(), const QString &urlPrefix=QString())
Gets a list of object IDs which fall within the specified extent.
static QVariantMap getObjects(const QString &layerurl, const QString &authcfg, const QList< quint32 > &objectIds, const QString &crs, bool fetchGeometry, const QStringList &fetchAttributes, bool fetchM, bool fetchZ, QString &errorTitle, QString &errorText, const QgsHttpHeaders &requestHeaders=QgsHttpHeaders(), QgsFeedback *feedback=nullptr, const QString &urlPrefix=QString())
Retrieves all matching objects from the specified layer URL.
static QgsCoordinateReferenceSystem convertSpatialReference(const QVariantMap &spatialReferenceMap)
Converts a spatial reference JSON definition to a QgsCoordinateReferenceSystem value.
static Qgis::WkbType convertGeometryType(const QString &type)
Converts an ESRI REST geometry type to a WKB type.
static Qgis::ArcGisRestServiceType serviceTypeFromString(const QString &type)
Converts a string value to a REST service type.
static Qgis::ArcGisRestServiceCapabilities serviceCapabilitiesFromString(const QString &capabilities)
Parses a capabilities string to known values.
static QgsRectangle convertRectangle(const QVariant &value)
Converts a rectangle value to a QgsRectangle.
A thread safe class for performing blocking (sync) network requests, with full support for QGIS proxy...
void setAuthCfg(const QString &authCfg)
Sets the authentication config id which should be used during the request.
QString errorMessage() const
Returns the error message string, after a get(), post(), head() or put() request has been made.
ErrorCode get(QNetworkRequest &request, bool forceRefresh=false, QgsFeedback *feedback=nullptr, RequestFlags requestFlags=QgsBlockingNetworkRequest::RequestFlags())
Performs a "get" operation on the specified request.
@ NoError
No error was encountered.
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).
Base class for feedback objects to be used for cancellation of something running in a worker thread.
bool isCanceled() const
Tells whether the operation has been canceled already.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE(), Qgis::StringFormat format=Qgis::StringFormat::PlainText)
Adds a message to the log instance (and creates it if necessary).
static QgsNetworkAccessManager * instance(Qt::ConnectionType connectionType=Qt::BlockingQueuedConnection)
Returns a pointer to the active QgsNetworkAccessManager for the current thread.
Encapsulates a network reply within a container which is inexpensive to copy and safe to pass between...
QByteArray content() const
Returns the reply content.
QByteArray rawHeader(const QByteArray &headerName) const
Returns the content of the header with the specified headerName, or an empty QByteArray if the specif...
A rectangle specified with double values.
static bool isNull(const QVariant &variant, bool silenceNullWarnings=false)
Returns true if the specified variant should be considered a NULL value.
static Qgis::GeometryType geometryType(Qgis::WkbType type)
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
#define QgsDebugMsgLevel(str, level)
#define QgsDebugError(str)
#define QgsSetRequestInitiatorClass(request, _class)
#define QgsSetRequestInitiatorId(request, str)
QLineF segment(int index, QRectF rect, double radius)
Encapsulates details relating to a layer item.
Qgis::ArcGisRestServiceType serviceType
Service type.
bool isMapServerWithQueryCapability
true if layer is a map server with the query capability
QString description
Description.
QString format
Map server image format.
QgsCoordinateReferenceSystem crs
Coordinate reference system.
bool isMapServerSpecialAllLayersOption
true if layer is the special map server "all layers" layer
bool isParentLayer
true if layer item represents a parent layer
QString parentLayerId
Parent layer ID.
Qgis::GeometryType geometryType
Geometry type.