1 /*************************************************************************** 2 qgswmscapabilities.h 3 --------------------- 4 begin : January 2014 5 copyright : (C) 2014 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 #ifndef QGSWMSCAPABILITIES_H 16 #define QGSWMSCAPABILITIES_H 17 18 #include <QHash> 19 #include <QMap> 20 #include <QNetworkRequest> 21 #include <QSet> 22 #include <QStringList> 23 #include <QVector> 24 25 #include "qgsauthmanager.h" 26 #include "qgsraster.h" 27 #include "qgsrectangle.h" 28 #include "qgsrasteriterator.h" 29 #include "qgsapplication.h" 30 #include "qgsdataprovider.h" 31 #include "qgsinterval.h" 32 #include "qgstemporalutils.h" 33 34 class QNetworkReply; 35 36 /* 37 * The following structs reflect the WMS XML schema, 38 * as illustrated in Appendix E of the Web Map Service standard, version 1.3, 2004-08-02. 39 */ 40 41 //! OnlineResource Attribute structure 42 // TODO: Fill to WMS specifications 43 struct QgsWmsOnlineResourceAttribute 44 { 45 QString xlinkHref; 46 }; 47 48 //! Gets Property structure 49 // TODO: Fill to WMS specifications 50 struct QgsWmsGetProperty 51 { 52 QgsWmsOnlineResourceAttribute onlineResource; 53 }; 54 55 //! Post Property structure 56 // TODO: Fill to WMS specifications 57 struct QgsWmsPostProperty 58 { 59 QgsWmsOnlineResourceAttribute onlineResource; 60 }; 61 62 //! HTTP Property structure 63 // TODO: Fill to WMS specifications 64 struct QgsWmsHttpProperty 65 { 66 QgsWmsGetProperty get; 67 QgsWmsPostProperty post; // can be null 68 }; 69 70 //! DCP Type Property structure 71 // TODO: Fill to WMS specifications 72 struct QgsWmsDcpTypeProperty 73 { 74 QgsWmsHttpProperty http; 75 }; 76 77 //! Operation Type structure (for GetMap and GetFeatureInfo) 78 // TODO: Fill to WMS specifications 79 struct QgsWmsOperationType 80 { 81 QStringList format; 82 QVector<QgsWmsDcpTypeProperty> dcpType; 83 QStringList allowedEncodings; 84 }; 85 86 //! Request Property structure 87 // TODO: Fill to WMS specifications 88 struct QgsWmsRequestProperty 89 { 90 // QgsWmsGetCapabilitiesProperty ... 91 // -- don't include since if we can get the capabilities, 92 // we already know what's in this part. 93 QgsWmsOperationType getMap; 94 QgsWmsOperationType getFeatureInfo; 95 QgsWmsOperationType getTile; 96 QgsWmsOperationType getLegendGraphic; 97 }; 98 99 //! Exception Property structure 100 // TODO: Fill to WMS specifications 101 struct QgsWmsExceptionProperty 102 { 103 QStringList format; // text formats supported. 104 }; 105 106 //! Primary Contact Person Property structure 107 struct QgsWmsContactPersonPrimaryProperty 108 { 109 QString contactPerson; 110 QString contactOrganization; 111 }; 112 113 //! Contact Address Property structure 114 struct QgsWmsContactAddressProperty 115 { 116 QString addressType; 117 QString address; 118 QString city; 119 QString stateOrProvince; 120 QString postCode; 121 QString country; 122 }; 123 124 //! Contact Information Property structure 125 struct QgsWmsContactInformationProperty 126 { 127 QgsWmsContactPersonPrimaryProperty contactPersonPrimary; 128 QString contactPosition; 129 QgsWmsContactAddressProperty contactAddress; 130 QString contactVoiceTelephone; 131 QString contactFacsimileTelephone; 132 QString contactElectronicMailAddress; 133 }; 134 135 //! Service Property structure 136 // TODO: Fill to WMS specifications 137 struct QgsWmsServiceProperty 138 { 139 QString title; 140 QString abstract; 141 QStringList keywordList; 142 QgsWmsOnlineResourceAttribute onlineResource; 143 QgsWmsContactInformationProperty contactInformation; 144 QString fees; 145 QString accessConstraints; 146 uint layerLimit = 0; 147 uint maxWidth = 0; 148 uint maxHeight = 0; 149 }; 150 151 //! Bounding Box Property structure 152 // TODO: Fill to WMS specifications 153 struct QgsWmsBoundingBoxProperty 154 { 155 QString crs; 156 QgsRectangle box; // consumes minx, miny, maxx, maxy. 157 }; 158 159 /** 160 * \brief Dimension Property structure. 161 * 162 * Contains the optional dimension element, 163 * the element can be present in Service or Layer metadata 164 */ 165 struct QgsWmsDimensionProperty 166 { 167 //! Name of the dimensional axis eg. time 168 QString name; 169 170 //! Units of the dimensional axis, defined from UCUM. Can be null. 171 QString units; 172 173 //! Optional, unit symbol a 7-bit ASCII character string also defined from UCUM. 174 QString unitSymbol; 175 176 //! Optional, default value to be used in GetMap request 177 QString defaultValue; // plain "default" is a reserved word 178 179 //! Text containing available value(s) for the dimension 180 QString extent; 181 182 //! Optional, determines whether multiple values of the dimension can be requested 183 bool multipleValues = false; 184 185 //! Optional, whether nearest value of the dimension will be returned, if requested. 186 bool nearestValue = false; 187 188 //! Optional, valid only for temporal exents, determines whether data are normally kept current. 189 bool current = false; 190 191 //! Parse the dimension extent to QgsDateTimeRange instance parseExtentQgsWmsDimensionProperty192 QgsDateTimeRange parseExtent() const 193 { 194 if ( extent.contains( '/' ) ) 195 { 196 QStringList extentContent = extent.split( '/' ); 197 int extentSize = extentContent.size(); 198 199 QDateTime start = QDateTime::fromString( extentContent.at( 0 ), Qt::ISODateWithMs ); 200 QDateTime end = QDateTime::fromString( extentContent.at( extentSize - 2 ), Qt::ISODateWithMs ); 201 202 if ( start.isValid() & end.isValid() ) 203 return QgsDateTimeRange( start, end ); 204 } 205 206 return QgsDateTimeRange(); 207 } 208 209 bool operator== ( const QgsWmsDimensionProperty &other ) const 210 { 211 return name == other.name && units == other.units && 212 unitSymbol == other.unitSymbol && defaultValue == other.defaultValue && 213 extent == other.extent && multipleValues == other.multipleValues && 214 nearestValue == other.nearestValue && current == other.current; 215 } 216 217 }; 218 219 //! Logo URL Property structure 220 // TODO: Fill to WMS specifications 221 struct QgsWmsLogoUrlProperty 222 { 223 QString format; 224 QgsWmsOnlineResourceAttribute onlineResource; 225 226 int width; 227 int height; 228 }; 229 230 //! Attribution Property structure 231 // TODO: Fill to WMS specifications 232 struct QgsWmsAttributionProperty 233 { 234 QString title; 235 QgsWmsOnlineResourceAttribute onlineResource; 236 QgsWmsLogoUrlProperty logoUrl; 237 }; 238 239 //! Legend URL Property structure 240 // TODO: Fill to WMS specifications 241 struct QgsWmsLegendUrlProperty 242 { 243 QString format; 244 QgsWmsOnlineResourceAttribute onlineResource; 245 246 int width; 247 int height; 248 }; 249 250 //! StyleSheet URL Property structure 251 // TODO: Fill to WMS specifications 252 struct QgsWmsStyleSheetUrlProperty 253 { 254 QString format; 255 QgsWmsOnlineResourceAttribute onlineResource; 256 }; 257 258 //! Style URL Property structure 259 // TODO: Fill to WMS specifications 260 struct QgsWmsStyleUrlProperty 261 { 262 QString format; 263 QgsWmsOnlineResourceAttribute onlineResource; 264 }; 265 266 //! Style Property structure 267 // TODO: Fill to WMS specifications 268 struct QgsWmsStyleProperty 269 { 270 QString name; 271 QString title; 272 QString abstract; 273 QVector<QgsWmsLegendUrlProperty> legendUrl; 274 QgsWmsStyleSheetUrlProperty styleSheetUrl; 275 QgsWmsStyleUrlProperty styleUrl; 276 }; 277 278 //! Authority URL Property structure 279 // TODO: Fill to WMS specifications 280 struct QgsWmsAuthorityUrlProperty 281 { 282 QgsWmsOnlineResourceAttribute onlineResource; 283 QString name; // XML "NMTOKEN" type 284 }; 285 286 //! Identifier Property structure 287 // TODO: Fill to WMS specifications 288 struct QgsWmsIdentifierProperty 289 { 290 QString authority; 291 }; 292 293 //! Metadata URL Property structure 294 // TODO: Fill to WMS specifications 295 struct QgsWmsMetadataUrlProperty 296 { 297 QString format; 298 QgsWmsOnlineResourceAttribute onlineResource; 299 QString type; // XML "NMTOKEN" type 300 }; 301 302 //! Data List URL Property structure 303 // TODO: Fill to WMS specifications 304 struct QgsWmsDataListUrlProperty 305 { 306 QString format; 307 QgsWmsOnlineResourceAttribute onlineResource; 308 }; 309 310 //! Feature List URL Property structure 311 // TODO: Fill to WMS specifications 312 struct QgsWmsFeatureListUrlProperty 313 { 314 QString format; 315 QgsWmsOnlineResourceAttribute onlineResource; 316 }; 317 318 //! Layer Property structure 319 // TODO: Fill to WMS specifications 320 struct QgsWmsLayerProperty 321 { 322 // WMS layer properties 323 int orderId; 324 QString name; 325 QString title; 326 QString abstract; 327 QStringList keywordList; 328 QStringList crs; // coord ref sys 329 QgsRectangle ex_GeographicBoundingBox; 330 QVector<QgsWmsBoundingBoxProperty> boundingBoxes; 331 QgsWmsAttributionProperty attribution; 332 QVector<QgsWmsAuthorityUrlProperty> authorityUrl; 333 QVector<QgsWmsIdentifierProperty> identifier; 334 QVector<QgsWmsDimensionProperty> dimensions; 335 QVector<QgsWmsMetadataUrlProperty> metadataUrl; 336 QVector<QgsWmsDataListUrlProperty> dataListUrl; 337 QVector<QgsWmsFeatureListUrlProperty> featureListUrl; 338 QVector<QgsWmsStyleProperty> style; 339 double minimumScaleDenominator; 340 double maximumScaleDenominator; 341 QVector<QgsWmsLayerProperty> layer; // nested layers 342 343 // WMS layer attributes 344 bool queryable; 345 int cascaded; 346 bool opaque; 347 bool noSubsets; 348 int fixedWidth; 349 int fixedHeight; 350 351 // TODO need to expand this to cover more of layer properties equalQgsWmsLayerProperty352 bool equal( const QgsWmsLayerProperty &layerProperty ) 353 { 354 if ( !( name == layerProperty.name ) ) 355 return false; 356 if ( !( title == layerProperty.title ) ) 357 return false; 358 if ( !( abstract == layerProperty.abstract ) ) 359 return false; 360 if ( !( dimensions == layerProperty.dimensions ) ) 361 return false; 362 363 return true; 364 } 365 366 /** 367 * Returns true if it the struct has the dimension with the passed name 368 */ hasDimensionQgsWmsLayerProperty369 bool hasDimension( QString dimensionName ) const 370 { 371 if ( dimensions.isEmpty() ) 372 return false; 373 374 for ( const QgsWmsDimensionProperty &dimension : std::as_const( dimensions ) ) 375 { 376 if ( dimension.name == dimensionName ) 377 return true; 378 } 379 380 return false; 381 } 382 383 /** 384 * Attempts to return a preferred CRS from the list of available CRS definitions. 385 * 386 * Prioritizes the first listed CRS, unless it's a block listed value. 387 */ preferredAvailableCrsQgsWmsLayerProperty388 QString preferredAvailableCrs() const 389 { 390 static QSet< QString > sSkipList { QStringLiteral( "EPSG:900913" ) }; 391 for ( const QString &candidate : crs ) 392 { 393 if ( sSkipList.contains( candidate ) ) 394 continue; 395 396 return candidate; 397 } 398 return crs.value( 0 ); 399 } 400 }; 401 402 /** 403 * Stores the dates parts from the WMS-T dimension extent. 404 * 405 */ 406 struct QgsWmstDates 407 { QgsWmstDatesQgsWmstDates408 QgsWmstDates( QList< QDateTime > dates ) 409 { 410 dateTimes = dates; 411 } QgsWmstDatesQgsWmstDates412 QgsWmstDates() 413 { 414 415 } 416 417 bool operator== ( const QgsWmstDates &other ) 418 { 419 return dateTimes == other.dateTimes; 420 } 421 422 QList< QDateTime > dateTimes; 423 }; 424 425 /** 426 * Stores dates and resolution structure pair. 427 */ 428 struct QgsWmstExtentPair 429 { QgsWmstExtentPairQgsWmstExtentPair430 QgsWmstExtentPair() 431 { 432 } 433 QgsWmstExtentPairQgsWmstExtentPair434 QgsWmstExtentPair( QgsWmstDates dates, QgsTimeDuration resolution ) 435 : dates( dates ) 436 , resolution( resolution ) 437 { 438 } 439 440 bool operator ==( const QgsWmstExtentPair &other ) 441 { 442 return dates == other.dates && 443 resolution == other.resolution; 444 } 445 446 QgsWmstDates dates; 447 QgsTimeDuration resolution; 448 449 }; 450 451 452 /** 453 * Stores the WMS-T dimension extent. 454 */ 455 struct QgsWmstDimensionExtent 456 { 457 QList <QgsWmstExtentPair> datesResolutionList; 458 }; 459 460 struct QgsWmtsTheme 461 { 462 QString identifier; 463 QString title, abstract; 464 QStringList keywords; 465 QgsWmtsTheme *subTheme = nullptr; 466 QStringList layerRefs; 467 468 QgsWmtsTheme() = default; ~QgsWmtsThemeQgsWmtsTheme469 ~QgsWmtsTheme() { delete subTheme; } 470 }; 471 472 struct QgsWmtsTileMatrixLimits; 473 474 struct QgsWmtsTileMatrix 475 { 476 QString identifier; 477 QString title, abstract; 478 QStringList keywords; 479 double scaleDenom = 0; 480 QgsPointXY topLeft; //!< Top-left corner of the tile matrix in map units 481 int tileWidth; //!< Width of a tile in pixels 482 int tileHeight; //!< Height of a tile in pixels 483 int matrixWidth; //!< Number of tiles horizontally 484 int matrixHeight; //!< Number of tiles vertically 485 double tres; //!< Pixel span in map units 486 487 /** 488 * Returns extent of a tile in map coordinates. 489 * (same function as tileBBox() but returns QRectF instead of QgsRectangle) 490 */ 491 QRectF tileRect( int col, int row ) const; 492 493 /** 494 * Returns extent of a tile in map coordinates 495 * (same function as tileRect() but returns QgsRectangle instead of QRectF) 496 */ 497 QgsRectangle tileBBox( int col, int row ) const; 498 499 /** 500 * Returns range of tiles that intersects with the view extent 501 * (\a tml may be NULLPTR) 502 */ 503 void viewExtentIntersection( const QgsRectangle &viewExtent, const QgsWmtsTileMatrixLimits *tml, int &col0, int &row0, int &col1, int &row1 ) const; 504 505 }; 506 507 struct QgsWmtsTileMatrixSet 508 { 509 QString identifier; //!< Tile matrix set identifier 510 QString title; //!< Human readable tile matrix set name 511 QString abstract; //!< Brief description of the tile matrix set 512 QStringList keywords; //!< List of words/phrases to describe the dataset 513 QString crs; //!< CRS of the tile matrix set 514 QString wkScaleSet; //!< Optional reference to a well-known scale set 515 //! available tile matrixes (key = pixel span in map units) 516 QMap<double, QgsWmtsTileMatrix> tileMatrices; 517 518 //! Returns closest tile resolution to the requested one. (resolution = width [map units] / with [pixels]) 519 const QgsWmtsTileMatrix *findNearestResolution( double vres ) const; 520 521 //! Returns the tile matrix for other near resolution from given tres (positive offset = lower resolution tiles) 522 const QgsWmtsTileMatrix *findOtherResolution( double tres, int offset ) const; 523 }; 524 525 enum QgsTileMode { WMTS, WMSC, XYZ }; 526 527 struct QgsWmtsTileMatrixLimits 528 { 529 QString tileMatrix; 530 int minTileRow, maxTileRow; 531 int minTileCol, maxTileCol; 532 }; 533 534 struct QgsWmtsTileMatrixSetLink 535 { 536 QString tileMatrixSet; 537 QHash<QString, QgsWmtsTileMatrixLimits> limits; 538 }; 539 540 struct QgsWmtsLegendURL 541 { 542 QString format; 543 double minScale, maxScale; 544 QString href; 545 int width, height; 546 }; 547 548 struct QgsWmtsStyle 549 { 550 QString identifier; 551 QString title, abstract; 552 QStringList keywords; 553 bool isDefault = false; 554 QList<QgsWmtsLegendURL> legendURLs; 555 }; 556 557 /** 558 * In case of multi-dimensional data, the service metadata can describe their multi- 559 * dimensionality and tiles can be requested at specific values in these dimensions. 560 * Examples of dimensions are Time, Elevation and Band. 561 */ 562 struct QgsWmtsDimension 563 { 564 QString identifier; //!< Name of the dimensional axis 565 QString title; //!< Human readable name 566 QString abstract; //!< Brief description of the dimension 567 QStringList keywords; //!< List of words/phrases to describe the dataset 568 QString UOM; //!< Units of measure of dimensional axis 569 QString unitSymbol; //!< Symbol of the units 570 QString defaultValue; //!< Default value to be used if value is not specified in request 571 bool current; //!< Indicates whether temporal data are normally kept current 572 QStringList values; //!< Available values for this dimension 573 }; 574 575 struct QgsWmtsTileLayer 576 { 577 enum QgsTileMode tileMode; 578 QString identifier; 579 QString title, abstract; 580 QStringList keywords; 581 QVector<QgsWmsBoundingBoxProperty> boundingBoxes; 582 QStringList formats; 583 QStringList infoFormats; 584 QString defaultStyle; 585 int dpi = -1; //!< DPI of the tile layer (-1 for unknown DPI) 586 //! available dimensions (optional, for multi-dimensional data) 587 QHash<QString, QgsWmtsDimension> dimensions; 588 QHash<QString, QgsWmtsStyle> styles; 589 QHash<QString, QgsWmtsTileMatrixSetLink> setLinks; 590 591 QHash<QString, QString> getTileURLs; 592 QHash<QString, QString> getFeatureInfoURLs; 593 }; 594 595 //! Capability Property structure 596 // TODO: Fill to WMS specifications 597 struct QgsWmsCapabilityProperty 598 { 599 QgsWmsRequestProperty request; 600 QgsWmsExceptionProperty exception; 601 602 // Top level layer should normally be present max once 603 // <element name="Capability"> 604 // <element ref="wms:Layer" minOccurs="0"/> - default maxOccurs=1 605 // but there are a few non conformant capabilities around (#13762) 606 QList<QgsWmsLayerProperty> layers; 607 608 QList<QgsWmtsTileLayer> tileLayers; 609 QHash<QString, QgsWmtsTileMatrixSet> tileMatrixSets; 610 }; 611 612 //! Capabilities Property structure 613 // TODO: Fill to WMS specifications 614 struct QgsWmsCapabilitiesProperty 615 { 616 QgsWmsServiceProperty service; 617 QgsWmsCapabilityProperty capability; 618 QString version; 619 }; 620 621 //! Formats supported by QImageReader 622 struct QgsWmsSupportedFormat 623 { 624 QString format; 625 QString label; 626 }; 627 628 enum QgsWmsTileAttribute 629 { 630 TileReqNo = QNetworkRequest::User + 0, 631 TileIndex = QNetworkRequest::User + 1, 632 TileRect = QNetworkRequest::User + 2, 633 TileRetry = QNetworkRequest::User + 3, 634 }; 635 636 enum QgsWmsDpiMode 637 { 638 DpiNone = 0, 639 DpiQGIS = 1, 640 DpiUMN = 2, 641 DpiGeoServer = 4, 642 DpiAll = DpiQGIS | DpiUMN | DpiGeoServer, 643 }; 644 645 646 647 struct QgsWmsParserSettings 648 { 649 QgsWmsParserSettings( bool ignAxis = false, bool invAxis = false ) ignoreAxisOrientationQgsWmsParserSettings650 : ignoreAxisOrientation( ignAxis ) 651 , invertAxisOrientation( invAxis ) 652 {} 653 bool ignoreAxisOrientation; 654 bool invertAxisOrientation; 655 }; 656 657 struct QgsWmsAuthorization 658 { 659 QgsWmsAuthorization( const QString &userName = QString(), const QString &password = QString(), const QString &referer = QString(), const QString &authcfg = QString() ) mUserNameQgsWmsAuthorization660 : mUserName( userName ) 661 , mPassword( password ) 662 , mReferer( referer ) 663 , mAuthCfg( authcfg ) 664 {} 665 setAuthorizationQgsWmsAuthorization666 bool setAuthorization( QNetworkRequest &request ) const 667 { 668 if ( !mAuthCfg.isEmpty() ) 669 { 670 return QgsApplication::authManager()->updateNetworkRequest( request, mAuthCfg ); 671 } 672 else if ( !mUserName.isEmpty() || !mPassword.isEmpty() ) 673 { 674 request.setRawHeader( "Authorization", "Basic " + QStringLiteral( "%1:%2" ).arg( mUserName, mPassword ).toUtf8().toBase64() ); 675 } 676 677 if ( !mReferer.isEmpty() ) 678 { 679 request.setRawHeader( "Referer", mReferer.toLatin1() ); 680 } 681 return true; 682 } 683 //! Sets authorization reply setAuthorizationReplyQgsWmsAuthorization684 bool setAuthorizationReply( QNetworkReply *reply ) const 685 { 686 if ( !mAuthCfg.isEmpty() ) 687 { 688 return QgsApplication::authManager()->updateNetworkReply( reply, mAuthCfg ); 689 } 690 return true; 691 } 692 693 //! Username for basic http authentication 694 QString mUserName; 695 696 //! Password for basic http authentication 697 QString mPassword; 698 699 //! Referer for http requests 700 QString mReferer; 701 702 //! Authentication configuration ID 703 QString mAuthCfg; 704 }; 705 706 707 //! URI that gets passed to provider 708 class QgsWmsSettings 709 { 710 public: 711 712 bool parseUri( const QString &uriString ); 713 baseUrl()714 QString baseUrl() const { return mBaseUrl; } authorization()715 QgsWmsAuthorization authorization() const { return mAuth; } 716 parserSettings()717 QgsWmsParserSettings parserSettings() const { return mParserSettings; } 718 719 /** 720 * Parse the given string extent into a well defined dates and resolution structures. 721 * The string extent comes from WMS-T dimension capabilities. 722 * 723 * \since QGIS 3.14 724 */ 725 QgsWmstDimensionExtent parseTemporalExtent( const QString &extent ); 726 727 /** 728 * Sets the dimension extent property 729 * 730 * \see timeDimensionExtent() 731 * \since QGIS 3.14 732 */ 733 void setTimeDimensionExtent( const QgsWmstDimensionExtent &timeDimensionExtent ); 734 735 /** 736 * Returns the dimension extent property. 737 * 738 * \see setTimeDimensionExtent() 739 * \since QGIS 3.14 740 */ 741 QgsWmstDimensionExtent timeDimensionExtent() const; 742 743 /** 744 * Parse the given string item into a resolution structure. 745 * 746 * \since QGIS 3.14 747 */ 748 QgsTimeDuration parseWmstResolution( const QString &item ); 749 750 /** 751 * Parse the given string item into QDateTime instant. 752 * 753 * \since QGIS 3.14 754 */ 755 QDateTime parseWmstDateTimes( const QString &item ); 756 757 /** 758 * Finds the least closest datetime from list of available dimension temporal ranges 759 * with the given \a dateTime. 760 * 761 * \note It works with wms-t capabilities that provide time dimension with temporal ranges only. 762 * 763 * \since QGIS 3.14 764 */ 765 QDateTime findLeastClosestDateTime( const QDateTime &dateTime, bool dateOnly = false ) const; 766 767 protected: 768 QgsWmsParserSettings mParserSettings; 769 770 //! layer is tiled, tile layer and active matrix set 771 bool mTiled; 772 //! whether we actually work with XYZ tiles instead of WMS / WMTS 773 bool mXyz; 774 775 //! Whether we are dealing with WMS-T 776 bool mIsTemporal = false; 777 778 //! Whether we are dealing bi-temporal dimensional WMS-T 779 bool mIsBiTemporal = false; 780 781 //! Temporal extent from dimension property in WMS-T 782 QString mTemporalExtent; 783 784 //! Fixed temporal range for the data provider 785 QgsDateTimeRange mFixedRange; 786 787 //! All available temporal ranges 788 QList< QgsDateTimeRange > mAllRanges; 789 790 QgsInterval mDefaultInterval; 791 792 //! Fixed reference temporal range for the data provider 793 QgsDateTimeRange mFixedReferenceRange; 794 795 //! Stores WMS-T time dimension extent dates 796 QgsWmstDimensionExtent mTimeDimensionExtent; 797 798 //! Stores WMS-T reference dimension extent dates 799 QgsWmstDimensionExtent mReferenceTimeDimensionExtent; 800 801 //! whether we are dealing with MBTiles file rather than using network-based tiles 802 bool mIsMBTiles = false; 803 //! chosen values for dimensions in case of multi-dimensional data (key=dim id, value=dim value) 804 QHash<QString, QString> mTileDimensionValues; 805 //! name of the chosen tile matrix set 806 QString mTileMatrixSetId; 807 808 /** 809 * Maximum width and height of getmap requests 810 */ 811 int mMaxWidth; 812 int mMaxHeight; 813 814 /** 815 * Step size when iterating the layer 816 */ 817 int mStepWidth = QgsRasterIterator::DEFAULT_MAXIMUM_TILE_WIDTH; 818 int mStepHeight = QgsRasterIterator::DEFAULT_MAXIMUM_TILE_HEIGHT; 819 820 //! Data source URI of the WMS for this layer 821 QString mHttpUri; 822 823 //! URL part of URI (httpuri) 824 QString mBaseUrl; 825 826 QgsWmsAuthorization mAuth; 827 828 bool mIgnoreGetMapUrl; 829 bool mIgnoreGetFeatureInfoUrl; 830 bool mIgnoreReportedLayerExtents = false; 831 bool mSmoothPixmapTransform; 832 enum QgsWmsDpiMode mDpiMode; 833 834 /** 835 * Active sublayers managed by this provider in a draw function, in order from bottom to top 836 * (some may not be visible in a draw function, cf. activeSubLayerVisibility) 837 */ 838 QStringList mActiveSubLayers; 839 QStringList mActiveSubStyles; 840 841 //! Opacities for wms layers. Same ordering as mActiveSubLayers/mActiveSubStyles 842 QStringList mOpacities; 843 844 /** 845 * Visibility status of the given active sublayer 846 */ 847 QMap<QString, bool> mActiveSubLayerVisibility; 848 849 //! FEATURE_COUNT for GetFeatureInfo 850 int mFeatureCount; 851 852 /** 853 * MIME type of the image encoding used from the WMS server 854 */ 855 QString mImageMimeType; 856 857 QString mCrsId; 858 859 bool mEnableContextualLegend; 860 861 friend class QgsWmsProvider; 862 }; 863 864 865 //! Keeps information about capabilities of particular URI 866 class QgsWmsCapabilities 867 { 868 public: 869 870 /** 871 * Constructs a QgsWmsCapabilities object with the given \a coordinateTransformContext 872 */ 873 QgsWmsCapabilities( const QgsCoordinateTransformContext &coordinateTransformContext = QgsCoordinateTransformContext(), const QString &baseUrl = QString() ); 874 isValid()875 bool isValid() const { return mValid; } 876 877 bool parseResponse( const QByteArray &response, QgsWmsParserSettings settings ); 878 lastError()879 QString lastError() const { return mError; } lastErrorFormat()880 QString lastErrorFormat() const { return mErrorFormat; } 881 capabilitiesProperty()882 QgsWmsCapabilitiesProperty capabilitiesProperty() { return mCapabilities; } 883 884 /** 885 * \brief Returns a list of the supported layers of the WMS server 886 * 887 * \returns The list of layers will be placed here. 888 * 889 * \todo Document this better 890 */ supportedLayers()891 QVector<QgsWmsLayerProperty> supportedLayers() const { return mLayersSupported; } 892 893 //! Gets raster image encodings supported by the WMS, expressed as MIME types supportedImageEncodings()894 QStringList supportedImageEncodings() const { return mCapabilities.capability.request.getMap.format; } 895 896 /** 897 * \brief Returns a map for the hierarchy of layers 898 */ layerParents(QMap<int,int> & parents,QMap<int,QStringList> & parentNames)899 void layerParents( QMap<int, int> &parents, QMap<int, QStringList> &parentNames ) const { parents = mLayerParents; parentNames = mLayerParentNames; } 900 901 /** 902 * \brief Returns a list of the supported tile layers of the WMS server 903 * 904 * \returns The list of tile sets will be placed here. 905 */ supportedTileLayers()906 QList<QgsWmtsTileLayer> supportedTileLayers() const { return mTileLayersSupported; } 907 908 /** 909 * \brief Returns a list of the available tile matrix sets 910 */ supportedTileMatrixSets()911 QHash<QString, QgsWmtsTileMatrixSet> supportedTileMatrixSets() const { return mTileMatrixSets; } 912 913 //! Find out whether to invert axis orientation when parsing/writing coordinates 914 bool shouldInvertAxisOrientation( const QString &ogcCrs ); 915 916 //! Find out identify capabilities 917 int identifyCapabilities() const; 918 919 protected: 920 bool parseCapabilitiesDom( const QByteArray &xml, QgsWmsCapabilitiesProperty &capabilitiesProperty ); 921 922 void parseService( const QDomElement &element, QgsWmsServiceProperty &serviceProperty ); 923 void parseOnlineResource( const QDomElement &element, QgsWmsOnlineResourceAttribute &onlineResourceAttribute ); 924 void parseKeywordList( const QDomElement &element, QStringList &keywordListProperty ); 925 void parseContactInformation( const QDomElement &element, QgsWmsContactInformationProperty &contactInformationProperty ); 926 void parseContactPersonPrimary( const QDomElement &element, QgsWmsContactPersonPrimaryProperty &contactPersonPrimaryProperty ); 927 void parseContactAddress( const QDomElement &element, QgsWmsContactAddressProperty &contactAddressProperty ); 928 929 void parseCapability( const QDomElement &element, QgsWmsCapabilityProperty &capabilityProperty ); 930 void parseRequest( const QDomElement &element, QgsWmsRequestProperty &requestProperty ); 931 void parseDimension( const QDomElement &element, QgsWmsDimensionProperty &dimensionProperty ); 932 void parseExtent( const QDomElement &element, QVector<QgsWmsDimensionProperty> &dimensionProperties ); 933 void parseLegendUrl( const QDomElement &element, QgsWmsLegendUrlProperty &legendUrlProperty ); 934 void parseMetadataUrl( const QDomElement &element, QgsWmsMetadataUrlProperty &metadataUrlProperty ); 935 void parseLayer( const QDomElement &element, QgsWmsLayerProperty &layerProperty, QgsWmsLayerProperty *parentProperty = nullptr ); 936 void parseStyle( const QDomElement &element, QgsWmsStyleProperty &styleProperty ); 937 938 void parseOperationType( const QDomElement &element, QgsWmsOperationType &operationType ); 939 void parseDcpType( const QDomElement &element, QgsWmsDcpTypeProperty &dcpType ); 940 void parseHttp( const QDomElement &element, QgsWmsHttpProperty &httpProperty ); 941 void parseGet( const QDomElement &element, QgsWmsGetProperty &getProperty ); 942 void parsePost( const QDomElement &element, QgsWmsPostProperty &postProperty ); 943 944 void parseTileSetProfile( const QDomElement &element ); 945 void parseWMTSContents( const QDomElement &element ); 946 void parseKeywords( const QDomNode &e, QStringList &keywords ); 947 void parseTheme( const QDomElement &e, QgsWmtsTheme &t ); 948 949 QString nodeAttribute( const QDomElement &element, const QString &name, const QString &defValue = QString() ); 950 951 /** 952 * In case no bounding box is present in WMTS capabilities, try to estimate it from tile matrix sets. 953 * Returns true if the detection went fine. 954 */ 955 bool detectTileLayerBoundingBox( QgsWmtsTileLayer &l ); 956 957 protected: 958 bool mValid = false; 959 960 QString mError; 961 QString mErrorCaption; 962 QString mErrorFormat; 963 964 QgsWmsParserSettings mParserSettings; 965 966 //! number of layers and parents 967 int mLayerCount = -1; 968 QMap<int, int> mLayerParents; 969 QMap<int, QStringList> mLayerParentNames; 970 971 /** 972 * WMS "queryable" per layer 973 * Used in determining if the Identify map tool can be useful on the rendered WMS map layer. 974 */ 975 QMap<QString, bool> mQueryableForLayer; 976 977 /** 978 * layers hosted by the WMS 979 */ 980 QVector<QgsWmsLayerProperty> mLayersSupported; 981 982 /** 983 * tilesets hosted by the WMTS 984 */ 985 QList<QgsWmtsTileLayer> mTileLayersSupported; 986 987 /** 988 * themes hosted by the WMTS 989 */ 990 QList<QgsWmtsTheme> mTileThemes; 991 992 /** 993 * Parsed capabilities of the WMS 994 */ 995 QgsWmsCapabilitiesProperty mCapabilities; 996 997 //! Formats supported by server and provider 998 QMap<QgsRaster::IdentifyFormat, QString> mIdentifyFormats; 999 1000 1001 /** 1002 * tile matrix sets hosted by the WMS 1003 */ 1004 QHash<QString, QgsWmtsTileMatrixSet> mTileMatrixSets; 1005 1006 //temporarily caches invert axis setting for each crs 1007 QHash<QString, bool> mCrsInvertAxis; 1008 1009 private: 1010 1011 QgsCoordinateTransformContext mCoordinateTransformContext; 1012 QString mBaseUrl; 1013 1014 friend class QgsWmsProvider; 1015 friend class TestQgsWmsCapabilities; 1016 }; 1017 1018 1019 1020 /** 1021 * Class that handles download of capabilities. 1022 */ 1023 class QgsWmsCapabilitiesDownload : public QObject 1024 { 1025 Q_OBJECT 1026 1027 public: 1028 explicit QgsWmsCapabilitiesDownload( bool forceRefresh, QObject *parent = nullptr ); 1029 1030 QgsWmsCapabilitiesDownload( const QString &baseUrl, const QgsWmsAuthorization &auth, bool forceRefresh, QObject *parent = nullptr ); 1031 1032 ~QgsWmsCapabilitiesDownload() override; 1033 1034 bool downloadCapabilities(); 1035 1036 bool downloadCapabilities( const QString &baseUrl, const QgsWmsAuthorization &auth ); 1037 1038 /** 1039 * Returns the download refresh state. 1040 * \see setForceRefresh() 1041 * 1042 * \since QGIS 3.22 1043 */ 1044 bool forceRefresh(); 1045 1046 /** 1047 * Sets the download refresh state. 1048 * \see forceRefresh() 1049 * 1050 * \since QGIS 3.22 1051 */ 1052 void setForceRefresh( bool forceRefresh ); 1053 lastError()1054 QString lastError() const { return mError; } 1055 response()1056 QByteArray response() const { return mHttpCapabilitiesResponse; } 1057 1058 //! Abort network request immediately 1059 void abort(); 1060 1061 signals: 1062 //! \brief emit a signal to be caught by qgisapp and display a msg on status bar 1063 void statusChanged( QString const &statusQString ); 1064 1065 //! \brief emit a signal once the download is finished 1066 void downloadFinished(); 1067 1068 protected slots: 1069 void capabilitiesReplyFinished(); 1070 void capabilitiesReplyProgress( qint64, qint64 ); 1071 1072 protected: 1073 //! URL part of URI (httpuri) 1074 QString mBaseUrl; 1075 1076 QgsWmsAuthorization mAuth; 1077 1078 //! The reply to the capabilities request 1079 QNetworkReply *mCapabilitiesReply = nullptr; 1080 1081 //! The error message associated with the last WMS error. 1082 QString mError; 1083 1084 //! The mime type of the message 1085 QString mErrorFormat; 1086 1087 //! Capabilities of the WMS (raw) 1088 QByteArray mHttpCapabilitiesResponse; 1089 1090 bool mIsAborted; 1091 bool mForceRefresh; 1092 }; 1093 1094 1095 1096 #endif // QGSWMSCAPABILITIES_H 1097