File indexing completed on 2024-04-21 03:49:49

0001 // SPDX-License-Identifier: LGPL-2.1-or-later
0002 //
0003 // SPDX-FileCopyrightText: 2023 Torsten Rahn <rahn@kde.org>
0004 //
0005 
0006 #include "OwsServiceManager.h"
0007 
0008 #include <QUrl>
0009 #include <QUrlQuery>
0010 #include <QNetworkReply>
0011 #include <QAuthenticator>
0012 
0013 #include <QBuffer>
0014 #include <QImageReader>
0015 
0016 #include <MarbleDebug.h>
0017 #include <cmath>
0018 
0019 namespace Marble
0020 {
0021 
0022 OwsMappingCapabilities::OwsMappingCapabilities()
0023 {
0024 
0025 }
0026 
0027 WmsCapabilities::WmsCapabilities()
0028 {
0029 }
0030 
0031 WmtsCapabilities::WmtsCapabilities()
0032 {
0033 
0034 }
0035 
0036 void WmtsCapabilities::setWmtsTileMatrixSets(const QMap<QString, QStringList> &wmtsTileMatrixSets)
0037 {
0038     m_wmtsTileMatrixSets = wmtsTileMatrixSets;
0039 }
0040 
0041 QMap<QString, QStringList> WmtsCapabilities::wmtsTileMatrixSets() const
0042 {
0043     return m_wmtsTileMatrixSets;
0044 }
0045 
0046 void WmtsCapabilities::setWmtsTileResource(const QMap<QString, QMap<QString, QString> > &wmtsTileRessource)
0047 {
0048     m_wmtsTileResource = wmtsTileRessource;
0049 }
0050 
0051 QMap<QString, QMap<QString, QString> > WmtsCapabilities::wmtsTileResource() const
0052 {
0053     return m_wmtsTileResource;
0054 }
0055 
0056 ImageRequestResult::ImageRequestResult()
0057     : m_imageStatus(WmsImageNone)
0058 {
0059 
0060 }
0061 
0062 void ImageRequestResult::setImageStatus(WmsImageStatus imageStatus)
0063 {
0064     m_imageStatus = imageStatus;
0065 }
0066 
0067 WmsImageStatus ImageRequestResult::imageStatus() const
0068 {
0069     return m_imageStatus;
0070 }
0071 
0072 void ImageRequestResult::setResultImage(const QImage &image)
0073 {
0074     m_resultImage = image;
0075 }
0076 
0077 QImage ImageRequestResult::resultImage() const
0078 {
0079     return m_resultImage;
0080 }
0081 
0082 void ImageRequestResult::setResultRaw(const QByteArray &resultRaw)
0083 {
0084     m_resultRaw = resultRaw;
0085 }
0086 
0087 QByteArray ImageRequestResult::resultRaw() const
0088 {
0089     return m_resultRaw;
0090 }
0091 
0092 void ImageRequestResult::setResultFormat(const QString &resultFormat)
0093 {
0094     m_resultFormat = resultFormat;
0095 }
0096 
0097 QString ImageRequestResult::resultFormat() const
0098 {
0099     return m_resultFormat;
0100 }
0101 
0102 void ImageRequestResult::setResultType(const ImageResultType resultType)
0103 {
0104     m_resultType = resultType;
0105 }
0106 
0107 ImageResultType ImageRequestResult::resultType() const
0108 {
0109     return m_resultType;
0110 }
0111 
0112 void OwsMappingCapabilities::setVersion(const QString &version)
0113 {
0114     m_version = version;
0115 }
0116 
0117 QString OwsMappingCapabilities::version() const
0118 {
0119     return m_version;
0120 }
0121 
0122 void OwsMappingCapabilities::setTitle(const QString &title)
0123 {
0124     m_title = title;
0125 }
0126 
0127 QString OwsMappingCapabilities::title() const
0128 {
0129     return m_title;
0130 }
0131 
0132 void OwsMappingCapabilities::setAbstract(const QString &abstract)
0133 {
0134     m_abstract = abstract;
0135 }
0136 
0137 QString OwsMappingCapabilities::abstract() const
0138 {
0139     return m_abstract;
0140 }
0141 
0142 void WmsCapabilities::setContactInformation(const QString &info)
0143 {
0144     m_contactInformation = info;
0145 }
0146 
0147 QString WmsCapabilities::contactInformation() const
0148 {
0149     return m_contactInformation;
0150 }
0151 
0152 void WmsCapabilities::setFees(const QString &fees)
0153 {
0154     m_fees = fees;
0155 }
0156 
0157 QString WmsCapabilities::fees() const
0158 {
0159     return m_fees;
0160 }
0161 
0162 QStringList OwsMappingCapabilities::layers() const
0163 {
0164     return m_owsLayerMetaInfo.keys();
0165 }
0166 
0167 QStringList WmsCapabilities::projections(const QString &layer)
0168 {
0169     QStringList result = m_wmsLayerCoordinateSystems.value(layer).keys();
0170     if (!m_wmsLayerCoordinateSystems.isEmpty()) {
0171         result << m_wmsLayerCoordinateSystems.value(m_wmsLayerCoordinateSystems.firstKey()).keys();
0172     }
0173     result.removeDuplicates();
0174 
0175     return result;
0176 }
0177 
0178 QString WmsCapabilities::boundingBox(const QString &layer, const QString &projection)
0179 {
0180     QString result;
0181     result = m_wmsLayerCoordinateSystems.value(layer).value(projection);
0182     if (result.isEmpty()) {
0183         result = m_wmsLayerCoordinateSystems.value(0).value(projection);
0184     }
0185     return result;
0186 }
0187 
0188 QString OwsMappingCapabilities::title(const QString &layer)
0189 {
0190     return m_owsLayerMetaInfo.value(layer).at(0);
0191 }
0192 
0193 QString OwsMappingCapabilities::abstract(const QString &layer)
0194 {
0195     return m_owsLayerMetaInfo.value(layer).at(1);
0196 }
0197 
0198 QString WmsCapabilities::legendUrl(const QString &layer)
0199 {
0200     return m_owsLayerMetaInfo.value(layer).at(2);
0201 }
0202 
0203 QString OwsMappingCapabilities::style(const QString &layer)
0204 {
0205     return m_owsLayerMetaInfo.value(layer).at(3);
0206 }
0207 
0208 QStringList WmsCapabilities::styles(const QStringList &layers)
0209 {
0210     QStringList retVal;
0211     for (auto layer : layers) {
0212         retVal << style(layer);
0213     }
0214     return retVal;
0215 }
0216 
0217 QString WmsCapabilities::boundingBoxNSEWDegrees(const QStringList &layers, const QString& projection)
0218 {
0219     QString retVal;
0220     for (auto layer : layers) {
0221         QString layerBBox = boundingBox(layer, projection);
0222         if (layerBBox.isEmpty()) {
0223             retVal = QString("90,-90,180,-180");
0224             break;
0225         }
0226         QStringList layerBBoxList = layerBBox.split(",");
0227         qreal west, south, east, north;
0228         if (projection == "epsg:3857") {
0229             west = layerBBoxList.at(0).toDouble() * 180/20037508.34;
0230             south = atan(pow(2.7182818284, (layerBBoxList.at(1).toDouble()/20037508.34 * M_PI))) * (360/M_PI) - 90;
0231             east = layerBBoxList.at(2).toDouble() * 180/20037508.34;
0232             north = atan(pow(2.7182818284, (layerBBoxList.at(3).toDouble()/20037508.34 * M_PI))) * (360/M_PI) - 90;
0233         }
0234         else {
0235             if (projection == "crs:84" || (projection == "4326" && version() != "1.3.0")) {
0236                 // order: longitude-latitude
0237                 west = layerBBoxList.at(0).toDouble();
0238                 south = layerBBoxList.at(1).toDouble();
0239                 east = layerBBoxList.at(2).toDouble();
0240                 north = layerBBoxList.at(3).toDouble();
0241             }
0242             else {
0243                 // order: latitude-longitude
0244                 west = layerBBoxList.at(1).toDouble();
0245                 south = layerBBoxList.at(0).toDouble();
0246                 east = layerBBoxList.at(3).toDouble();
0247                 north = layerBBoxList.at(2).toDouble();
0248             }
0249         }
0250         retVal = QString("%1,%2,%3,%4").arg(north).arg(south).arg(east).arg(west);
0251         // TODO: merge possibly different layer bboxes
0252         break;
0253     }
0254     return retVal;
0255 }
0256 
0257 void WmsCapabilities::setReferenceSystemType(const QString &refSystem)
0258 {
0259     m_referenceSystemType = refSystem;
0260 }
0261 
0262 QString WmsCapabilities::referenceSystemType() const
0263 {
0264     return m_referenceSystemType;
0265 }
0266 
0267 void OwsMappingCapabilities::setOwsLayerMetaInfo(const QMap<QString, QStringList> &wmsLayerMetaInfo)
0268 {
0269     m_owsLayerMetaInfo = wmsLayerMetaInfo;
0270 }
0271 
0272 QMap<QString, QStringList> OwsMappingCapabilities::owsLayerMetaInfo() const
0273 {
0274     return m_owsLayerMetaInfo;
0275 }
0276 
0277 void WmsCapabilities::setWmsLayerCoordinateSystems(const QMap<QString, QMap<QString, QString> > &wmsLayerCoordinateSystems)
0278 {
0279     m_wmsLayerCoordinateSystems = wmsLayerCoordinateSystems;
0280 }
0281 
0282 QMap<QString, QMap<QString, QString> > WmsCapabilities::wmsLayerCoordinateSystems() const
0283 {
0284     return m_wmsLayerCoordinateSystems;
0285 }
0286 
0287 void WmsCapabilities::setFormats(const QStringList &formats)
0288 {
0289     m_formats = formats;
0290 }
0291 
0292 QStringList WmsCapabilities::formats()
0293 {
0294     return m_formats;
0295 }
0296 
0297 
0298 OwsServiceManager::OwsServiceManager(QObject *parent)
0299     : QObject(parent),
0300       m_capabilitiesStatus(OwsCapabilitiesNone)
0301 {
0302     connect( &m_capabilitiesAccessManager, &QNetworkAccessManager::finished, this, &OwsServiceManager::parseOwsCapabilities );
0303     connect( &m_imageAccessManager, &QNetworkAccessManager::finished, this, &OwsServiceManager::parseImageResult );
0304 
0305     connect( &m_capabilitiesAccessManager, &QNetworkAccessManager::authenticationRequired, this, &OwsServiceManager::handleAuthentication );
0306     connect( &m_imageAccessManager, &QNetworkAccessManager::authenticationRequired, this, &OwsServiceManager::handleAuthentication );
0307 }
0308 
0309 void OwsServiceManager::queryOwsCapabilities(const QUrl& queryUrl, const QString& serviceString)
0310 {
0311     m_url = queryUrl;
0312     QUrl url(queryUrl);
0313     QUrlQuery urlQuery;
0314     urlQuery.addQueryItem( "service", serviceString );
0315     urlQuery.addQueryItem( "request", "GetCapabilities" );
0316     url.setQuery(urlQuery);
0317 
0318     QNetworkRequest request;
0319     request.setUrl( url );
0320     request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
0321 
0322     mDebug() << "for url" << url;
0323     m_capabilitiesAccessManager.get( request );
0324 }
0325 
0326 void OwsServiceManager::queryWmsMap(const QUrl &url, const QString &layers, const QString &projection,
0327                                     const QString &bbox, const QString &format, const QString &style)
0328 {
0329     m_imageRequestResult.setResultImage(QImage());
0330     m_imageRequestResult.setImageStatus(WmsImageNone);
0331     m_imageRequestResult.setResultRaw("");
0332     m_imageRequestResult.setResultFormat(QString());
0333 
0334     QUrlQuery downloadQuery;
0335     downloadQuery.addQueryItem( "request", "GetMap" ); // Requests that the server generates a map.
0336     downloadQuery.addQueryItem( "service", "wms" ); // Service name. Value is WMS.
0337 
0338     QString versionkey = wmsCapabilities().version() == "1.0.0" ? "wmtver" : "version";
0339     downloadQuery.addQueryItem( versionkey , wmsCapabilities().version() ); // Service version. Value is one of 1.0.0, 1.1.0, 1.1.1, 1.3.0.
0340     downloadQuery.addQueryItem( "layers", layers ); // Layers to display on map. Value is a comma-separated list of layer names.
0341 
0342     // Spatial Reference System for map output. Value is in the form EPSG:nnn. srs was used before WMS 1.3.0, crs has been used since then.
0343     downloadQuery.addQueryItem( wmsCapabilities().referenceSystemType(), projection );
0344     // downloadQuery.addQueryItem( "bgcolor", "#ff0000" ); // rarely supported by servers
0345 
0346     downloadQuery.addQueryItem( "width", "256" ); // Width of map output, in pixels.
0347     downloadQuery.addQueryItem( "height", "256" ); // Height of map output, in pixels.
0348 
0349     QString boundingBox = bbox;
0350     if (boundingBox.isEmpty()) {
0351         if (projection == "epsg:3857") {
0352             boundingBox = "-20037508.34,-20048966.1,20037508.34,20048966.1";
0353         }
0354         else if (projection == "epsg:4326") {
0355             boundingBox = wmsCapabilities().version() == "1.3.0" ? "-90,-180,90,180" : "-180,-90,180,90";  // flipped axes for 1.3.0 in epsg:4326 according to spec
0356         }
0357         else if (projection == "crs:84") {
0358             boundingBox = "-180,-90,180,90"; // order: WGS84 longitude-latitude
0359         }
0360     }
0361     downloadQuery.addQueryItem( "bbox", boundingBox );
0362     downloadQuery.addQueryItem( "transparent", "true");
0363 
0364     // Format for the map output. In addition to common bitmap formats WMS servers
0365     // sometimes support "vector" formats (PDF, SVG, KML, etc.)
0366     // Currently Marble only supports JPEG, PNG, TIFF, GIF, BMP and their variants.
0367     downloadQuery.addQueryItem( "format", QString("image/%1").arg(format) );
0368 
0369     // Styles in which layers are to be rendered. Value is a comma-separated list of style names,
0370     // or empty if default styling is required. Style names may be empty in the list,
0371     // to use default layer styling. However some servers do not accept empty style names.
0372     downloadQuery.addQueryItem( "styles", style );
0373     m_imageRequestResult.setResultFormat((format == QLatin1String("jpeg")) ? "jpg" : format); // Is this needed here?
0374 
0375     QUrl finalDownloadUrl( url );
0376     finalDownloadUrl.setQuery( downloadQuery );
0377     mDebug() << "requesting WMS image" << finalDownloadUrl;
0378 
0379     QNetworkRequest request( finalDownloadUrl );
0380 
0381     m_imageAccessManager.get( request );
0382 }
0383 
0384 void OwsServiceManager::queryWmsLevelZeroTile(const QUrl& url, const QString &layers, const QString &projection,
0385                                            const QString &format, const QString &style)
0386 {
0387     QString bbox;
0388     if (projection == "epsg:3857") {
0389         bbox = "-20037508.34,-20048966.1,20037508.34,20048966.1";
0390 
0391     }
0392     else if (projection == "epsg:4326") {
0393         bbox = wmsCapabilities().version() == "1.3.0" ? "-90,-180,90,180" : "-180,-90,180,90"; // flipped axes for 1.3.0 in epsg:4326 according to spec
0394     }
0395     else if (projection == "crs:84") {
0396         bbox = "-180,-90,180,90"; // order: WGS84 longitude-latitude
0397     }
0398 
0399     m_imageRequestResult.setResultType(LevelZeroTile);
0400 
0401     queryWmsMap(url, layers, projection, bbox, format, style);
0402 }
0403 
0404 void OwsServiceManager::queryWmsPreviewImage(const QUrl& url, const QString &layers, const QString &projection,
0405                                           const QString &format, const QString &style)
0406 {
0407 
0408     QString firstLayer = layers.contains(',') ? layers.section(',',0,0) : layers;
0409     QString bbox = wmsCapabilities().boundingBox(firstLayer, projection);
0410 
0411     m_imageRequestResult.setResultType(PreviewImage);
0412 
0413     queryWmsMap(url, layers, projection, bbox, format, style);
0414 }
0415 
0416 void OwsServiceManager::queryWmsLegendImage(const QUrl &url)
0417 {
0418     m_imageRequestResult.setResultImage(QImage());
0419     m_imageRequestResult.setImageStatus(WmsImageNone);
0420     m_imageRequestResult.setResultRaw("");
0421     m_imageRequestResult.setResultFormat(QString());
0422     m_imageRequestResult.setResultType(LegendImage);
0423 
0424     mDebug() << "requesting legend" << url;
0425 
0426     QNetworkRequest request( url );
0427 
0428     m_imageAccessManager.get( request );
0429 }
0430 
0431 void OwsServiceManager::queryWmtsLevelZeroTile(const QString &url, const QString &style, const QString &tileMatrixSet)
0432 {
0433     m_imageRequestResult.setResultType(LevelZeroTile);
0434     queryWmtsTile(url, style, tileMatrixSet, "0", "0", "0");
0435 }
0436 
0437 void OwsServiceManager::queryWmtsPreviewImage(const QString &url, const QString &style, const QString &tileMatrixSet)
0438 {
0439     m_imageRequestResult.setResultType(PreviewImage);
0440     queryWmtsTile(url, style, tileMatrixSet, "0", "0", "0");
0441 }
0442 
0443 void OwsServiceManager::queryWmtsTile(const QString &url, const QString &style, const QString &tileMatrixSet, const QString& tileMatrix, const QString &tileRow, const QString &tileCol)
0444 {
0445     m_imageRequestResult.setResultImage(QImage());
0446     m_imageRequestResult.setImageStatus(WmsImageNone);
0447     m_imageRequestResult.setResultRaw("");
0448     m_imageRequestResult.setResultFormat(QString());
0449 
0450     QUrl downloadUrl;
0451     QString baseUrl = url;
0452     baseUrl.replace(baseUrl.indexOf(QLatin1String("{Time}")), 6, "current");
0453     baseUrl.replace(baseUrl.indexOf(QLatin1String("{style}")), 7, style);
0454     baseUrl.replace(baseUrl.indexOf(QLatin1String("{Style}")), 7, style);
0455     baseUrl.replace(baseUrl.indexOf(QLatin1String("{TileMatrixSet}")), 15,  tileMatrixSet);
0456     baseUrl.replace(baseUrl.indexOf(QLatin1String("{TileMatrix}")), 12,  tileMatrix);
0457     baseUrl.replace(baseUrl.indexOf(QLatin1String("{TileRow}")), 9,  tileRow);
0458     baseUrl.replace(baseUrl.indexOf(QLatin1String("{TileCol}")), 9,  tileCol);
0459     downloadUrl.setUrl( baseUrl );
0460 
0461     QNetworkRequest request( downloadUrl );
0462     mDebug() << "requesting static map" << downloadUrl;
0463     m_imageAccessManager.get( request );
0464 }
0465 
0466 void OwsServiceManager::queryXYZPreviewImage(const QString &urlString)
0467 {
0468     m_imageRequestResult.setResultType(PreviewImage);
0469     queryXYZImage(urlString);
0470 }
0471 
0472 void OwsServiceManager::queryXYZLevelZeroTile(const QString &urlString)
0473 {
0474     m_imageRequestResult.setResultType(LevelZeroTile);
0475     queryXYZImage(urlString);
0476 }
0477 
0478 void OwsServiceManager::queryXYZImage(const QString urlString)
0479 {
0480     QUrl downloadUrl;
0481     QString baseUrl = urlString;
0482     baseUrl.replace(baseUrl.indexOf(QLatin1String("{x}")), 3,  QString::number(0));
0483     baseUrl.replace(baseUrl.indexOf(QLatin1String("{y}")), 3,  QString::number(0));
0484     baseUrl.replace(baseUrl.indexOf(QLatin1String("{zoomLevel}")), 11,  QString::number(0));
0485     baseUrl.replace(baseUrl.indexOf(QLatin1String("{z}")), 3,  QString::number(0));
0486     downloadUrl.setUrl( baseUrl );
0487 
0488     QNetworkRequest request( downloadUrl );
0489     mDebug() << "requesting static map" << downloadUrl;
0490     m_imageAccessManager.get( request );
0491 }
0492 
0493 void OwsServiceManager::handleAuthentication(QNetworkReply *reply, QAuthenticator *authenticator)
0494 {
0495     if (reply->url().host() == QString("api.tileserver.org")) {
0496         authenticator->setUser("");
0497         authenticator->setPassword("");
0498     }
0499 }
0500 
0501 void OwsServiceManager::setCapabilitiesStatus(OwsCapabilitiesStatus capabilitiesStatus)
0502 {
0503     m_capabilitiesStatus = capabilitiesStatus;
0504 }
0505 
0506 OwsCapabilitiesStatus OwsServiceManager::capabilitiesStatus() const
0507 {
0508     return m_capabilitiesStatus;
0509 }
0510 
0511 OwsServiceType OwsServiceManager::owsServiceType()
0512 {
0513     return m_owsServiceType;
0514 }
0515 
0516 WmsCapabilities Marble::OwsServiceManager::wmsCapabilities()
0517 {
0518     return m_wmsCapabilities;
0519 }
0520 
0521 WmtsCapabilities OwsServiceManager::wmtsCapabilities()
0522 {
0523     return m_wmtsCapabilities;
0524 }
0525 
0526 ImageRequestResult OwsServiceManager::imageRequestResult()
0527 {
0528     return m_imageRequestResult;
0529 }
0530 
0531 QImage OwsServiceManager::resultImage()
0532 {
0533     return m_imageRequestResult.resultImage();
0534 }
0535 
0536 ImageResultType OwsServiceManager::resultType()
0537 {
0538     return m_imageRequestResult.resultType();
0539 }
0540 
0541 QByteArray OwsServiceManager::resultRaw()
0542 {
0543     return m_imageRequestResult.resultRaw();
0544 }
0545 
0546 QString OwsServiceManager::resultFormat()
0547 {
0548     return m_imageRequestResult.resultFormat();
0549 }
0550 
0551 void OwsServiceManager::parseOwsCapabilities(QNetworkReply *reply)
0552 {
0553     mDebug() << "received reply from" << reply->url();
0554     QString result( reply->readAll() );
0555 
0556     m_wmsCapabilities = WmsCapabilities(); // clear()
0557 
0558     if( !m_xml.setContent( result ) )
0559     {
0560         setCapabilitiesStatus(OwsCapabilitiesReplyUnreadable); // Wizard cannot parse server's response
0561         emit wmsCapabilitiesReady();
0562         return;
0563     }
0564 
0565     if( m_xml.documentElement().firstChildElement().tagName().isNull()
0566         || !m_xml.documentElement().tagName().contains("Capabilities"))
0567     {
0568         setCapabilitiesStatus(OwsCapabilitiesNoOwsServer); // Server is not a Ows Server.
0569         emit wmsCapabilitiesReady();
0570         return;
0571     }
0572 
0573     if (m_xml.documentElement().tagName() == "WMS_Capabilities"
0574      || m_xml.documentElement().tagName() == "WMT_MS_Capabilities") { // WMTS server used for WMS?
0575         m_owsServiceType = WmsType;
0576         parseWmsCapabilities(reply);
0577     }
0578     else if (m_xml.documentElement().tagName() == "Capabilities") {
0579         m_owsServiceType = WmtsType;
0580         parseWmtsCapabilities(reply);
0581     }
0582     else if (m_xml.documentElement().tagName() == ("wfs:WFS_Capabilities")) {
0583         m_owsServiceType = WfsType;
0584     }
0585     else if (m_xml.documentElement().tagName() == ("wcs:Capabilities")) {
0586         m_owsServiceType = WcsType;
0587     }
0588     else {
0589         m_owsServiceType = NoOwsType;
0590     }
0591 }
0592 
0593 void OwsServiceManager::parseWmsCapabilities(QNetworkReply *reply)
0594 {
0595     Q_UNUSED(reply)
0596 
0597     m_wmsCapabilities.setVersion( m_xml.documentElement().attribute("version") );
0598     m_wmsCapabilities.setReferenceSystemType( (m_wmsCapabilities.version() == "1.0.0"
0599                                          || m_wmsCapabilities.version() == "1.1.0"
0600                                          || m_wmsCapabilities.version() == "1.1.1")  ? "SRS" : "CRS" );
0601 
0602     QDomElement service = m_xml.documentElement().firstChildElement( "Service" );
0603     QDomNodeList layers = m_xml.documentElement().firstChildElement( "Capability" ).elementsByTagName("Layer");
0604 
0605     m_wmsCapabilities.setTitle(service.firstChildElement( "Title" ).text());
0606     m_wmsCapabilities.setAbstract(service.firstChildElement( "Abstract" ).text() );
0607 
0608     QDomElement contactElement = service.firstChildElement( "ContactInformation");
0609     QDomElement contactPersonPrimaryElement = contactElement.firstChildElement("ContactPersonPrimary");
0610     QString contactPersonPrimary;
0611     if (!contactPersonPrimaryElement.isNull()) {
0612         QString contactPerson = contactPersonPrimaryElement.firstChildElement("ContactPerson").text();
0613         QString contactOrganisation = contactPersonPrimaryElement.firstChildElement("ContactOrganization").text();
0614         contactPersonPrimary = contactPerson + "<br>" + contactOrganisation + "<br>";
0615     }
0616     QString contactPosition = contactElement.firstChildElement("ContactPosition").text();
0617     contactPersonPrimary += contactPosition;
0618 
0619     QDomElement addressElement = contactElement.firstChildElement("ContactAddress");
0620     QString postalAddress;
0621     if (!addressElement.isNull() && addressElement.firstChildElement("AddressType").text() == "postal") {
0622         QString address = addressElement.firstChildElement("Address").text();
0623         QString city = addressElement.firstChildElement("City").text();
0624         QString stateOrProvince = addressElement.firstChildElement("StateOrProvince").text();
0625         QString postalCode = addressElement.firstChildElement("PostCode").text();
0626         QString country = addressElement.firstChildElement("Country").text();
0627         postalAddress = address + "<br>" + city + "<br>" + stateOrProvince + "<br>" + postalCode + "<br>" + country;
0628     }
0629     QString contactVoicePhone = contactElement.firstChildElement("ContactVoiceTelephone").text();
0630     QString contactFacsimileTelephone = contactElement.firstChildElement("ContactFacsimileTelephone").text();
0631     QString contactEmail = contactElement.firstChildElement("ContactElectronicMailAddress" ).text();
0632     QString contactMedium = contactVoicePhone + "<br>" + contactFacsimileTelephone + "<br>" + contactEmail;
0633 
0634     QString contactInformation = contactPersonPrimary + "<br><small><font color=\"darkgrey\">" + postalAddress + "<br>" + contactMedium + "</font></small>";
0635 
0636     m_wmsCapabilities.setContactInformation(contactInformation);
0637     QString fees = service.firstChildElement( "Fees" ).text();
0638     m_wmsCapabilities.setFees(fees);
0639 
0640     QMap<QString, QStringList> wmsLayerMetaInfo;
0641 
0642     for( int i = 0; i < layers.size(); ++i )
0643     {
0644         QString name = layers.at(i).firstChildElement( "Name" ).text();
0645         QString title = layers.at(i).firstChildElement( "Title" ).text();
0646         QString abstract = layers.at(i ).firstChildElement( "Abstract" ).text();
0647         QDomElement legendElement = layers.at( i ).firstChildElement( "Style" ).firstChildElement( "LegendURL" );
0648         QString legendUrl;
0649         if (!legendElement.isNull()) legendUrl = legendElement.firstChildElement( "OnlineResource" ).attribute( "xlink:href" );
0650         QString style = layers.at(i).firstChildElement("Style").firstChildElement( "Name" ).text();
0651         if (style.isEmpty()) style = "default";
0652 /*      QDomElement gbboxElement = layers.at(i).firstChildElement("EX_GeographicBoundingBox");
0653         QStringList bbox;
0654         if (!gbboxElement.isNull()) {
0655             bbox << gbboxElement.firstChildElement("westBoundLongitude").text() << gbboxElement.firstChildElement("southBoundLatitude").text()
0656                  << gbboxElement.firstChildElement("eastBoundLongitude").text() << gbboxElement.firstChildElement("northBoundLatitude").text();
0657         }
0658         wmsLayerMetaInfo[ name ] << title << abstract << legendUrl << style << bbox.join(","); */
0659         wmsLayerMetaInfo[ name ] << title << abstract << legendUrl << style;
0660     }
0661 
0662     m_wmsCapabilities.setOwsLayerMetaInfo(wmsLayerMetaInfo);
0663 
0664     QMap<QString, QMap<QString, QString>> wmsLayerCoordinateSystems;
0665     for( int i = 0; i < layers.size(); ++i )
0666     {
0667         QString layerName = layers.at(i).firstChildElement( "Name" ).text();
0668         QDomNodeList projectionList = layers.at(i).toElement().elementsByTagName(m_wmsCapabilities.referenceSystemType());
0669         QDomNodeList layerPreviewBBox = layers.at(i).toElement().elementsByTagName("BoundingBox");
0670 
0671         for ( int s = 0; s < projectionList.size(); ++s ) {
0672             QString projection = projectionList.at(s).toElement().text().toLower();
0673             // SRS and CRS tags might contain a list of epsgs, so we need to use contains()
0674             if (projection.contains("epsg:3857")) {
0675 /*              if (wmsLayerMetaInfo.value(layerName).at(4) != ",,,") {  // EX_GeographicBoundingBox
0676                     QStringList coords = wmsLayerMetaInfo.value(layerName).at(4).split(",");
0677                     double west = (coords.at(0).toDouble() * 20037508.34) / 180;
0678                     double south = 20037508.34 / M_PI * log(tan(((90 + coords.at(1).toDouble()) * M_PI) / 360));
0679                     double east = (coords.at(2).toDouble() * 20037508.34) / 180;
0680                     double north = 20037508.34 / M_PI * log(tan(((90 + coords.at(3).toDouble()) * M_PI) / 360));
0681                     QString bbox = QString("%1,%2,%3,%4").arg(QString::number( west, 'f', 6 )).arg(QString::number( south, 'f', 6 ))
0682                                                          .arg(QString::number( east, 'f', 6 )).arg(QString::number( north, 'f', 6 ));
0683                     wmsLayerCoordinateSystems[layerName]["epsg:3857"] = bbox;
0684                 }
0685                 else */
0686                     wmsLayerCoordinateSystems[layerName]["epsg:3857"] = QString();
0687             }
0688             if (projection.contains("epsg:4326")) {
0689 /*              if (wmsLayerMetaInfo.value(layerName).at(4) != ",,,") {
0690                     wmsLayerCoordinateSystems[layerName]["epsg:4326"] = wmsLayerMetaInfo.value(layerName).at(4); // Ignores flip
0691                 }
0692                 else */
0693                     wmsLayerCoordinateSystems[layerName]["epsg:4326"] = QString();
0694             }
0695             if (projection.contains("crs:84")) {
0696                     wmsLayerCoordinateSystems[layerName]["crs:84"] = QString();
0697             }
0698         }
0699         for ( int b = 0; b < layerPreviewBBox.size(); ++b ) {
0700             QDomElement bboxElement = layerPreviewBBox.at(b).toElement();
0701             QString bboxProjection = bboxElement.attribute(m_wmsCapabilities.referenceSystemType());
0702             if (bboxProjection != "epsg:3857" && bboxProjection != "epsg:4326"  && bboxProjection != "crs:84") continue;
0703             int precision = bboxProjection == "epsg:3857" ? 6 : 12;
0704             double west = bboxElement.attribute("minx").toDouble();
0705             double south = bboxElement.attribute("miny").toDouble();
0706             double east = bboxElement.attribute("maxx").toDouble();
0707             double north = bboxElement.attribute("maxy").toDouble();
0708             QString bboxString = QString("%1,%2,%3,%4")
0709             .arg(QString::number(west, 'f', precision),
0710                  QString::number(south, 'f', precision),
0711                  QString::number(east, 'f', precision),
0712                  QString::number(north, 'f', precision));
0713 //          TODO: convert bbox coordinates from UTM to 3857 (e.g. from epsg:25832/33)
0714             wmsLayerCoordinateSystems[layerName][bboxProjection] = bboxString;
0715         }
0716         // FIXME: parse EX_GeographicBoundingBox if wmsLayerCoordinateSystems[layerName]["epsg:4326"/"epsg:3857"] == QString()
0717     }
0718 
0719     m_wmsCapabilities.setWmsLayerCoordinateSystems(wmsLayerCoordinateSystems);
0720 
0721     QDomNodeList formatList = m_xml.documentElement().firstChildElement( "Capability" ).firstChildElement( "Request" )
0722             .firstChildElement( "GetMap" ).elementsByTagName("Format");
0723 
0724     QStringList formats;
0725     for ( int f = 0; f < formatList.size(); ++f ) {
0726         QString format = formatList.at(f).toElement().text();
0727         format = format.right(format.length() - format.indexOf(QLatin1Char('/')) - 1).toLower();
0728         if (format == "jpeg" || format.contains("png")
0729             || format.contains("tif") || format.contains("gif")
0730             || format.contains("bmp") || format.contains("jpg") ) {
0731             formats << format;
0732         }
0733     }
0734 
0735     m_wmsCapabilities.setFormats(formats);
0736 
0737     setCapabilitiesStatus(OwsCapabilitiesSuccess);
0738     emit wmsCapabilitiesReady();
0739 }
0740 
0741 void OwsServiceManager::parseWmtsCapabilities(QNetworkReply *reply)
0742 {
0743     Q_UNUSED(reply)
0744 
0745     m_wmsCapabilities.setVersion( m_xml.documentElement().firstChildElement("ows:ServiceIdentification").firstChildElement("ows:ServiceTypeVersion").text() );
0746 
0747     QDomElement service = m_xml.documentElement().firstChildElement( "ows:ServiceIdentification" );
0748     QDomNodeList layers = m_xml.documentElement().firstChildElement( "Contents" ).elementsByTagName("Layer");
0749 
0750     m_wmtsCapabilities.setTitle(service.firstChildElement( "ows:Title" ).text());
0751     m_wmtsCapabilities.setAbstract(service.firstChildElement( "ows:Abstract" ).text() );
0752 
0753     QMap<QString, QStringList> wmtsLayerMetaInfo;
0754     QMap<QString, QStringList> wmtsTileMatrixSets;
0755     QMap<QString, QMap<QString, QString>> wmtsTileResource;
0756 
0757     for( int i = 0; i < layers.size(); ++i )
0758     {
0759         QString name = layers.at(i).firstChildElement( "ows:Identifier" ).text();
0760         QString title = layers.at(i).firstChildElement( "ows:Title" ).text();
0761         QString abstract = layers.at(i ).firstChildElement( "ows:Abstract" ).text();
0762         QDomElement legendElement = layers.at( i ).firstChildElement( "Style" ).firstChildElement( "LegendURL" );
0763         QString legendUrl;
0764         if (!legendElement.isNull()) legendUrl = legendElement.attribute( "xlink:href" );
0765         QString style = layers.at(i).firstChildElement("Style").firstChildElement( "ows:Identifier" ).text();
0766 
0767         wmtsLayerMetaInfo[ name ] << title << abstract << legendUrl << style;
0768 
0769         QDomNodeList resourceList = layers.at(i).toElement().elementsByTagName("ResourceURL");
0770         for (int r = 0; r < resourceList.size(); ++r) {
0771             if (resourceList.at(r).toElement().attribute("resourceType") == "tile") {
0772                 QString format = resourceList.at(r).toElement().attribute("format");
0773                 QString resultFormat;
0774                 format = format.right(format.length() - format.indexOf(QLatin1Char('/')) - 1).toLower();
0775                 if (format == "jpeg" || format.contains("png")
0776                     || format.contains("tif") || format.contains("gif")
0777                     || format.contains("bmp") || format.contains("jpg") ) {
0778                     resultFormat = format;
0779                 }
0780                 else {
0781                     continue;
0782                 }
0783                 QString templ = resourceList.at(r).toElement().attribute("template");
0784                 wmtsTileResource[name][resultFormat] = templ;
0785             }
0786         }
0787 
0788         QStringList tileMatrixSets;
0789         QDomNodeList tileMatrixLinkList = layers.at(i).toElement().elementsByTagName("TileMatrixSetLink");
0790         for (int t = 0; t < tileMatrixLinkList.size(); ++t) {
0791             tileMatrixSets << tileMatrixLinkList.at(t).toElement().firstChildElement("TileMatrixSet").text();
0792         }
0793         wmtsTileMatrixSets[name] = tileMatrixSets;
0794     }
0795 
0796     m_wmtsCapabilities.setWmtsTileMatrixSets(wmtsTileMatrixSets);
0797     m_wmtsCapabilities.setWmtsTileResource(wmtsTileResource);
0798 
0799     m_wmtsCapabilities.setOwsLayerMetaInfo(wmtsLayerMetaInfo);
0800     setCapabilitiesStatus(OwsCapabilitiesSuccess);
0801     emit wmtsCapabilitiesReady();
0802 }
0803 
0804 void OwsServiceManager::parseImageResult(QNetworkReply *reply)
0805 {
0806     // QString request = reply->request().url().toString();
0807 
0808     // m_imageResult is already reset in the queryWmsMap
0809 
0810     QImage testImage;
0811     m_imageRequestResult.setResultRaw(reply->readAll());
0812     testImage = QImage::fromData(m_imageRequestResult.resultRaw());
0813 
0814     if (testImage.isNull()) {
0815         m_imageRequestResult.setImageStatus(WmsImageFailedServerMessage); // Image could not be downloaded
0816     }
0817     else if (m_imageRequestResult.resultRaw().isNull()) {
0818         m_imageRequestResult.setImageStatus(WmsImageFailed); // Image could not be downloaded
0819     }
0820     else {
0821         m_imageRequestResult.setImageStatus(WmsImageSuccess);
0822     }
0823 
0824     m_imageRequestResult.setResultImage(testImage);
0825 
0826     QByteArray resultRaw = m_imageRequestResult.resultRaw();
0827     QBuffer testBuffer( &resultRaw );
0828     m_imageRequestResult.setResultFormat(QImageReader( &testBuffer ).format());
0829 
0830     emit imageRequestResultReady();
0831 }
0832 
0833 }
0834 
0835 #include "moc_OwsServiceManager.cpp"