diff options
Diffstat (limited to 'src/plugins/geoservices/osm')
9 files changed, 542 insertions, 348 deletions
diff --git a/src/plugins/geoservices/osm/providers/5.8/street b/src/plugins/geoservices/osm/providers/5.8/street index 9819f619..b3bccf1d 100644 --- a/src/plugins/geoservices/osm/providers/5.8/street +++ b/src/plugins/geoservices/osm/providers/5.8/street @@ -1,9 +1,10 @@ { - "UrlTemplate" : "https://maps.wikimedia.org/osm-intl/%z/%x/%y@2x.png", - "ImageFormat" : "png", + "UrlTemplate" : "http://korona.geog.uni-heidelberg.de/tiles/roads/x=%x&y=%y&z=%z", + "ImageFormat" : "jpg", "QImageFormat" : "Indexed8", - "MaximumZoomLevel" : 18, - "ID" : "wmf-intl-2x", - "MapCopyRight" : "<a href='https://wikimediafoundation.org/wiki/Terms_of_Use'>WikiMedia Foundation</a>", + "ID" : "oms-street", + "MaximumZoomLevel" : 20, + "MapCopyRight" : "<a href='http://giscience.uni-hd.de/'>GIScience Research Group @ University of Heidelberg</a>", + "StyleCopyRight" : "<a href='http://www.geog.uni-heidelberg.de/personen/gis_rylov.html'>Maxim Rylov</a>", "DataCopyRight" : "<a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors" } diff --git a/src/plugins/geoservices/osm/providers/5.8/street-hires b/src/plugins/geoservices/osm/providers/5.8/street-hires new file mode 100644 index 00000000..9819f619 --- /dev/null +++ b/src/plugins/geoservices/osm/providers/5.8/street-hires @@ -0,0 +1,9 @@ +{ + "UrlTemplate" : "https://maps.wikimedia.org/osm-intl/%z/%x/%y@2x.png", + "ImageFormat" : "png", + "QImageFormat" : "Indexed8", + "MaximumZoomLevel" : 18, + "ID" : "wmf-intl-2x", + "MapCopyRight" : "<a href='https://wikimediafoundation.org/wiki/Terms_of_Use'>WikiMedia Foundation</a>", + "DataCopyRight" : "<a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors" +} diff --git a/src/plugins/geoservices/osm/qgeotiledmaposm.cpp b/src/plugins/geoservices/osm/qgeotiledmaposm.cpp index f16e602a..d94a40a6 100644 --- a/src/plugins/geoservices/osm/qgeotiledmaposm.cpp +++ b/src/plugins/geoservices/osm/qgeotiledmaposm.cpp @@ -71,10 +71,13 @@ void QGeoTiledMapOsm::evaluateCopyrights(const QSet<QGeoTileSpec> &visibleTiles) return; int providerId = tile.mapId() - 1; - if (providerId < 0 || providerId >= m_engine->providers().size() || !m_engine->providers().at(providerId)->isValid()) + if (providerId < 0 || providerId >= m_engine->providers().size()) return; m_mapId = tile.mapId(); + if (!m_engine->providers().at(providerId)->isValid()) + return; + onProviderDataUpdated(m_engine->providers().at(providerId)); } diff --git a/src/plugins/geoservices/osm/qgeotiledmappingmanagerengineosm.cpp b/src/plugins/geoservices/osm/qgeotiledmappingmanagerengineosm.cpp index 4f25204a..152df9b6 100644 --- a/src/plugins/geoservices/osm/qgeotiledmappingmanagerengineosm.cpp +++ b/src/plugins/geoservices/osm/qgeotiledmappingmanagerengineosm.cpp @@ -73,66 +73,93 @@ QGeoTiledMappingManagerEngineOsm::QGeoTiledMappingManagerEngineOsm(const QVarian domain = customAddress; } - m_providers.push_back( - new QGeoTileProviderOsm(domain + "street", - nm, + bool highdpi = false; + if (parameters.contains(QStringLiteral("osm.mapping.highdpi_tiles"))) { + const QString param = parameters.value(QStringLiteral("osm.mapping.highdpi_tiles")).toString().toLower(); + if (param == "true") + highdpi = true; + } + + /* TileProviders setup */ + QVector<TileProvider *> providers_street; + QVector<TileProvider *> providers_satellite; + QVector<TileProvider *> providers_cycle; + QVector<TileProvider *> providers_transit; + QVector<TileProvider *> providers_nighttransit; + QVector<TileProvider *> providers_terrain; + QVector<TileProvider *> providers_hiking; + if (highdpi) { + providers_street.push_back(new TileProvider(domain + "street-hires")); + providers_satellite.push_back(new TileProvider(domain + "satellite-hires")); + providers_cycle.push_back(new TileProvider(domain + "cycle-hires")); + providers_transit.push_back(new TileProvider(domain + "transit-hires")); + providers_nighttransit.push_back(new TileProvider(domain + "night-transit-hires")); + providers_terrain.push_back(new TileProvider(domain + "terrain-hires")); + providers_hiking.push_back(new TileProvider(domain + "hiking-hires")); + } + providers_street.push_back(new TileProvider(domain + "street")); + providers_satellite.push_back(new TileProvider(domain + "satellite")); + providers_cycle.push_back(new TileProvider(domain + "cycle")); + providers_transit.push_back(new TileProvider(domain + "transit")); + providers_nighttransit.push_back(new TileProvider(domain + "night-transit")); + providers_terrain.push_back(new TileProvider(domain + "terrain")); + providers_hiking.push_back(new TileProvider(domain + "hiking")); + // Backups + providers_street.push_back( + new TileProvider(QStringLiteral("http://c.tile.openstreetmap.org/%z/%x/%y.png"), + QStringLiteral("png"), + QStringLiteral("<a href='http://www.openstreetmap.org/copyright'>OpenStreetMap.org</a>"), + QStringLiteral("<a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors"))); + // No available satellite backup + providers_cycle.push_back( + new TileProvider(QStringLiteral("http://c.tile.opencyclemap.org/cycle/%z/%x/%y.png"), + QStringLiteral("png"), + QStringLiteral("<a href='http://www.thunderforest.com/'>Thunderforest</a>"), + QStringLiteral("<a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors"))); + providers_transit.push_back( + new TileProvider(QStringLiteral("http://c.tile2.opencyclemap.org/transport/%z/%x/%y.png"), + QStringLiteral("png"), + QStringLiteral("<a href='http://www.thunderforest.com/'>Thunderforest</a>"), + QStringLiteral("<a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors"))); + providers_nighttransit.push_back( + new TileProvider(QStringLiteral("http://a.tile.thunderforest.com/transport-dark/%z/%x/%y.png"), + QStringLiteral("png"), + QStringLiteral("<a href='http://www.thunderforest.com/'>Thunderforest</a>"), + QStringLiteral("<a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors")) ); + providers_terrain.push_back( + new TileProvider(QStringLiteral("http://a.tile.thunderforest.com/landscape/%z/%x/%y.png"), + QStringLiteral("png"), + QStringLiteral("<a href='http://www.thunderforest.com/'>Thunderforest</a>"), + QStringLiteral("<a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors"))); + providers_hiking.push_back( + new TileProvider(QStringLiteral("http://a.tile.thunderforest.com/outdoors/%z/%x/%y.png"), + QStringLiteral("png"), + QStringLiteral("<a href='http://www.thunderforest.com/'>Thunderforest</a>"), + QStringLiteral("<a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors"))); + + + /* QGeoTileProviderOsms setup */ + m_providers.push_back( new QGeoTileProviderOsm( nm, QGeoMapType(QGeoMapType::StreetMap, tr("Street Map"), tr("Street map view in daylight mode"), false, false, 1), - QGeoTileProviderOsm::TileProvider(QStringLiteral("http://c.tile.openstreetmap.org/%z/%x/%y.png"), - QStringLiteral("png"), - QStringLiteral("<a href='http://www.openstreetmap.org/copyright'>OpenStreetMap.org</a>"), - QStringLiteral("<a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors") - ))); - m_providers.push_back( - new QGeoTileProviderOsm(domain + "satellite", - nm, + providers_street )); + m_providers.push_back( new QGeoTileProviderOsm( nm, QGeoMapType(QGeoMapType::SatelliteMapDay, tr("Satellite Map"), tr("Satellite map view in daylight mode"), false, false, 2), - QGeoTileProviderOsm::TileProvider() - )); - m_providers.push_back( - new QGeoTileProviderOsm(domain + "cycle", - nm, + providers_satellite )); + m_providers.push_back( new QGeoTileProviderOsm( nm, QGeoMapType(QGeoMapType::CycleMap, tr("Cycle Map"), tr("Cycle map view in daylight mode"), false, false, 3), - QGeoTileProviderOsm::TileProvider(QStringLiteral("http://c.tile.opencyclemap.org/cycle/%z/%x/%y.png"), - QStringLiteral("png"), - QStringLiteral("<a href='http://www.thunderforest.com/'>Thunderforest</a>"), - QStringLiteral("<a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors") - ))); - m_providers.push_back( - new QGeoTileProviderOsm(domain + "transit", - nm, + providers_cycle )); + m_providers.push_back( new QGeoTileProviderOsm( nm, QGeoMapType(QGeoMapType::TransitMap, tr("Transit Map"), tr("Public transit map view in daylight mode"), false, false, 4), - QGeoTileProviderOsm::TileProvider(QStringLiteral("http://c.tile2.opencyclemap.org/transport/%z/%x/%y.png"), - QStringLiteral("png"), - QStringLiteral("<a href='http://www.thunderforest.com/'>Thunderforest</a>"), - QStringLiteral("<a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors") - ))); - m_providers.push_back( - new QGeoTileProviderOsm(domain + "night-transit", - nm, + providers_transit )); + m_providers.push_back( new QGeoTileProviderOsm( nm, QGeoMapType(QGeoMapType::TransitMap, tr("Night Transit Map"), tr("Public transit map view in night mode"), false, true, 5), - QGeoTileProviderOsm::TileProvider(QStringLiteral("http://a.tile.thunderforest.com/transport-dark/%z/%x/%y.png"), - QStringLiteral("png"), - QStringLiteral("<a href='http://www.thunderforest.com/'>Thunderforest</a>"), - QStringLiteral("<a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors") - ))); - m_providers.push_back( - new QGeoTileProviderOsm(domain + "terrain", - nm, + providers_nighttransit )); + m_providers.push_back( new QGeoTileProviderOsm( nm, QGeoMapType(QGeoMapType::TerrainMap, tr("Terrain Map"), tr("Terrain map view"), false, false, 6), - QGeoTileProviderOsm::TileProvider(QStringLiteral("http://a.tile.thunderforest.com/landscape/%z/%x/%y.png"), - QStringLiteral("png"), - QStringLiteral("<a href='http://www.thunderforest.com/'>Thunderforest</a>"), - QStringLiteral("<a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors") - ))); - m_providers.push_back( - new QGeoTileProviderOsm(domain + "hiking", - nm, + providers_terrain )); + m_providers.push_back( new QGeoTileProviderOsm( nm, QGeoMapType(QGeoMapType::PedestrianMap, tr("Hiking Map"), tr("Hiking map view"), false, false, 7), - QGeoTileProviderOsm::TileProvider(QStringLiteral("http://a.tile.thunderforest.com/outdoors/%z/%x/%y.png"), - QStringLiteral("png"), - QStringLiteral("<a href='http://www.thunderforest.com/'>Thunderforest</a>"), - QStringLiteral("<a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors") - ))); + providers_hiking )); if (parameters.contains(QStringLiteral("osm.mapping.custom.host")) || parameters.contains(QStringLiteral("osm.mapping.host"))) { @@ -154,14 +181,13 @@ QGeoTiledMappingManagerEngineOsm::QGeoTiledMappingManagerEngineOsm(const QVarian m_customCopyright = parameters.value(QStringLiteral("osm.mapping.copyright")).toString(); m_providers.push_back( - new QGeoTileProviderOsm("", - nm, + new QGeoTileProviderOsm( nm, QGeoMapType(QGeoMapType::CustomMap, tr("Custom URL Map"), tr("Custom url map view set via urlprefix parameter"), false, false, 8), - QGeoTileProviderOsm::TileProvider(tmsServer + QStringLiteral("%z/%x/%y.png"), + { new TileProvider(tmsServer + QStringLiteral("%z/%x/%y.png"), QStringLiteral("png"), mapCopyright, - dataCopyright - ))); + dataCopyright) } + )); m_providers.last()->disableRedirection(); } @@ -257,9 +283,8 @@ void QGeoTiledMappingManagerEngineOsm::onProviderResolutionFinished(const QGeoTi updateMapTypes(); } -void QGeoTiledMappingManagerEngineOsm::onProviderResolutionError(const QGeoTileProviderOsm *provider, QNetworkReply::NetworkError error) +void QGeoTiledMappingManagerEngineOsm::onProviderResolutionError(const QGeoTileProviderOsm *provider) { - Q_UNUSED(error) if (!provider->isResolved()) return; updateMapTypes(); diff --git a/src/plugins/geoservices/osm/qgeotiledmappingmanagerengineosm.h b/src/plugins/geoservices/osm/qgeotiledmappingmanagerengineosm.h index 7536e655..b1f0a13c 100644 --- a/src/plugins/geoservices/osm/qgeotiledmappingmanagerengineosm.h +++ b/src/plugins/geoservices/osm/qgeotiledmappingmanagerengineosm.h @@ -65,7 +65,7 @@ public: protected Q_SLOTS: void onProviderResolutionFinished(const QGeoTileProviderOsm *provider); - void onProviderResolutionError(const QGeoTileProviderOsm *provider, QNetworkReply::NetworkError error); + void onProviderResolutionError(const QGeoTileProviderOsm *provider); protected: void updateMapTypes(); diff --git a/src/plugins/geoservices/osm/qgeotilefetcherosm.cpp b/src/plugins/geoservices/osm/qgeotilefetcherosm.cpp index 98621411..0d7fa58e 100644 --- a/src/plugins/geoservices/osm/qgeotilefetcherosm.cpp +++ b/src/plugins/geoservices/osm/qgeotilefetcherosm.cpp @@ -100,9 +100,8 @@ void QGeoTileFetcherOsm::onProviderResolutionFinished(const QGeoTileProviderOsm emit providerDataUpdated(provider); } -void QGeoTileFetcherOsm::onProviderResolutionError(const QGeoTileProviderOsm *provider, QNetworkReply::NetworkError error) +void QGeoTileFetcherOsm::onProviderResolutionError(const QGeoTileProviderOsm *provider) { - Q_UNUSED(error) if ((m_ready = providersResolved(m_providers))) { qWarning("QGeoTileFetcherOsm: all providers resolved"); readyUpdated(); diff --git a/src/plugins/geoservices/osm/qgeotilefetcherosm.h b/src/plugins/geoservices/osm/qgeotilefetcherosm.h index 8d69cc56..c3f33faa 100644 --- a/src/plugins/geoservices/osm/qgeotilefetcherosm.h +++ b/src/plugins/geoservices/osm/qgeotilefetcherosm.h @@ -69,7 +69,7 @@ protected: protected Q_SLOTS: void onProviderResolutionFinished(const QGeoTileProviderOsm *provider); - void onProviderResolutionError(const QGeoTileProviderOsm *provider, QNetworkReply::NetworkError error); + void onProviderResolutionError(const QGeoTileProviderOsm *provider); private: QGeoTiledMapReply *getTileImage(const QGeoTileSpec &spec); diff --git a/src/plugins/geoservices/osm/qgeotileproviderosm.cpp b/src/plugins/geoservices/osm/qgeotileproviderosm.cpp index 3d46a425..afa8e45f 100644 --- a/src/plugins/geoservices/osm/qgeotileproviderosm.cpp +++ b/src/plugins/geoservices/osm/qgeotileproviderosm.cpp @@ -44,150 +44,271 @@ QT_BEGIN_NAMESPACE static const int maxValidZoom = 30; -QGeoTileProviderOsm::QGeoTileProviderOsm(const QString &urlRedir, - QNetworkAccessManager *nm, - const QGeoMapType &mapType, - const QGeoTileProviderOsm::TileProvider &providerFallback) - : m_nm(nm), m_urlRedirector(urlRedir), - m_providerFallback(providerFallback), - m_mapType(mapType), m_status(Idle) +QGeoTileProviderOsm::QGeoTileProviderOsm(QNetworkAccessManager *nm, + const QGeoMapType &mapType, + const QVector<TileProvider *> &providers) +: m_nm(nm), m_provider(nullptr), m_mapType(mapType), m_status(Idle) { - if (!m_urlRedirector.isValid()) - disableRedirection(); + for (int i = 0; i < providers.size(); ++i) { + TileProvider *p = providers[i]; + if (!m_provider) + m_providerId = i; + addProvider(p); + } + + if (!m_provider || m_provider->isValid()) + m_status = Resolved; } QGeoTileProviderOsm::~QGeoTileProviderOsm() { +} + +QUrl QGeoTileProviderOsm::tileAddress(int x, int y, int z) const +{ + if (m_status != Resolved || !m_provider) + return QUrl(); + return m_provider->tileAddress(x, y, z); +} + +QString QGeoTileProviderOsm::mapCopyRight() const +{ + if (m_status != Resolved || !m_provider) + return QString(); + return m_provider->mapCopyRight(); +} + +QString QGeoTileProviderOsm::dataCopyRight() const +{ + if (m_status != Resolved || !m_provider) + return QString(); + return m_provider->dataCopyRight(); +} + +QString QGeoTileProviderOsm::styleCopyRight() const +{ + if (m_status != Resolved || !m_provider) + return QString(); + return m_provider->styleCopyRight(); +} + +QString QGeoTileProviderOsm::format() const +{ + if (m_status != Resolved || !m_provider) + return QString(); + return m_provider->format(); +} + +const QGeoMapType &QGeoTileProviderOsm::mapType() const +{ + return m_mapType; +} + +bool QGeoTileProviderOsm::isValid() const +{ + if (m_status != Resolved || !m_provider) + return false; + return m_provider->isValid(); +} +bool QGeoTileProviderOsm::isResolved() const +{ + return (m_status == Resolved); } void QGeoTileProviderOsm::resolveProvider() { - switch (m_status) { - case Resolving: - case Invalid: - case Valid: - return; - case Idle: - m_status = Resolving; - break; - } + if (m_status == Resolved || m_status == Resolving) + return; - QNetworkRequest request; - request.setHeader(QNetworkRequest::UserAgentHeader, QByteArrayLiteral("QGeoTileFetcherOsm")); - request.setUrl(m_urlRedirector); - QNetworkReply *reply = m_nm->get(request); - connect(reply, SIGNAL(finished()), this, SLOT(onNetworkReplyFinished())); - connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), - this, SLOT(onNetworkReplyError(QNetworkReply::NetworkError))); + m_status = Resolving; + // Provider can't be null while on Idle status. + connect(m_provider, &TileProvider::resolutionFinished, this, &QGeoTileProviderOsm::onResolutionFinished); + connect(m_provider, &TileProvider::resolutionError, this, &QGeoTileProviderOsm::onResolutionError); + m_provider->resolveProvider(); } void QGeoTileProviderOsm::disableRedirection() { - m_status = Invalid; - m_provider.m_valid = false; + if (m_provider && m_provider->isValid()) + return; + bool found = false; + for (TileProvider *p: m_providerList) { + if (p->isValid() && !found) { + m_provider = p; + found = true; + } + p->disconnect(this); + } } -void QGeoTileProviderOsm::handleError(QNetworkReply::NetworkError error) +void QGeoTileProviderOsm::onResolutionFinished(TileProvider *provider) { - switch (error) { - case QNetworkReply::ConnectionRefusedError: - case QNetworkReply::TooManyRedirectsError: - case QNetworkReply::InsecureRedirectError: - case QNetworkReply::ContentAccessDenied: - case QNetworkReply::ContentOperationNotPermittedError: - case QNetworkReply::ContentNotFoundError: - case QNetworkReply::AuthenticationRequiredError: - case QNetworkReply::ContentGoneError: - case QNetworkReply::OperationNotImplementedError: - case QNetworkReply::ServiceUnavailableError: - // Errors we don't expect to recover from in the near future, which - // prevent accessing the redirection info but not the actual providers. - m_status = Invalid; - default: - break; + Q_UNUSED(provider) + // provider and m_provider are the same, at this point. m_status is Resolving. + m_status = Resolved; + emit resolutionFinished(this); +} + +void QGeoTileProviderOsm::onResolutionError(TileProvider *provider) +{ + Q_UNUSED(provider) + // provider and m_provider are the same at this point. m_status is Resolving. + if (m_provider->isInvalid()) { + m_provider = nullptr; + m_status = Resolved; + if (m_providerId >= m_providerList.size() -1) { // no hope left + emit resolutionError(this); + return; + } + // Advance the pointer in the provider list, and possibly start resolution on the next in the list. + for (int i = m_providerId + 1; i < m_providerList.size(); ++i) { + m_providerId = i; + TileProvider *p = m_providerList[m_providerId]; + if (!p->isInvalid()) { + m_provider = p; + if (!p->isValid()) { + m_status = Idle; + //m_status = Resolving; + //p->resolveProvider(); + } + } + } + if (!m_provider) + emit resolutionError(this); + } else if (m_provider->isValid()) { + m_status = Resolved; + emit resolutionFinished(this); + } else { // still not resolved. But network error is recoverable. + m_status = Idle; + //m_provider->resolveProvider(); } } -QUrl QGeoTileProviderOsm::tileAddress(int x, int y, int z) const +void QGeoTileProviderOsm::addProvider(TileProvider *provider) { - if (m_provider.isValid()) - return m_provider.tileAddress(x,y,z); - if (m_providerFallback.isValid()) - return m_providerFallback.tileAddress(x,y,z); - return QUrl(); + if (!provider) + return; + QScopedPointer<TileProvider> p(provider); + if (provider->status() == TileProvider::Invalid) + return; // if the provider is already resolved and invalid, no point in adding it. + + provider = p.take(); + provider->setNetworkManager(m_nm); + provider->setParent(this); + m_providerList.append(provider); + if (!m_provider) + m_provider = provider; } -QString QGeoTileProviderOsm::mapCopyRight() const + +/* + QGeoTileProviderOsm::TileProvder +*/ + +static void sort2(int &a, int &b) { - if (m_provider.isValid()) - return m_provider.mapCopyRight(); - if (m_providerFallback.isValid()) - return m_providerFallback.mapCopyRight(); - return QString(); + if (a > b) { + int temp=a; + a=b; + b=temp; + } } -QString QGeoTileProviderOsm::dataCopyRight() const +TileProvider::TileProvider() : m_status(Invalid), m_nm(nullptr) { - if (m_provider.isValid()) - return m_provider.dataCopyRight(); - if (m_providerFallback.isValid()) - return m_providerFallback.dataCopyRight(); - return QString(); + } -QString QGeoTileProviderOsm::styleCopyRight() const +TileProvider::TileProvider(const QUrl &urlRedirector) : m_status(Idle), m_urlRedirector(urlRedirector), m_nm(nullptr) { - if (m_provider.isValid()) - return m_provider.styleCopyRight(); - if (m_providerFallback.isValid()) - return m_providerFallback.styleCopyRight(); - return QString(); + if (!m_urlRedirector.isValid()) + m_status = Invalid; } -QString QGeoTileProviderOsm::format() const +TileProvider::TileProvider(const QString &urlTemplate, + const QString &format, + const QString ©RightMap, + const QString ©RightData, + int minimumZoomLevel, + int maximumZoomLevel) +: m_status(Invalid), m_nm(nullptr), m_urlTemplate(urlTemplate), + m_format(format), m_copyRightMap(copyRightMap), m_copyRightData(copyRightData), + m_minimumZoomLevel(minimumZoomLevel), m_maximumZoomLevel(maximumZoomLevel) { - if (m_provider.isValid()) - return m_provider.format(); - if (m_providerFallback.isValid()) - return m_providerFallback.format(); - return QString(); + setupProvider(); } -const QGeoMapType &QGeoTileProviderOsm::mapType() const +TileProvider::~TileProvider() { - return m_mapType; } -bool QGeoTileProviderOsm::isValid() const +void TileProvider::resolveProvider() { - return (m_provider.isValid() || m_providerFallback.isValid()); + if (!m_nm) + return; + + switch (m_status) { + case Resolving: + case Invalid: + case Valid: + return; + case Idle: + m_status = Resolving; + break; + } + + QNetworkRequest request; + request.setHeader(QNetworkRequest::UserAgentHeader, QByteArrayLiteral("QGeoTileFetcherOsm")); + request.setUrl(m_urlRedirector); + QNetworkReply *reply = m_nm->get(request); + connect(reply, SIGNAL(finished()), this, SLOT(onNetworkReplyFinished()) ); + connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onNetworkReplyError(QNetworkReply::NetworkError))); } -bool QGeoTileProviderOsm::isResolved() const +void TileProvider::handleError(QNetworkReply::NetworkError error) { - return (m_status == Valid || m_status == Invalid); + switch (error) { + case QNetworkReply::ConnectionRefusedError: + case QNetworkReply::TooManyRedirectsError: + case QNetworkReply::InsecureRedirectError: + case QNetworkReply::ContentAccessDenied: + case QNetworkReply::ContentOperationNotPermittedError: + case QNetworkReply::ContentNotFoundError: + case QNetworkReply::AuthenticationRequiredError: + case QNetworkReply::ContentGoneError: + case QNetworkReply::OperationNotImplementedError: + case QNetworkReply::ServiceUnavailableError: + // Errors we don't expect to recover from in the near future, which + // prevent accessing the redirection info but not the actual providers. + qWarning() << "QGeoTileProviderOsm network error:" << error; + m_status = Invalid; + default: + break; + } } -void QGeoTileProviderOsm::onNetworkReplyFinished() +void TileProvider::onNetworkReplyFinished() { QNetworkReply *reply = static_cast<QNetworkReply *>(sender()); reply->deleteLater(); switch (m_status) { - case Resolving: - m_status = Idle; - case Idle: // should not happen - case Invalid: // should not happen - break; - case Valid: // should not happen - return; + case Resolving: + m_status = Idle; + case Idle: // should not happen + case Invalid: // should not happen + break; + case Valid: // should not happen + emit resolutionFinished(this); + return; } + QObject errorEmitter; + QMetaObject::Connection errorEmitterConnection = connect(&errorEmitter, &QObject::destroyed, [this](){ this->resolutionError(this); }); + if (reply->error() != QNetworkReply::NoError) { handleError(reply->error()); - if (m_status == Invalid) - emit resolutionError(this, reply->error()); return; } m_status = Invalid; @@ -241,12 +362,10 @@ void QGeoTileProviderOsm::onNetworkReplyFinished() QJsonDocument d = QJsonDocument::fromJson(reply->readAll(), &error); if (error.error != QJsonParseError::NoError) { qWarning() << "QGeoTileProviderOsm: Error parsing redirection data: "<<error.errorString() << "at "<<m_urlRedirector; - emit resolutionFinished(this); return; } if (!d.isObject()) { qWarning() << "QGeoTileProviderOsm: Invalid redirection data" << "at "<<m_urlRedirector; - emit resolutionFinished(this); return; } const QJsonObject json = d.object(); @@ -263,56 +382,175 @@ void QGeoTileProviderOsm::onNetworkReplyFinished() || !copyRightMap.isString() || !copyRightData.isString()) { qWarning() << "QGeoTileProviderOsm: Incomplete redirection data" << "at "<<m_urlRedirector; - emit resolutionFinished(this); return; } + m_urlTemplate = urlTemplate.toString(); + m_format = imageFormat.toString(); + m_copyRightMap = copyRightMap.toString(); + m_copyRightData = copyRightData.toString(); + const QJsonValue enabled = json.value(QLatin1String("Enabled")); if (enabled.isBool() && ! enabled.toBool()) { qWarning() << "QGeoTileProviderOsm: Tileserver disabled" << "at "<<m_urlRedirector; - emit resolutionFinished(this); return; } - QString styleCopyRight; const QJsonValue copyRightStyle = json.value(QLatin1String("StyleCopyRight")); if (copyRightStyle != QJsonValue::Undefined && copyRightStyle.isString()) - styleCopyRight = copyRightStyle.toString(); + m_copyRightStyle = copyRightStyle.toString(); - int minZL = 0; - int maxZL = 19; + m_minimumZoomLevel = 0; + m_maximumZoomLevel = 19; const QJsonValue minZoom = json.value(QLatin1String("MinimumZoomLevel")); if (minZoom.isDouble()) - minZL = qBound(0, int(minZoom.toDouble()), maxValidZoom); + m_minimumZoomLevel = qBound(0, int(minZoom.toDouble()), maxValidZoom); const QJsonValue maxZoom = json.value(QLatin1String("MaximumZoomLevel")); if (maxZoom.isDouble()) - maxZL = qBound(0, int(maxZoom.toDouble()), maxValidZoom); - - m_provider = TileProvider(urlTemplate.toString(), - imageFormat.toString(), - copyRightMap.toString(), - copyRightData.toString(), - minZL, - maxZL); - m_provider.setStyleCopyRight(styleCopyRight); - - if (m_provider.isValid()) - m_status = Valid; + m_maximumZoomLevel = qBound(0, int(maxZoom.toDouble()), maxValidZoom); - emit resolutionFinished(this); + setupProvider(); + if (isValid()) { + QObject::disconnect(errorEmitterConnection); + emit resolutionFinished(this); + } } -void QGeoTileProviderOsm::onNetworkReplyError(QNetworkReply::NetworkError error) +void TileProvider::onNetworkReplyError(QNetworkReply::NetworkError error) { if (m_status == Resolving) m_status = Idle; - qWarning() << "QGeoTileProviderOsm::onNetworkReplyError " << error; handleError(error); - static_cast<QNetworkReply *>(sender())->deleteLater(); - if (m_status == Invalid) - emit resolutionError(this, error); + emit resolutionError(this); +} + +void TileProvider::setupProvider() +{ + if (m_urlTemplate.isEmpty()) + return; + + if (m_format.isEmpty()) + return; + + if (m_minimumZoomLevel < 0 || m_minimumZoomLevel > 30) + return; + + if (m_maximumZoomLevel < 0 || m_maximumZoomLevel > 30 || m_maximumZoomLevel < m_minimumZoomLevel) + return; + + // Currently supporting only %x, %y and &z + int offset[3]; + offset[0] = m_urlTemplate.indexOf(QLatin1String("%x")); + if (offset[0] < 0) + return; + + offset[1] = m_urlTemplate.indexOf(QLatin1String("%y")); + if (offset[1] < 0) + return; + + offset[2] = m_urlTemplate.indexOf(QLatin1String("%z")); + if (offset[2] < 0) + return; + + int sortedOffsets[3]; + std::copy(offset, offset + 3, sortedOffsets); + sort2(sortedOffsets[0] ,sortedOffsets[1]); + sort2(sortedOffsets[1] ,sortedOffsets[2]); + sort2(sortedOffsets[0] ,sortedOffsets[1]); + + int min = sortedOffsets[0]; + int max = sortedOffsets[2]; + int mid = sortedOffsets[1]; + + // Initing LUT + for (int i=0; i<3; i++) { + if (offset[0] == sortedOffsets[i]) + paramsLUT[i] = 0; + else if (offset[1] == sortedOffsets[i]) + paramsLUT[i] = 1; + else + paramsLUT[i] = 2; + } + + m_urlPrefix = m_urlTemplate.mid(0 , min); + m_urlSuffix = m_urlTemplate.mid(max + 2, m_urlTemplate.size() - max - 2); + + paramsSep[0] = m_urlTemplate.mid(min + 2, mid - min - 2); + paramsSep[1] = m_urlTemplate.mid(mid + 2, max - mid - 2); + m_status = Valid; } +bool TileProvider::isValid() const +{ + return m_status == Valid; +} + +bool TileProvider::isInvalid() const +{ + return m_status == Invalid; +} + +bool TileProvider::isResolved() const +{ + return (m_status == Valid || m_status == Invalid); +} + +QString TileProvider::mapCopyRight() const +{ + return m_copyRightMap; +} + +QString TileProvider::dataCopyRight() const +{ + return m_copyRightData; +} + +QString TileProvider::styleCopyRight() const +{ + return m_copyRightStyle; +} + +QString TileProvider::format() const +{ + return m_format; +} + +void TileProvider::setStyleCopyRight(const QString ©right) +{ + m_copyRightStyle = copyright; +} + +QUrl TileProvider::tileAddress(int x, int y, int z) const +{ + if (z < m_minimumZoomLevel || z > m_maximumZoomLevel) + return QUrl(); + int params[3] = { x, y, z}; + QString url; + url += m_urlPrefix; + url += QString::number(params[paramsLUT[0]]); + url += paramsSep[0]; + url += QString::number(params[paramsLUT[1]]); + url += paramsSep[1]; + url += QString::number(params[paramsLUT[2]]); + url += m_urlSuffix; + return QUrl(url); +} + +void TileProvider::setNetworkManager(QNetworkAccessManager *nm) +{ + m_nm = nm; +} + +TileProvider::Status TileProvider::status() const +{ + return m_status; +} + + QT_END_NAMESPACE + + + + diff --git a/src/plugins/geoservices/osm/qgeotileproviderosm.h b/src/plugins/geoservices/osm/qgeotileproviderosm.h index f396b3b5..d9f80482 100644 --- a/src/plugins/geoservices/osm/qgeotileproviderosm.h +++ b/src/plugins/geoservices/osm/qgeotileproviderosm.h @@ -40,186 +40,102 @@ #include <QtLocation/private/qgeomaptype_p.h> #include <QtCore/QUrl> +#include <QtCore/QVector> #include <QtNetwork/QNetworkAccessManager> #include <QtNetwork/QNetworkReply> #include <QtCore/QPointer> #include <QTimer> #include <algorithm> +#include <QtCore/QJsonDocument> +#include <QtCore/QJsonObject> QT_BEGIN_NAMESPACE -class QGeoTileProviderOsm: public QObject +class TileProvider: public QObject { Q_OBJECT - - friend class QGeoTileFetcherOsm; - friend class QGeoMapReplyOsm; - friend class QGeoTiledMappingManagerEngineOsm; public: - struct TileProvider { - - static inline void sort2(int &a, int &b) - { - if (a > b) { - int temp=a; - a=b; - b=temp; - } - } - - TileProvider() : m_valid(false) - { - - } - - TileProvider(const QString &urlTemplate, - const QString &format, - const QString ©RightMap, - const QString ©RightData, - int minimumZoomLevel = 0, - int maximumZoomLevel = 19) : m_valid(false) - { - if (urlTemplate.isEmpty()) - return; - m_urlTemplate = urlTemplate; - - if (format.isEmpty()) - return; - m_format = format; - - m_copyRightMap = copyRightMap; - m_copyRightData = copyRightData; - - if (minimumZoomLevel < 0 || minimumZoomLevel > 30) - return; - m_minimumZoomLevel = minimumZoomLevel; - - if (maximumZoomLevel < 0 || maximumZoomLevel > 30 || maximumZoomLevel < minimumZoomLevel) - return; - m_maximumZoomLevel = maximumZoomLevel; - - // Currently supporting only %x, %y and &z - int offset[3]; - offset[0] = m_urlTemplate.indexOf(QLatin1String("%x")); - if (offset[0] < 0) - return; - - offset[1] = m_urlTemplate.indexOf(QLatin1String("%y")); - if (offset[1] < 0) - return; - - offset[2] = m_urlTemplate.indexOf(QLatin1String("%z")); - if (offset[2] < 0) - return; - - int sortedOffsets[3]; - std::copy(offset, offset + 3, sortedOffsets); - sort2(sortedOffsets[0] ,sortedOffsets[1]); - sort2(sortedOffsets[1] ,sortedOffsets[2]); - sort2(sortedOffsets[0] ,sortedOffsets[1]); - - int min = sortedOffsets[0]; - int max = sortedOffsets[2]; - int mid = sortedOffsets[1]; - - // Initing LUT - for (int i=0; i<3; i++) { - if (offset[0] == sortedOffsets[i]) - paramsLUT[i] = 0; - else if (offset[1] == sortedOffsets[i]) - paramsLUT[i] = 1; - else - paramsLUT[i] = 2; - } - - m_urlPrefix = m_urlTemplate.mid(0 , min); - m_urlSuffix = m_urlTemplate.mid(max + 2, m_urlTemplate.size() - max - 2); + enum Status {Idle, + Resolving, + Valid, + Invalid }; - paramsSep[0] = m_urlTemplate.mid(min + 2, mid - min - 2); - paramsSep[1] = m_urlTemplate.mid(mid + 2, max - mid - 2); - m_valid = true; - } + TileProvider(); + // "Online" constructor. Needs resolution to fetch the parameters + TileProvider(const QUrl &urlRedirector); + // Offline constructor. Doesn't need URLRedirector and networkmanager + TileProvider(const QString &urlTemplate, + const QString &format, + const QString ©RightMap, + const QString ©RightData, + int minimumZoomLevel = 0, + int maximumZoomLevel = 19); - ~TileProvider() - { - } + ~TileProvider(); + void setNetworkManager(QNetworkAccessManager *nm); - inline bool isValid() const - { - return m_valid; - } + void resolveProvider(); + void handleError(QNetworkReply::NetworkError error); + void setupProvider(); - inline QString mapCopyRight() const - { - return m_copyRightMap; - } + inline bool isValid() const; + inline bool isInvalid() const; + inline bool isResolved() const; + inline Status status() const; - inline QString dataCopyRight() const - { - return m_copyRightData; - } + inline QString mapCopyRight() const; + inline QString dataCopyRight() const; + inline QString styleCopyRight() const; + inline QString format() const; + QUrl tileAddress(int x, int y, int z) const; - inline QString styleCopyRight() const - { - return m_copyRightStyle; - } + // Optional properties, not needed to construct a provider + void setStyleCopyRight(const QString ©right); - inline QString format() const - { - return m_format; - } + Status m_status; + QUrl m_urlRedirector; // The URL from where to fetch the URL template in case of a provider to resolve. + QNetworkAccessManager *m_nm; + QString m_urlTemplate; + QString m_format; + QString m_copyRightMap; + QString m_copyRightData; + QString m_copyRightStyle; + QString m_urlPrefix; + QString m_urlSuffix; + int m_minimumZoomLevel; + int m_maximumZoomLevel; + + int paramsLUT[3]; //Lookup table to handle possibly shuffled x,y,z + QString paramsSep[2]; // what goes in between %x, %y and %z - // Optional properties, not needed to construct a provider - void setStyleCopyRight(const QString ©right) - { - m_copyRightStyle = copyright; - } +Q_SIGNALS: + void resolutionFinished(TileProvider *provider); + void resolutionError(TileProvider *provider); - QUrl tileAddress(int x, int y, int z) const - { - if (z < m_minimumZoomLevel || z > m_maximumZoomLevel) - return QUrl(); - int params[3] = { x, y, z}; - QString url; - url += m_urlPrefix; - url += QString::number(params[paramsLUT[0]]); - url += paramsSep[0]; - url += QString::number(params[paramsLUT[1]]); - url += paramsSep[1]; - url += QString::number(params[paramsLUT[2]]); - url += m_urlSuffix; - return QUrl(url); - } +public Q_SLOTS: + void onNetworkReplyFinished(); + void onNetworkReplyError(QNetworkReply::NetworkError error); - bool m_valid; - QString m_urlTemplate; - QString m_format; - QString m_copyRightMap; - QString m_copyRightData; - QString m_copyRightStyle; - QString m_urlPrefix; - QString m_urlSuffix; - int m_minimumZoomLevel; - int m_maximumZoomLevel; +friend class QGeoTileProviderOsm; +}; - int paramsLUT[3]; //Lookup table to handle possibly shuffled x,y,z - QString paramsSep[2]; // what goes in between %x, %y and %z - }; +class QGeoTileProviderOsm: public QObject +{ + Q_OBJECT + friend class QGeoTileFetcherOsm; + friend class QGeoMapReplyOsm; + friend class QGeoTiledMappingManagerEngineOsm; +public: enum Status {Idle, Resolving, - Valid, - Invalid }; - - QGeoTileProviderOsm(const QString &urlRedir, - QNetworkAccessManager *nm, - const QGeoMapType &mapType, - const TileProvider &providerFallback); + Resolved }; + QGeoTileProviderOsm(QNetworkAccessManager *nm, + const QGeoMapType &mapType, + const QVector<TileProvider *> &providers); ~QGeoTileProviderOsm(); - - QUrl tileAddress(int x, int y, int z) const; QString mapCopyRight() const; QString dataCopyRight() const; @@ -231,24 +147,27 @@ public: Q_SIGNALS: void resolutionFinished(const QGeoTileProviderOsm *provider); - void resolutionError(const QGeoTileProviderOsm *provider, QNetworkReply::NetworkError error); + void resolutionError(const QGeoTileProviderOsm *provider); public Q_SLOTS: - void onNetworkReplyFinished(); - void onNetworkReplyError(QNetworkReply::NetworkError error); void resolveProvider(); + void disableRedirection(); + +protected Q_SLOTS: + void onResolutionFinished(TileProvider *provider); + void onResolutionError(TileProvider *provider); protected: - void disableRedirection(); - void handleError(QNetworkReply::NetworkError error); + void addProvider(TileProvider *provider); + +/* Data members */ QNetworkAccessManager *m_nm; - QUrl m_urlRedirector; // The URL from where to fetch the URL template - TileProvider m_provider; - TileProvider m_providerFallback; + QVector<TileProvider *> m_providerList; + TileProvider *m_provider; + int m_providerId; QGeoMapType m_mapType; Status m_status; - QTimer m_retryTimer; }; QT_END_NAMESPACE |