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 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 : qgis::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 resolution part of the WMS-T dimension extent. 427 * 428 * If resolution does not exist, active() will return false; 429 */ 430 struct QgsWmstResolution 431 { 432 int year = -1; 433 int month = -1; 434 int day = -1; 435 436 int hour = -1; 437 int minutes = -1; 438 int seconds = -1; 439 intervalQgsWmstResolution440 long long interval() const 441 { 442 long long secs = 0.0; 443 444 if ( year != -1 ) 445 secs += year * QgsInterval::YEARS ; 446 if ( month != -1 ) 447 secs += month * QgsInterval::MONTHS; 448 if ( day != -1 ) 449 secs += day * QgsInterval::DAY; 450 if ( hour != -1 ) 451 secs += hour * QgsInterval::HOUR; 452 if ( minutes != -1 ) 453 secs += minutes * QgsInterval::MINUTE; 454 if ( seconds != -1 ) 455 secs += seconds; 456 457 return secs; 458 } 459 activeQgsWmstResolution460 bool active() const 461 { 462 return year != -1 || month != -1 || day != -1 || 463 hour != -1 || minutes != -1 || seconds != -1; 464 } 465 textQgsWmstResolution466 QString text() const 467 { 468 QString text( "P" ); 469 470 if ( year != -1 ) 471 { 472 text.append( QString::number( year ) ); 473 text.append( 'Y' ); 474 } 475 if ( month != -1 ) 476 { 477 text.append( QString::number( month ) ); 478 text.append( 'M' ); 479 } 480 if ( day != -1 ) 481 { 482 text.append( QString::number( day ) ); 483 text.append( 'D' ); 484 } 485 486 if ( hour != -1 ) 487 { 488 if ( !text.contains( 'T' ) ) 489 text.append( 'T' ); 490 text.append( QString::number( hour ) ); 491 text.append( 'H' ); 492 } 493 if ( minutes != -1 ) 494 { 495 if ( !text.contains( 'T' ) ) 496 text.append( 'T' ); 497 text.append( QString::number( minutes ) ); 498 text.append( 'M' ); 499 } 500 if ( seconds != -1 ) 501 { 502 if ( !text.contains( 'T' ) ) 503 text.append( 'T' ); 504 text.append( QString::number( seconds ) ); 505 text.append( 'S' ); 506 } 507 return text; 508 } 509 510 bool operator==( const QgsWmstResolution &other ) const 511 { 512 return year == other.year && month == other.month && 513 day == other.day && hour == other.hour && 514 minutes == other.minutes && seconds == other.seconds; 515 } 516 517 }; 518 519 520 /** 521 * Stores dates and resolution structure pair. 522 */ 523 struct QgsWmstExtentPair 524 { QgsWmstExtentPairQgsWmstExtentPair525 QgsWmstExtentPair() 526 { 527 } 528 QgsWmstExtentPairQgsWmstExtentPair529 QgsWmstExtentPair( QgsWmstDates otherDates, QgsWmstResolution otherResolution ) 530 { 531 dates = otherDates; 532 resolution = otherResolution; 533 } 534 535 bool operator ==( const QgsWmstExtentPair &other ) 536 { 537 return dates == other.dates && 538 resolution == other.resolution; 539 } 540 541 QgsWmstDates dates; 542 QgsWmstResolution resolution; 543 }; 544 545 546 /** 547 * Stores the WMS-T dimension extent. 548 */ 549 struct QgsWmstDimensionExtent 550 { 551 QList <QgsWmstExtentPair> datesResolutionList; 552 }; 553 554 struct QgsWmtsTheme 555 { 556 QString identifier; 557 QString title, abstract; 558 QStringList keywords; 559 QgsWmtsTheme *subTheme = nullptr; 560 QStringList layerRefs; 561 562 QgsWmtsTheme() = default; ~QgsWmtsThemeQgsWmtsTheme563 ~QgsWmtsTheme() { delete subTheme; } 564 }; 565 566 struct QgsWmtsTileMatrixLimits; 567 568 struct QgsWmtsTileMatrix 569 { 570 QString identifier; 571 QString title, abstract; 572 QStringList keywords; 573 double scaleDenom; 574 QgsPointXY topLeft; //!< Top-left corner of the tile matrix in map units 575 int tileWidth; //!< Width of a tile in pixels 576 int tileHeight; //!< Height of a tile in pixels 577 int matrixWidth; //!< Number of tiles horizontally 578 int matrixHeight; //!< Number of tiles vertically 579 double tres; //!< Pixel span in map units 580 581 /** 582 * Returns extent of a tile in map coordinates. 583 * (same function as tileBBox() but returns QRectF instead of QgsRectangle) 584 */ 585 QRectF tileRect( int col, int row ) const; 586 587 /** 588 * Returns extent of a tile in map coordinates 589 * (same function as tileRect() but returns QgsRectangle instead of QRectF) 590 */ 591 QgsRectangle tileBBox( int col, int row ) const; 592 593 /** 594 * Returns range of tiles that intersects with the view extent 595 * (\a tml may be NULLPTR) 596 */ 597 void viewExtentIntersection( const QgsRectangle &viewExtent, const QgsWmtsTileMatrixLimits *tml, int &col0, int &row0, int &col1, int &row1 ) const; 598 599 }; 600 601 struct QgsWmtsTileMatrixSet 602 { 603 QString identifier; //!< Tile matrix set identifier 604 QString title; //!< Human readable tile matrix set name 605 QString abstract; //!< Brief description of the tile matrix set 606 QStringList keywords; //!< List of words/phrases to describe the dataset 607 QString crs; //!< CRS of the tile matrix set 608 QString wkScaleSet; //!< Optional reference to a well-known scale set 609 //! available tile matrixes (key = pixel span in map units) 610 QMap<double, QgsWmtsTileMatrix> tileMatrices; 611 612 //! Returns closest tile resolution to the requested one. (resolution = width [map units] / with [pixels]) 613 const QgsWmtsTileMatrix *findNearestResolution( double vres ) const; 614 615 //! Returns the tile matrix for other near resolution from given tres (positive offset = lower resolution tiles) 616 const QgsWmtsTileMatrix *findOtherResolution( double tres, int offset ) const; 617 }; 618 619 enum QgsTileMode { WMTS, WMSC, XYZ }; 620 621 struct QgsWmtsTileMatrixLimits 622 { 623 QString tileMatrix; 624 int minTileRow, maxTileRow; 625 int minTileCol, maxTileCol; 626 }; 627 628 struct QgsWmtsTileMatrixSetLink 629 { 630 QString tileMatrixSet; 631 QHash<QString, QgsWmtsTileMatrixLimits> limits; 632 }; 633 634 struct QgsWmtsLegendURL 635 { 636 QString format; 637 double minScale, maxScale; 638 QString href; 639 int width, height; 640 }; 641 642 struct QgsWmtsStyle 643 { 644 QString identifier; 645 QString title, abstract; 646 QStringList keywords; 647 bool isDefault; 648 QList<QgsWmtsLegendURL> legendURLs; 649 }; 650 651 /** 652 * In case of multi-dimensional data, the service metadata can describe their multi- 653 * dimensionality and tiles can be requested at specific values in these dimensions. 654 * Examples of dimensions are Time, Elevation and Band. 655 */ 656 struct QgsWmtsDimension 657 { 658 QString identifier; //!< Name of the dimensional axis 659 QString title; //!< Human readable name 660 QString abstract; //!< Brief description of the dimension 661 QStringList keywords; //!< List of words/phrases to describe the dataset 662 QString UOM; //!< Units of measure of dimensional axis 663 QString unitSymbol; //!< Symbol of the units 664 QString defaultValue; //!< Default value to be used if value is not specified in request 665 bool current; //!< Indicates whether temporal data are normally kept current 666 QStringList values; //!< Available values for this dimension 667 }; 668 669 struct QgsWmtsTileLayer 670 { 671 enum QgsTileMode tileMode; 672 QString identifier; 673 QString title, abstract; 674 QStringList keywords; 675 QVector<QgsWmsBoundingBoxProperty> boundingBoxes; 676 QStringList formats; 677 QStringList infoFormats; 678 QString defaultStyle; 679 int dpi = -1; //!< DPI of the tile layer (-1 for unknown DPI) 680 //! available dimensions (optional, for multi-dimensional data) 681 QHash<QString, QgsWmtsDimension> dimensions; 682 QHash<QString, QgsWmtsStyle> styles; 683 QHash<QString, QgsWmtsTileMatrixSetLink> setLinks; 684 685 QHash<QString, QString> getTileURLs; 686 QHash<QString, QString> getFeatureInfoURLs; 687 }; 688 689 //! Capability Property structure 690 // TODO: Fill to WMS specifications 691 struct QgsWmsCapabilityProperty 692 { 693 QgsWmsRequestProperty request; 694 QgsWmsExceptionProperty exception; 695 696 // Top level layer should normally be present max once 697 // <element name="Capability"> 698 // <element ref="wms:Layer" minOccurs="0"/> - default maxOccurs=1 699 // but there are a few non conformant capabilities around (#13762) 700 QList<QgsWmsLayerProperty> layers; 701 702 QList<QgsWmtsTileLayer> tileLayers; 703 QHash<QString, QgsWmtsTileMatrixSet> tileMatrixSets; 704 }; 705 706 //! Capabilities Property structure 707 // TODO: Fill to WMS specifications 708 struct QgsWmsCapabilitiesProperty 709 { 710 QgsWmsServiceProperty service; 711 QgsWmsCapabilityProperty capability; 712 QString version; 713 }; 714 715 //! Formats supported by QImageReader 716 struct QgsWmsSupportedFormat 717 { 718 QString format; 719 QString label; 720 }; 721 722 enum QgsWmsTileAttribute 723 { 724 TileReqNo = QNetworkRequest::User + 0, 725 TileIndex = QNetworkRequest::User + 1, 726 TileRect = QNetworkRequest::User + 2, 727 TileRetry = QNetworkRequest::User + 3, 728 }; 729 730 enum QgsWmsDpiMode 731 { 732 DpiNone = 0, 733 DpiQGIS = 1, 734 DpiUMN = 2, 735 DpiGeoServer = 4, 736 DpiAll = DpiQGIS | DpiUMN | DpiGeoServer, 737 }; 738 739 740 741 struct QgsWmsParserSettings 742 { 743 QgsWmsParserSettings( bool ignAxis = false, bool invAxis = false ) ignoreAxisOrientationQgsWmsParserSettings744 : ignoreAxisOrientation( ignAxis ) 745 , invertAxisOrientation( invAxis ) 746 {} 747 bool ignoreAxisOrientation; 748 bool invertAxisOrientation; 749 }; 750 751 struct QgsWmsAuthorization 752 { 753 QgsWmsAuthorization( const QString &userName = QString(), const QString &password = QString(), const QString &referer = QString(), const QString &authcfg = QString() ) mUserNameQgsWmsAuthorization754 : mUserName( userName ) 755 , mPassword( password ) 756 , mReferer( referer ) 757 , mAuthCfg( authcfg ) 758 {} 759 setAuthorizationQgsWmsAuthorization760 bool setAuthorization( QNetworkRequest &request ) const 761 { 762 if ( !mAuthCfg.isEmpty() ) 763 { 764 return QgsApplication::authManager()->updateNetworkRequest( request, mAuthCfg ); 765 } 766 else if ( !mUserName.isEmpty() || !mPassword.isEmpty() ) 767 { 768 request.setRawHeader( "Authorization", "Basic " + QStringLiteral( "%1:%2" ).arg( mUserName, mPassword ).toUtf8().toBase64() ); 769 } 770 771 if ( !mReferer.isEmpty() ) 772 { 773 request.setRawHeader( "Referer", mReferer.toLatin1() ); 774 } 775 return true; 776 } 777 //! Sets authorization reply setAuthorizationReplyQgsWmsAuthorization778 bool setAuthorizationReply( QNetworkReply *reply ) const 779 { 780 if ( !mAuthCfg.isEmpty() ) 781 { 782 return QgsApplication::authManager()->updateNetworkReply( reply, mAuthCfg ); 783 } 784 return true; 785 } 786 787 //! Username for basic http authentication 788 QString mUserName; 789 790 //! Password for basic http authentication 791 QString mPassword; 792 793 //! Referer for http requests 794 QString mReferer; 795 796 //! Authentication configuration ID 797 QString mAuthCfg; 798 }; 799 800 801 //! URI that gets passed to provider 802 class QgsWmsSettings 803 { 804 public: 805 806 bool parseUri( const QString &uriString ); 807 baseUrl()808 QString baseUrl() const { return mBaseUrl; } authorization()809 QgsWmsAuthorization authorization() const { return mAuth; } 810 parserSettings()811 QgsWmsParserSettings parserSettings() const { return mParserSettings; } 812 813 /** 814 * Parse the given string extent into a well defined dates and resolution structures. 815 * The string extent comes from WMS-T dimension capabilities. 816 * 817 * \since QGIS 3.14 818 */ 819 QgsWmstDimensionExtent parseTemporalExtent( const QString &extent ); 820 821 /** 822 * Sets the dimension extent property 823 * 824 * \see timeDimensionExtent() 825 * \since QGIS 3.14 826 */ 827 void setTimeDimensionExtent( const QgsWmstDimensionExtent &timeDimensionExtent ); 828 829 /** 830 * Returns the dimension extent property. 831 * 832 * \see setTimeDimensionExtent() 833 * \since QGIS 3.14 834 */ 835 QgsWmstDimensionExtent timeDimensionExtent() const; 836 837 /** 838 * Parse the given string item into a resolution structure. 839 * 840 * \since QGIS 3.14 841 */ 842 QgsWmstResolution parseWmstResolution( const QString &item ); 843 844 /** 845 * Parse the given string item into QDateTime instant. 846 * 847 * \since QGIS 3.14 848 */ 849 QDateTime parseWmstDateTimes( const QString &item ); 850 851 /** 852 * Returns the datetime with the sum of passed \a dateTime and the \a resolution time. 853 * 854 * \since QGIS 3.14 855 */ 856 QDateTime addTime( const QDateTime &dateTime, const QgsWmstResolution &resolution ); 857 858 /** 859 * Finds the least closest datetime from list of available dimension temporal ranges 860 * with the given \a dateTime. 861 * 862 * \note It works with wms-t capabilities that provide time dimension with temporal ranges only. 863 * 864 * \since QGIS 3.14 865 */ 866 QDateTime findLeastClosestDateTime( const QDateTime &dateTime, bool dateOnly = false ) const; 867 868 protected: 869 QgsWmsParserSettings mParserSettings; 870 871 //! layer is tiled, tile layer and active matrix set 872 bool mTiled; 873 //! whether we actually work with XYZ tiles instead of WMS / WMTS 874 bool mXyz; 875 876 //! Whether we are dealing with WMS-T 877 bool mIsTemporal = false; 878 879 //! Whether we are dealing bi-temporal dimensional WMS-T 880 bool mIsBiTemporal = false; 881 882 //! Temporal extent from dimension property in WMS-T 883 QString mTemporalExtent; 884 885 //! Fixed temporal range for the data provider 886 QgsDateTimeRange mFixedRange; 887 888 //! Fixed reference temporal range for the data provider 889 QgsDateTimeRange mFixedReferenceRange; 890 891 //! Stores WMS-T time dimension extent dates 892 QgsWmstDimensionExtent mTimeDimensionExtent; 893 894 //! Stores WMS-T reference dimension extent dates 895 QgsWmstDimensionExtent mReferenceTimeDimensionExtent; 896 897 //! whether we are dealing with MBTiles file rather than using network-based tiles 898 bool mIsMBTiles = false; 899 //! chosen values for dimensions in case of multi-dimensional data (key=dim id, value=dim value) 900 QHash<QString, QString> mTileDimensionValues; 901 //! name of the chosen tile matrix set 902 QString mTileMatrixSetId; 903 904 /** 905 * Maximum width and height of getmap requests 906 */ 907 int mMaxWidth; 908 int mMaxHeight; 909 910 /** 911 * Step size when iterating the layer 912 */ 913 int mStepWidth = QgsRasterIterator::DEFAULT_MAXIMUM_TILE_WIDTH; 914 int mStepHeight = QgsRasterIterator::DEFAULT_MAXIMUM_TILE_HEIGHT; 915 916 //! Data source URI of the WMS for this layer 917 QString mHttpUri; 918 919 //! URL part of URI (httpuri) 920 QString mBaseUrl; 921 922 QgsWmsAuthorization mAuth; 923 924 bool mIgnoreGetMapUrl; 925 bool mIgnoreGetFeatureInfoUrl; 926 bool mIgnoreReportedLayerExtents = false; 927 bool mSmoothPixmapTransform; 928 enum QgsWmsDpiMode mDpiMode; 929 930 /** 931 * Active sublayers managed by this provider in a draw function, in order from bottom to top 932 * (some may not be visible in a draw function, cf. activeSubLayerVisibility) 933 */ 934 QStringList mActiveSubLayers; 935 QStringList mActiveSubStyles; 936 937 QStringList mOpacities; 938 939 /** 940 * Visibility status of the given active sublayer 941 */ 942 QMap<QString, bool> mActiveSubLayerVisibility; 943 944 //! FEATURE_COUNT for GetFeatureInfo 945 int mFeatureCount; 946 947 /** 948 * MIME type of the image encoding used from the WMS server 949 */ 950 QString mImageMimeType; 951 952 QString mCrsId; 953 954 bool mEnableContextualLegend; 955 956 friend class QgsWmsProvider; 957 }; 958 959 960 //! Keeps information about capabilities of particular URI 961 class QgsWmsCapabilities 962 { 963 public: 964 965 /** 966 * Constructs a QgsWmsCapabilities object with the given \a coordinateTransformContext 967 */ 968 QgsWmsCapabilities( const QgsCoordinateTransformContext &coordinateTransformContext = QgsCoordinateTransformContext(), const QString &baseUrl = QString() ); 969 isValid()970 bool isValid() const { return mValid; } 971 972 bool parseResponse( const QByteArray &response, QgsWmsParserSettings settings ); 973 lastError()974 QString lastError() const { return mError; } lastErrorFormat()975 QString lastErrorFormat() const { return mErrorFormat; } 976 capabilitiesProperty()977 QgsWmsCapabilitiesProperty capabilitiesProperty() { return mCapabilities; } 978 979 /** 980 * \brief Returns a list of the supported layers of the WMS server 981 * 982 * \returns The list of layers will be placed here. 983 * 984 * \todo Document this better 985 */ supportedLayers()986 QVector<QgsWmsLayerProperty> supportedLayers() const { return mLayersSupported; } 987 988 //! Gets raster image encodings supported by the WMS, expressed as MIME types supportedImageEncodings()989 QStringList supportedImageEncodings() const { return mCapabilities.capability.request.getMap.format; } 990 991 /** 992 * \brief Returns a map for the hierarchy of layers 993 */ layerParents(QMap<int,int> & parents,QMap<int,QStringList> & parentNames)994 void layerParents( QMap<int, int> &parents, QMap<int, QStringList> &parentNames ) const { parents = mLayerParents; parentNames = mLayerParentNames; } 995 996 /** 997 * \brief Returns a list of the supported tile layers of the WMS server 998 * 999 * \returns The list of tile sets will be placed here. 1000 */ supportedTileLayers()1001 QList<QgsWmtsTileLayer> supportedTileLayers() const { return mTileLayersSupported; } 1002 1003 /** 1004 * \brief Returns a list of the available tile matrix sets 1005 */ supportedTileMatrixSets()1006 QHash<QString, QgsWmtsTileMatrixSet> supportedTileMatrixSets() const { return mTileMatrixSets; } 1007 1008 //! Find out whether to invert axis orientation when parsing/writing coordinates 1009 bool shouldInvertAxisOrientation( const QString &ogcCrs ); 1010 1011 //! Find out identify capabilities 1012 int identifyCapabilities() const; 1013 1014 protected: 1015 bool parseCapabilitiesDom( const QByteArray &xml, QgsWmsCapabilitiesProperty &capabilitiesProperty ); 1016 1017 void parseService( const QDomElement &element, QgsWmsServiceProperty &serviceProperty ); 1018 void parseOnlineResource( const QDomElement &element, QgsWmsOnlineResourceAttribute &onlineResourceAttribute ); 1019 void parseKeywordList( const QDomElement &element, QStringList &keywordListProperty ); 1020 void parseContactInformation( const QDomElement &element, QgsWmsContactInformationProperty &contactInformationProperty ); 1021 void parseContactPersonPrimary( const QDomElement &element, QgsWmsContactPersonPrimaryProperty &contactPersonPrimaryProperty ); 1022 void parseContactAddress( const QDomElement &element, QgsWmsContactAddressProperty &contactAddressProperty ); 1023 1024 void parseCapability( const QDomElement &element, QgsWmsCapabilityProperty &capabilityProperty ); 1025 void parseRequest( const QDomElement &element, QgsWmsRequestProperty &requestProperty ); 1026 void parseDimension( const QDomElement &element, QgsWmsDimensionProperty &dimensionProperty ); 1027 void parseExtent( const QDomElement &element, QVector<QgsWmsDimensionProperty> &dimensionProperties ); 1028 void parseLegendUrl( const QDomElement &element, QgsWmsLegendUrlProperty &legendUrlProperty ); 1029 void parseMetadataUrl( const QDomElement &element, QgsWmsMetadataUrlProperty &metadataUrlProperty ); 1030 void parseLayer( const QDomElement &element, QgsWmsLayerProperty &layerProperty, QgsWmsLayerProperty *parentProperty = nullptr ); 1031 void parseStyle( const QDomElement &element, QgsWmsStyleProperty &styleProperty ); 1032 1033 void parseOperationType( const QDomElement &element, QgsWmsOperationType &operationType ); 1034 void parseDcpType( const QDomElement &element, QgsWmsDcpTypeProperty &dcpType ); 1035 void parseHttp( const QDomElement &element, QgsWmsHttpProperty &httpProperty ); 1036 void parseGet( const QDomElement &element, QgsWmsGetProperty &getProperty ); 1037 void parsePost( const QDomElement &element, QgsWmsPostProperty &postProperty ); 1038 1039 void parseTileSetProfile( const QDomElement &element ); 1040 void parseWMTSContents( const QDomElement &element ); 1041 void parseKeywords( const QDomNode &e, QStringList &keywords ); 1042 void parseTheme( const QDomElement &e, QgsWmtsTheme &t ); 1043 1044 QString nodeAttribute( const QDomElement &element, const QString &name, const QString &defValue = QString() ); 1045 1046 /** 1047 * In case no bounding box is present in WMTS capabilities, try to estimate it from tile matrix sets. 1048 * Returns true if the detection went fine. 1049 */ 1050 bool detectTileLayerBoundingBox( QgsWmtsTileLayer &l ); 1051 1052 protected: 1053 bool mValid = false; 1054 1055 QString mError; 1056 QString mErrorCaption; 1057 QString mErrorFormat; 1058 1059 QgsWmsParserSettings mParserSettings; 1060 1061 //! number of layers and parents 1062 int mLayerCount = -1; 1063 QMap<int, int> mLayerParents; 1064 QMap<int, QStringList> mLayerParentNames; 1065 1066 /** 1067 * WMS "queryable" per layer 1068 * Used in determining if the Identify map tool can be useful on the rendered WMS map layer. 1069 */ 1070 QMap<QString, bool> mQueryableForLayer; 1071 1072 /** 1073 * layers hosted by the WMS 1074 */ 1075 QVector<QgsWmsLayerProperty> mLayersSupported; 1076 1077 /** 1078 * tilesets hosted by the WMTS 1079 */ 1080 QList<QgsWmtsTileLayer> mTileLayersSupported; 1081 1082 /** 1083 * themes hosted by the WMTS 1084 */ 1085 QList<QgsWmtsTheme> mTileThemes; 1086 1087 /** 1088 * Parsed capabilities of the WMS 1089 */ 1090 QgsWmsCapabilitiesProperty mCapabilities; 1091 1092 //! Formats supported by server and provider 1093 QMap<QgsRaster::IdentifyFormat, QString> mIdentifyFormats; 1094 1095 1096 /** 1097 * tile matrix sets hosted by the WMS 1098 */ 1099 QHash<QString, QgsWmtsTileMatrixSet> mTileMatrixSets; 1100 1101 //temporarily caches invert axis setting for each crs 1102 QHash<QString, bool> mCrsInvertAxis; 1103 1104 private: 1105 1106 QgsCoordinateTransformContext mCoordinateTransformContext; 1107 QString mBaseUrl; 1108 1109 friend class QgsWmsProvider; 1110 friend class TestQgsWmsCapabilities; 1111 }; 1112 1113 1114 1115 /** 1116 * Class that handles download of capabilities. 1117 */ 1118 class QgsWmsCapabilitiesDownload : public QObject 1119 { 1120 Q_OBJECT 1121 1122 public: 1123 explicit QgsWmsCapabilitiesDownload( bool forceRefresh, QObject *parent = nullptr ); 1124 1125 QgsWmsCapabilitiesDownload( const QString &baseUrl, const QgsWmsAuthorization &auth, bool forceRefresh, QObject *parent = nullptr ); 1126 1127 ~QgsWmsCapabilitiesDownload() override; 1128 1129 bool downloadCapabilities(); 1130 1131 bool downloadCapabilities( const QString &baseUrl, const QgsWmsAuthorization &auth ); 1132 lastError()1133 QString lastError() const { return mError; } 1134 response()1135 QByteArray response() const { return mHttpCapabilitiesResponse; } 1136 1137 //! Abort network request immediately 1138 void abort(); 1139 1140 signals: 1141 //! \brief emit a signal to be caught by qgisapp and display a msg on status bar 1142 void statusChanged( QString const &statusQString ); 1143 1144 //! \brief emit a signal once the download is finished 1145 void downloadFinished(); 1146 1147 protected slots: 1148 void capabilitiesReplyFinished(); 1149 void capabilitiesReplyProgress( qint64, qint64 ); 1150 1151 protected: 1152 //! URL part of URI (httpuri) 1153 QString mBaseUrl; 1154 1155 QgsWmsAuthorization mAuth; 1156 1157 //! The reply to the capabilities request 1158 QNetworkReply *mCapabilitiesReply = nullptr; 1159 1160 //! The error message associated with the last WMS error. 1161 QString mError; 1162 1163 //! The mime type of the message 1164 QString mErrorFormat; 1165 1166 //! Capabilities of the WMS (raw) 1167 QByteArray mHttpCapabilitiesResponse; 1168 1169 bool mIsAborted; 1170 bool mForceRefresh; 1171 }; 1172 1173 1174 1175 #endif // QGSWMSCAPABILITIES_H 1176