summaryrefslogtreecommitdiff
path: root/src/plugins/geoservices/osm
diff options
context:
space:
mode:
authorMichal Klocek <michal.klocek@theqtcompany.com>2016-07-28 19:21:35 +0200
committerMichal Klocek <michal.klocek@theqtcompany.com>2016-07-28 19:21:47 +0200
commit1a1d2e3fff5856dc9d1283b510a9f325c6fb8a93 (patch)
tree2c16537e3321cde9ca9730f871f47ed32668e120 /src/plugins/geoservices/osm
parent4e1008b4ac1eea776585ca41a6a3db127cf500ff (diff)
parent75dd424e11964d8755abdb1b12b27a8479353b37 (diff)
downloadqtlocation-1a1d2e3fff5856dc9d1283b510a9f325c6fb8a93.tar.gz
Merge remote-tracking branch 'origin/5.6' into 5.7
Change-Id: I37542960aa091ab2074914a2cebb8c5114237a26
Diffstat (limited to 'src/plugins/geoservices/osm')
-rw-r--r--src/plugins/geoservices/osm/osm.pro6
-rw-r--r--src/plugins/geoservices/osm/qgeomapreplyosm.cpp17
-rw-r--r--src/plugins/geoservices/osm/qgeomapreplyosm.h5
-rw-r--r--src/plugins/geoservices/osm/qgeotiledmaposm.cpp65
-rw-r--r--src/plugins/geoservices/osm/qgeotiledmaposm.h7
-rw-r--r--src/plugins/geoservices/osm/qgeotiledmappingmanagerengineosm.cpp150
-rw-r--r--src/plugins/geoservices/osm/qgeotiledmappingmanagerengineosm.h8
-rw-r--r--src/plugins/geoservices/osm/qgeotilefetcherosm.cpp110
-rw-r--r--src/plugins/geoservices/osm/qgeotilefetcherosm.h27
-rw-r--r--src/plugins/geoservices/osm/qgeotileproviderosm.cpp318
-rw-r--r--src/plugins/geoservices/osm/qgeotileproviderosm.h256
11 files changed, 868 insertions, 101 deletions
diff --git a/src/plugins/geoservices/osm/osm.pro b/src/plugins/geoservices/osm/osm.pro
index e73c16d7..56f4cb33 100644
--- a/src/plugins/geoservices/osm/osm.pro
+++ b/src/plugins/geoservices/osm/osm.pro
@@ -14,7 +14,8 @@ HEADERS += \
qplacemanagerengineosm.h \
qplacesearchreplyosm.h \
qplacecategoriesreplyosm.h \
- qgeotiledmaposm.h
+ qgeotiledmaposm.h \
+ qgeotileproviderosm.h
SOURCES += \
qgeoserviceproviderpluginosm.cpp \
@@ -28,7 +29,8 @@ SOURCES += \
qplacemanagerengineosm.cpp \
qplacesearchreplyosm.cpp \
qplacecategoriesreplyosm.cpp \
- qgeotiledmaposm.cpp
+ qgeotiledmaposm.cpp \
+ qgeotileproviderosm.cpp
OTHER_FILES += \
diff --git a/src/plugins/geoservices/osm/qgeomapreplyosm.cpp b/src/plugins/geoservices/osm/qgeomapreplyosm.cpp
index a4a62e7f..052ed351 100644
--- a/src/plugins/geoservices/osm/qgeomapreplyosm.cpp
+++ b/src/plugins/geoservices/osm/qgeomapreplyosm.cpp
@@ -41,12 +41,16 @@
#include <QtLocation/private/qgeotilespec_p.h>
-QGeoMapReplyOsm::QGeoMapReplyOsm(QNetworkReply *reply, const QGeoTileSpec &spec, QObject *parent)
+QGeoMapReplyOsm::QGeoMapReplyOsm(QNetworkReply *reply,
+ const QGeoTileSpec &spec,
+ const QString &imageFormat,
+ QObject *parent)
: QGeoTiledMapReply(spec, parent), m_reply(reply)
{
connect(m_reply, SIGNAL(finished()), this, SLOT(networkReplyFinished()));
connect(m_reply, SIGNAL(error(QNetworkReply::NetworkError)),
this, SLOT(networkReplyError(QNetworkReply::NetworkError)));
+ setMapImageFormat(imageFormat);
}
QGeoMapReplyOsm::~QGeoMapReplyOsm()
@@ -75,18 +79,15 @@ void QGeoMapReplyOsm::networkReplyFinished()
if (!m_reply)
return;
- if (m_reply->error() != QNetworkReply::NoError)
+ if (m_reply->error() != QNetworkReply::NoError) {
+ m_reply->deleteLater();
+ m_reply = 0;
return;
+ }
QByteArray a = m_reply->readAll();
setMapImageData(a);
- int mapId = tileSpec().mapId();
- if (mapId == 1 || mapId == 2)
- setMapImageFormat(QStringLiteral("jpg"));
- else
- setMapImageFormat(QStringLiteral("png"));
-
setFinished(true);
m_reply->deleteLater();
diff --git a/src/plugins/geoservices/osm/qgeomapreplyosm.h b/src/plugins/geoservices/osm/qgeomapreplyosm.h
index 994e568a..804a0a24 100644
--- a/src/plugins/geoservices/osm/qgeomapreplyosm.h
+++ b/src/plugins/geoservices/osm/qgeomapreplyosm.h
@@ -40,6 +40,9 @@
#ifndef QGEOMAPREPLYOSM_H
#define QGEOMAPREPLYOSM_H
+#include "qgeotilefetcherosm.h"
+#include "qgeotileproviderosm.h"
+
#include <QtNetwork/QNetworkReply>
#include <QtLocation/private/qgeotiledmapreply_p.h>
#include <QtCore/qpointer.h>
@@ -51,7 +54,7 @@ class QGeoMapReplyOsm : public QGeoTiledMapReply
Q_OBJECT
public:
- explicit QGeoMapReplyOsm(QNetworkReply *reply, const QGeoTileSpec &spec, QObject *parent = 0);
+ QGeoMapReplyOsm(QNetworkReply *reply, const QGeoTileSpec &spec, const QString &imageFormat, QObject *parent = 0);
~QGeoMapReplyOsm();
void abort();
diff --git a/src/plugins/geoservices/osm/qgeotiledmaposm.cpp b/src/plugins/geoservices/osm/qgeotiledmaposm.cpp
index e0ec919e..f16e602a 100644
--- a/src/plugins/geoservices/osm/qgeotiledmaposm.cpp
+++ b/src/plugins/geoservices/osm/qgeotiledmaposm.cpp
@@ -39,14 +39,22 @@
#include "qgeotiledmaposm.h"
#include "qgeotiledmappingmanagerengineosm.h"
+#include "qgeotilefetcherosm.h"
#include <QtLocation/private/qgeotilespec_p.h>
QT_BEGIN_NAMESPACE
QGeoTiledMapOsm::QGeoTiledMapOsm(QGeoTiledMappingManagerEngineOsm *engine, QObject *parent)
-: QGeoTiledMap(engine, parent), m_mapId(-1), m_customCopyright(engine->customCopyright())
+: QGeoTiledMap(engine, parent), m_mapId(-1), m_engine(engine)
{
+ // Needed because evaluateCopyrights() is only triggered if visible tiles change in the map.
+ // It fails the first time it gets called if providers aren't resolved, and subsequent calls
+ // to it will be skipped until visible tiles change.
+ // This connection makes sure the copyrights are evaluated when copyright data are ready regardless
+ // of what tiles are visible.
+ connect(qobject_cast<QGeoTileFetcherOsm *>(engine->tileFetcher()), &QGeoTileFetcherOsm::providerDataUpdated,
+ this, &QGeoTiledMapOsm::onProviderDataUpdated);
}
QGeoTiledMapOsm::~QGeoTiledMapOsm()
@@ -62,32 +70,43 @@ void QGeoTiledMapOsm::evaluateCopyrights(const QSet<QGeoTileSpec> &visibleTiles)
if (tile.mapId() == m_mapId)
return;
+ int providerId = tile.mapId() - 1;
+ if (providerId < 0 || providerId >= m_engine->providers().size() || !m_engine->providers().at(providerId)->isValid())
+ return;
+
m_mapId = tile.mapId();
+ onProviderDataUpdated(m_engine->providers().at(providerId));
+}
- QString copyrights;
- switch (m_mapId) {
- case 1:
- case 2:
- // set attribution to Map Quest
- copyrights = tr("Tiles Courtesy of <a href='http://www.mapquest.com/'>MapQuest</a><br/>Data &copy; <a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors");
- break;
- case 3:
- case 4:
- case 5:
- case 6:
- case 7:
- // set attribution to Thunder Forest
- copyrights = tr("Maps &copy; <a href='http://www.thunderforest.com/'>Thunderforest</a><br/>Data &copy; <a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors");
- break;
- case 8:
- copyrights = m_customCopyright;
- break;
- default:
- // set attribution to OSM
- copyrights = tr("&copy; <a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors");
+void QGeoTiledMapOsm::onProviderDataUpdated(const QGeoTileProviderOsm *provider)
+{
+ if (!provider->isResolved() || provider->mapType().mapId() != m_mapId)
+ return;
+ QString copyRights;
+ const QString mapCopy = provider->mapCopyRight();
+ const QString dataCopy = provider->dataCopyRight();
+ const QString styleCopy = provider->styleCopyRight();
+ if (!mapCopy.isEmpty()) {
+ copyRights += QStringLiteral("Map &copy; ");
+ copyRights += mapCopy;
+ }
+ if (!dataCopy.isEmpty()) {
+ if (!copyRights.isEmpty())
+ copyRights += QStringLiteral("<br/>");
+ copyRights += QStringLiteral("Data &copy; ");
+ copyRights += dataCopy;
}
+ if (!styleCopy.isEmpty()) {
+ if (!copyRights.isEmpty())
+ copyRights += QStringLiteral("<br/>");
+ copyRights += QStringLiteral("Style &copy; ");
+ copyRights += styleCopy;
+ }
+
+ if (copyRights.isEmpty() && provider->mapType().style() == QGeoMapType::CustomMap)
+ copyRights = m_engine->customCopyright();
- emit copyrightsChanged(copyrights);
+ emit copyrightsChanged(copyRights);
}
QT_END_NAMESPACE
diff --git a/src/plugins/geoservices/osm/qgeotiledmaposm.h b/src/plugins/geoservices/osm/qgeotiledmaposm.h
index 40d4e79b..cfc72948 100644
--- a/src/plugins/geoservices/osm/qgeotiledmaposm.h
+++ b/src/plugins/geoservices/osm/qgeotiledmaposm.h
@@ -40,6 +40,8 @@
#ifndef QGEOTILEDMAPOSM_H
#define QGEOTILEDMAPOSM_H
+#include "qgeotileproviderosm.h"
+
#include <QtLocation/private/qgeotiledmap_p.h>
QT_BEGIN_NAMESPACE
@@ -56,9 +58,12 @@ public:
protected:
void evaluateCopyrights(const QSet<QGeoTileSpec> &visibleTiles) Q_DECL_OVERRIDE;
+protected Q_SLOTS:
+ void onProviderDataUpdated(const QGeoTileProviderOsm *provider);
+
private:
int m_mapId;
- const QString m_customCopyright;
+ QGeoTiledMappingManagerEngineOsm *m_engine;
};
QT_END_NAMESPACE
diff --git a/src/plugins/geoservices/osm/qgeotiledmappingmanagerengineosm.cpp b/src/plugins/geoservices/osm/qgeotiledmappingmanagerengineosm.cpp
index d5490559..920b0148 100644
--- a/src/plugins/geoservices/osm/qgeotiledmappingmanagerengineosm.cpp
+++ b/src/plugins/geoservices/osm/qgeotiledmappingmanagerengineosm.cpp
@@ -40,10 +40,14 @@
#include "qgeotiledmappingmanagerengineosm.h"
#include "qgeotilefetcherosm.h"
#include "qgeotiledmaposm.h"
+#include "qgeotileproviderosm.h"
#include <QtLocation/private/qgeocameracapabilities_p.h>
#include <QtLocation/private/qgeomaptype_p.h>
#include <QtLocation/private/qgeotiledmap_p.h>
+#include <QtLocation/private/qgeofiletilecache_p.h>
+
+#include <QtNetwork/QNetworkAccessManager>
QT_BEGIN_NAMESPACE
@@ -57,33 +61,142 @@ QGeoTiledMappingManagerEngineOsm::QGeoTiledMappingManagerEngineOsm(const QVarian
setTileSize(QSize(256, 256));
+ QNetworkAccessManager *nm = new QNetworkAccessManager();
+ QString domain = QStringLiteral("http://maps-redirect.qt.io/osm/5.6/");
+ if (parameters.contains(QStringLiteral("osm.mapping.providersrepository.address"))) {
+ QString customAddress = parameters.value(QStringLiteral("osm.mapping.providersrepository.address")).toString();
+ // Allowing some malformed addresses ( containing the suffix "/osm/5.6/"
+ if (customAddress.indexOf(QStringLiteral(":")) < 0) // defaulting to http:// if no prefix is found
+ customAddress = QStringLiteral("http://") + customAddress;
+ if (customAddress[customAddress.length()-1] != QLatin1Char('/'))
+ customAddress += QLatin1Char('/');
+ domain = customAddress;
+ }
+
+ m_providers.push_back(
+ new QGeoTileProviderOsm(domain + "street",
+ 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,
+ QGeoMapType(QGeoMapType::SatelliteMapDay, tr("Satellite Map"), tr("Satellite map view in daylight mode"), false, false, 2),
+ QGeoTileProviderOsm::TileProvider(QStringLiteral("http://basemap.nationalmap.gov/arcgis/rest/services/USGSImageryOnly/MapServer/tile/%z/%y/%x"),
+ QStringLiteral("jpg"),
+ QStringLiteral("<a href='http://basemap.nationalmap.gov/arcgis/rest/services/USGSImageryOnly/MapServer'>USGS The National Map: Orthoimagery</a>"),
+ QStringLiteral("<a href='http://landsat.gsfc.nasa.gov/?page_id=2339'>USGS/NASA Landsat</a>")
+ )));
+ m_providers.push_back(
+ new QGeoTileProviderOsm(domain + "cycle",
+ 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,
+ 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,
+ 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,
+ 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,
+ 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")
+ )));
+
+ if (parameters.contains(QStringLiteral("osm.mapping.custom.host"))
+ || parameters.contains(QStringLiteral("osm.mapping.host"))) {
+ // Adding a custom provider
+ QString tmsServer;
+ if (parameters.contains(QStringLiteral("osm.mapping.host")))
+ tmsServer = parameters.value(QStringLiteral("osm.mapping.host")).toString();
+ if (parameters.contains(QStringLiteral("osm.mapping.custom.host"))) // priority to the new one
+ tmsServer = parameters.value(QStringLiteral("osm.mapping.custom.host")).toString();
+
+ QString mapCopyright;
+ QString dataCopyright;
+ if (parameters.contains(QStringLiteral("osm.mapping.custom.mapcopyright")))
+ mapCopyright = parameters.value(QStringLiteral("osm.mapping.custom.mapcopyright")).toString();
+ if (parameters.contains(QStringLiteral("osm.mapping.custom.datacopyright")))
+ dataCopyright = parameters.value(QStringLiteral("osm.mapping.custom.datacopyright")).toString();
+
+ if (parameters.contains(QStringLiteral("osm.mapping.copyright")))
+ m_customCopyright = parameters.value(QStringLiteral("osm.mapping.copyright")).toString();
+
+ m_providers.push_back(
+ 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"),
+ QStringLiteral("png"),
+ mapCopyright,
+ dataCopyright
+ )));
+
+ m_providers.last()->disableRedirection();
+ }
+
+ bool disableRedirection = false;
+ if (parameters.contains(QStringLiteral("osm.mapping.providersrepository.disabled")))
+ disableRedirection = parameters.value(QStringLiteral("osm.mapping.providersrepository.disabled")).toBool();
+
QList<QGeoMapType> mapTypes;
+ foreach (QGeoTileProviderOsm * provider, m_providers) {
+ provider->setParent(this);
+ if (disableRedirection)
+ provider->disableRedirection();
+ mapTypes << provider->mapType();
+ }
// See map type implementations in QGeoTiledMapOsm and QGeoTileFetcherOsm.
- mapTypes << QGeoMapType(QGeoMapType::StreetMap, tr("Street Map"), tr("Street map view in daylight mode"), false, false, 1);
- mapTypes << QGeoMapType(QGeoMapType::SatelliteMapDay, tr("Satellite Map"), tr("Satellite map view in daylight mode"), false, false, 2);
- mapTypes << QGeoMapType(QGeoMapType::CycleMap, tr("Cycle Map"), tr("Cycle map view in daylight mode"), false, false, 3);
- mapTypes << QGeoMapType(QGeoMapType::TransitMap, tr("Transit Map"), tr("Public transit map view in daylight mode"), false, false, 4);
- mapTypes << QGeoMapType(QGeoMapType::TransitMap, tr("Night Transit Map"), tr("Public transit map view in night mode"), false, true, 5);
- mapTypes << QGeoMapType(QGeoMapType::TerrainMap, tr("Terrain Map"), tr("Terrain map view"), false, false, 6);
- mapTypes << QGeoMapType(QGeoMapType::PedestrianMap, tr("Hiking Map"), tr("Hiking map view"), false, false, 7);
- if (parameters.contains(QStringLiteral("osm.mapping.host")))
- mapTypes << QGeoMapType(QGeoMapType::CustomMap, tr("Custom URL Map"), tr("Custom url map view set via urlprefix parameter"), false, false, 8);
setSupportedMapTypes(mapTypes);
- QGeoTileFetcherOsm *tileFetcher = new QGeoTileFetcherOsm(this);
+ QGeoTileFetcherOsm *tileFetcher = new QGeoTileFetcherOsm(m_providers, nm, this);
if (parameters.contains(QStringLiteral("osm.useragent"))) {
const QByteArray ua = parameters.value(QStringLiteral("osm.useragent")).toString().toLatin1();
tileFetcher->setUserAgent(ua);
}
- if (parameters.contains(QStringLiteral("osm.mapping.host"))) {
- const QString up = parameters.value(QStringLiteral("osm.mapping.host")).toString().toLatin1();
- tileFetcher->setUrlPrefix(up);
- }
- if (parameters.contains(QStringLiteral("osm.mapping.copyright")))
- m_customCopyright = parameters.value(QStringLiteral("osm.mapping.copyright")).toString().toLatin1();
+
setTileFetcher(tileFetcher);
+ QAbstractGeoTileCache *tileCache = new QGeoFileTileCache(QAbstractGeoTileCache::baseCacheDirectory() + QStringLiteral("osm"));
+ // 50mb of disk cache by default to minimize n. of accesses to public OSM servers
+ tileCache->setMaxDiskUsage(50 * 1024 * 1024);
+ setTileCache(tileCache);
+
*error = QGeoServiceProvider::NoError;
errorString->clear();
}
@@ -97,6 +210,11 @@ QGeoMap *QGeoTiledMappingManagerEngineOsm::createMap()
return new QGeoTiledMapOsm(this);
}
+const QVector<QGeoTileProviderOsm *> &QGeoTiledMappingManagerEngineOsm::providers()
+{
+ return m_providers;
+}
+
QString QGeoTiledMappingManagerEngineOsm::customCopyright() const
{
return m_customCopyright;
diff --git a/src/plugins/geoservices/osm/qgeotiledmappingmanagerengineosm.h b/src/plugins/geoservices/osm/qgeotiledmappingmanagerengineosm.h
index e0f7d873..2ceebc74 100644
--- a/src/plugins/geoservices/osm/qgeotiledmappingmanagerengineosm.h
+++ b/src/plugins/geoservices/osm/qgeotiledmappingmanagerengineosm.h
@@ -40,25 +40,31 @@
#ifndef QGEOTILEDMAPPINGMANAGERENGINEOSM_H
#define QGEOTILEDMAPPINGMANAGERENGINEOSM_H
-#include <QtLocation/QGeoServiceProvider>
+#include "qgeotileproviderosm.h"
+#include <QtLocation/QGeoServiceProvider>
#include <QtLocation/private/qgeotiledmappingmanagerengine_p.h>
+#include <QVector>
+
QT_BEGIN_NAMESPACE
class QGeoTiledMappingManagerEngineOsm : public QGeoTiledMappingManagerEngine
{
Q_OBJECT
+ friend class QGeoTiledMapOsm;
public:
QGeoTiledMappingManagerEngineOsm(const QVariantMap &parameters,
QGeoServiceProvider::Error *error, QString *errorString);
~QGeoTiledMappingManagerEngineOsm();
QGeoMap *createMap();
+ const QVector<QGeoTileProviderOsm *> &providers();
QString customCopyright() const;
private:
+ QVector<QGeoTileProviderOsm *> m_providers;
QString m_customCopyright;
};
diff --git a/src/plugins/geoservices/osm/qgeotilefetcherosm.cpp b/src/plugins/geoservices/osm/qgeotilefetcherosm.cpp
index 021c2882..730b5379 100644
--- a/src/plugins/geoservices/osm/qgeotilefetcherosm.cpp
+++ b/src/plugins/geoservices/osm/qgeotilefetcherosm.cpp
@@ -44,12 +44,36 @@
#include <QtNetwork/QNetworkRequest>
#include <QtLocation/private/qgeotilespec_p.h>
+
QT_BEGIN_NAMESPACE
-QGeoTileFetcherOsm::QGeoTileFetcherOsm(QObject *parent)
-: QGeoTileFetcher(parent), m_networkManager(new QNetworkAccessManager(this)),
- m_userAgent("Qt Location based application")
+static bool providersResolved(const QVector<QGeoTileProviderOsm *> &providers)
{
+ foreach (const QGeoTileProviderOsm *provider, providers)
+ if (!provider->isResolved())
+ return false;
+ return true;
+}
+
+QGeoTileFetcherOsm::QGeoTileFetcherOsm(const QVector<QGeoTileProviderOsm *> &providers,
+ QNetworkAccessManager *nm,
+ QObject *parent)
+: QGeoTileFetcher(parent), m_userAgent("Qt Location based application"),
+ m_providers(providers), m_nm(nm), m_ready(true)
+{
+ m_nm->setParent(this);
+ foreach (QGeoTileProviderOsm *provider, m_providers) {
+ if (!provider->isResolved()) {
+ m_ready = false;
+ connect(provider, &QGeoTileProviderOsm::resolutionFinished,
+ this, &QGeoTileFetcherOsm::onProviderResolutionFinished);
+ connect(provider, &QGeoTileProviderOsm::resolutionError,
+ this, &QGeoTileFetcherOsm::onProviderResolutionError);
+ provider->resolveProvider();
+ }
+ }
+ if (m_ready)
+ readyUpdated();
}
void QGeoTileFetcherOsm::setUserAgent(const QByteArray &userAgent)
@@ -57,57 +81,55 @@ void QGeoTileFetcherOsm::setUserAgent(const QByteArray &userAgent)
m_userAgent = userAgent;
}
-void QGeoTileFetcherOsm::setUrlPrefix(const QString &urlPrefix)
+bool QGeoTileFetcherOsm::initialized() const
{
- m_urlPrefix = urlPrefix;
+ if (!m_ready) {
+ foreach (QGeoTileProviderOsm *provider, m_providers)
+ if (!provider->isResolved())
+ provider->resolveProvider();
+ }
+ return m_ready;
}
-QGeoTiledMapReply *QGeoTileFetcherOsm::getTileImage(const QGeoTileSpec &spec)
+void QGeoTileFetcherOsm::onProviderResolutionFinished(const QGeoTileProviderOsm *provider)
{
- QNetworkRequest request;
- request.setRawHeader("User-Agent", m_userAgent);
+ if ((m_ready = providersResolved(m_providers))) {
+ qWarning("QGeoTileFetcherOsm: all providers resolved");
+ readyUpdated();
+ }
+ emit providerDataUpdated(provider);
+}
- QString urlPrefix;
- QString suffix = QStringLiteral(".png");
+void QGeoTileFetcherOsm::onProviderResolutionError(const QGeoTileProviderOsm *provider, QNetworkReply::NetworkError error)
+{
+ Q_UNUSED(error)
+ if ((m_ready = providersResolved(m_providers))) {
+ qWarning("QGeoTileFetcherOsm: all providers resolved");
+ readyUpdated();
+ }
+ emit providerDataUpdated(provider);
+}
- switch (spec.mapId()) {
- case 1:
- urlPrefix = QStringLiteral("http://otile1.mqcdn.com/tiles/1.0.0/map/");
- suffix = QStringLiteral(".jpg");
- break;
- case 2:
- urlPrefix = QStringLiteral("http://otile1.mqcdn.com/tiles/1.0.0/sat/");
- suffix = QStringLiteral(".jpg");
- break;
- case 3:
- urlPrefix = QStringLiteral("http://a.tile.thunderforest.com/cycle/");
- break;
- case 4:
- urlPrefix = QStringLiteral("http://a.tile.thunderforest.com/transport/");
- break;
- case 5:
- urlPrefix = QStringLiteral("http://a.tile.thunderforest.com/transport-dark/");
- break;
- case 6:
- urlPrefix = QStringLiteral("http://a.tile.thunderforest.com/landscape/");
- break;
- case 7:
- urlPrefix = QStringLiteral("http://a.tile.thunderforest.com/outdoors/");
- break;
- case 8:
- urlPrefix = m_urlPrefix;
- break;
- default:
+QGeoTiledMapReply *QGeoTileFetcherOsm::getTileImage(const QGeoTileSpec &spec)
+{
+ int id = spec.mapId();
+ if (id < 1 || id > m_providers.size()) {
qWarning("Unknown map id %d\n", spec.mapId());
+ id = 0;
}
+ id -= 1; // TODO: make OSM map ids start from 0.
- request.setUrl(QUrl(urlPrefix + QString::number(spec.zoom()) + QLatin1Char('/') +
- QString::number(spec.x()) + QLatin1Char('/') +
- QString::number(spec.y()) + suffix));
-
- QNetworkReply *reply = m_networkManager->get(request);
+ const QUrl url = m_providers[id]->tileAddress(spec.x(), spec.y(), spec.zoom());
+ QNetworkRequest request;
+ request.setHeader(QNetworkRequest::UserAgentHeader, m_userAgent);
+ request.setUrl(url);
+ QNetworkReply *reply = m_nm->get(request);
+ return new QGeoMapReplyOsm(reply, spec, m_providers[id]->format());
+}
- return new QGeoMapReplyOsm(reply, spec);
+void QGeoTileFetcherOsm::readyUpdated()
+{
+ updateTileRequests(QSet<QGeoTileSpec>(), QSet<QGeoTileSpec>());
}
QT_END_NAMESPACE
diff --git a/src/plugins/geoservices/osm/qgeotilefetcherosm.h b/src/plugins/geoservices/osm/qgeotilefetcherosm.h
index 184f20a6..8d69cc56 100644
--- a/src/plugins/geoservices/osm/qgeotilefetcherosm.h
+++ b/src/plugins/geoservices/osm/qgeotilefetcherosm.h
@@ -40,31 +40,48 @@
#ifndef QGEOTILEFETCHEROSM_H
#define QGEOTILEFETCHEROSM_H
+#include "qgeotileproviderosm.h"
#include <QtLocation/private/qgeotilefetcher_p.h>
+#include <QVector>
QT_BEGIN_NAMESPACE
-class QGeoTiledMappingManagerEngine;
class QNetworkAccessManager;
class QGeoTileFetcherOsm : public QGeoTileFetcher
{
Q_OBJECT
+ friend class QGeoMapReplyOsm;
+ friend class QGeoTiledMappingManagerEngineOsm;
public:
- QGeoTileFetcherOsm(QObject *parent = 0);
+ QGeoTileFetcherOsm(const QVector<QGeoTileProviderOsm *> &providers,
+ QNetworkAccessManager *nm,
+ QObject *parent = 0);
void setUserAgent(const QByteArray &userAgent);
- void setUrlPrefix(const QString &urlPrefix);
+
+Q_SIGNALS:
+ void providerDataUpdated(const QGeoTileProviderOsm *provider);
+
+protected:
+ bool initialized() const Q_DECL_OVERRIDE;
+
+protected Q_SLOTS:
+ void onProviderResolutionFinished(const QGeoTileProviderOsm *provider);
+ void onProviderResolutionError(const QGeoTileProviderOsm *provider, QNetworkReply::NetworkError error);
private:
QGeoTiledMapReply *getTileImage(const QGeoTileSpec &spec);
+ void readyUpdated();
- QNetworkAccessManager *m_networkManager;
QByteArray m_userAgent;
- QString m_urlPrefix;
+ QVector<QGeoTileProviderOsm *> m_providers;
+ QNetworkAccessManager *m_nm;
+ bool m_ready;
};
QT_END_NAMESPACE
#endif // QGEOTILEFETCHEROSM_H
+
diff --git a/src/plugins/geoservices/osm/qgeotileproviderosm.cpp b/src/plugins/geoservices/osm/qgeotileproviderosm.cpp
new file mode 100644
index 00000000..3d46a425
--- /dev/null
+++ b/src/plugins/geoservices/osm/qgeotileproviderosm.cpp
@@ -0,0 +1,318 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qgeotileproviderosm.h"
+
+#include <QtCore/QJsonDocument>
+#include <QtCore/QJsonObject>
+#include <QDebug>
+
+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)
+{
+ if (!m_urlRedirector.isValid())
+ disableRedirection();
+}
+
+QGeoTileProviderOsm::~QGeoTileProviderOsm()
+{
+
+}
+
+void QGeoTileProviderOsm::resolveProvider()
+{
+ 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)));
+}
+
+void QGeoTileProviderOsm::disableRedirection()
+{
+ m_status = Invalid;
+ m_provider.m_valid = false;
+}
+
+void QGeoTileProviderOsm::handleError(QNetworkReply::NetworkError error)
+{
+ 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;
+ }
+}
+
+QUrl QGeoTileProviderOsm::tileAddress(int x, int y, int z) const
+{
+ if (m_provider.isValid())
+ return m_provider.tileAddress(x,y,z);
+ if (m_providerFallback.isValid())
+ return m_providerFallback.tileAddress(x,y,z);
+ return QUrl();
+}
+
+QString QGeoTileProviderOsm::mapCopyRight() const
+{
+ if (m_provider.isValid())
+ return m_provider.mapCopyRight();
+ if (m_providerFallback.isValid())
+ return m_providerFallback.mapCopyRight();
+ return QString();
+}
+
+QString QGeoTileProviderOsm::dataCopyRight() const
+{
+ if (m_provider.isValid())
+ return m_provider.dataCopyRight();
+ if (m_providerFallback.isValid())
+ return m_providerFallback.dataCopyRight();
+ return QString();
+}
+
+QString QGeoTileProviderOsm::styleCopyRight() const
+{
+ if (m_provider.isValid())
+ return m_provider.styleCopyRight();
+ if (m_providerFallback.isValid())
+ return m_providerFallback.styleCopyRight();
+ return QString();
+}
+
+QString QGeoTileProviderOsm::format() const
+{
+ if (m_provider.isValid())
+ return m_provider.format();
+ if (m_providerFallback.isValid())
+ return m_providerFallback.format();
+ return QString();
+}
+
+const QGeoMapType &QGeoTileProviderOsm::mapType() const
+{
+ return m_mapType;
+}
+
+bool QGeoTileProviderOsm::isValid() const
+{
+ return (m_provider.isValid() || m_providerFallback.isValid());
+}
+
+bool QGeoTileProviderOsm::isResolved() const
+{
+ return (m_status == Valid || m_status == Invalid);
+}
+
+void QGeoTileProviderOsm::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;
+ }
+
+ if (reply->error() != QNetworkReply::NoError) {
+ handleError(reply->error());
+ if (m_status == Invalid)
+ emit resolutionError(this, reply->error());
+ return;
+ }
+ m_status = Invalid;
+
+ /*
+ * The content of a provider information file must be in JSON format, containing
+ * (as of Qt 5.6.2) the following fields:
+ *
+ * {
+ * "Enabled" : bool, (optional)
+ * "UrlTemplate" : "<url template>", (mandatory)
+ * "ImageFormat" : "<image format>", (mandatory)
+ * "MapCopyRight" : "<copyright>", (mandatory)
+ * "DataCopyRight" : "<copyright>", (mandatory)
+ * "StyleCopyRight" : "<copyright>", (optional)
+ * "MinimumZoomLevel" : <minimumZoomLevel>, (optional)
+ * "MaximumZoomLevel" : <maximumZoomLevel>, (optional)
+ * }
+ *
+ * Enabled is optional, and allows to temporarily disable a tile provider if it becomes
+ * unavailable, without making the osm plugin fire requests to it. Default is true.
+ *
+ * MinimumZoomLevel and MaximumZoomLevel are also optional, and allow to prevent invalid tile
+ * requests to the providers, if they do not support the specific ZL. Default is 0 and 19,
+ * respectively.
+ *
+ * <server address template> is required, and is the tile url template, with %x, %y and %z as
+ * placeholders for the actual parameters.
+ * Example:
+ * http://localhost:8080/maps/%z/%x/%y.png
+ *
+ * <image format> is required, and is the format of the tile.
+ * Examples:
+ * "png", "jpg"
+ *
+ * <MapCopyRight> is required and is the string that will be displayed in the "Map (c)" part
+ * of the on-screen copyright notice. Can be an empty string.
+ * Example:
+ * "<a href='http://www.mapquest.com/'>MapQuest</a>"
+ *
+ * <DataCopyRight> is required and is the string that will be displayed in the "Data (c)" part
+ * of the on-screen copyright notice. Can be an empty string.
+ * Example:
+ * "<a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors"
+ *
+ * <StyleCopyRight> is optional and is the string that will be displayed in the optional "Style (c)" part
+ * of the on-screen copyright notice.
+ */
+
+ QJsonParseError error;
+ 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();
+ const QJsonValue urlTemplate = json.value(QLatin1String("UrlTemplate"));
+ const QJsonValue imageFormat = json.value(QLatin1String("ImageFormat"));
+ const QJsonValue copyRightMap = json.value(QLatin1String("MapCopyRight"));
+ const QJsonValue copyRightData = json.value(QLatin1String("DataCopyRight"));
+ if ( urlTemplate == QJsonValue::Undefined
+ || imageFormat == QJsonValue::Undefined
+ || copyRightMap == QJsonValue::Undefined
+ || copyRightData == QJsonValue::Undefined
+ || !urlTemplate.isString()
+ || !imageFormat.isString()
+ || !copyRightMap.isString()
+ || !copyRightData.isString()) {
+ qWarning() << "QGeoTileProviderOsm: Incomplete redirection data" << "at "<<m_urlRedirector;
+ emit resolutionFinished(this);
+ return;
+ }
+
+ 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();
+
+ int minZL = 0;
+ int maxZL = 19;
+ const QJsonValue minZoom = json.value(QLatin1String("MinimumZoomLevel"));
+ if (minZoom.isDouble())
+ minZL = 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;
+
+ emit resolutionFinished(this);
+}
+
+void QGeoTileProviderOsm::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);
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/geoservices/osm/qgeotileproviderosm.h b/src/plugins/geoservices/osm/qgeotileproviderosm.h
new file mode 100644
index 00000000..cdff7997
--- /dev/null
+++ b/src/plugins/geoservices/osm/qgeotileproviderosm.h
@@ -0,0 +1,256 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTILEPROVIDEROSM_H
+#define QTILEPROVIDEROSM_H
+
+#include <QtLocation/private/qgeomaptype_p.h>
+
+#include <QtCore/QUrl>
+#include <QtNetwork/QNetworkAccessManager>
+#include <QtNetwork/QNetworkReply>
+#include <QtCore/QPointer>
+#include <QTimer>
+#include <algorithm>
+
+QT_BEGIN_NAMESPACE
+
+class QGeoTileProviderOsm: 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 &copyRightMap,
+ const QString &copyRightData,
+ 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 + 4, 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_valid = true;
+ }
+
+ ~TileProvider()
+ {
+ }
+
+ inline bool isValid() const
+ {
+ return m_valid;
+ }
+
+ inline QString mapCopyRight() const
+ {
+ return m_copyRightMap;
+ }
+
+ inline QString dataCopyRight() const
+ {
+ return m_copyRightData;
+ }
+
+ inline QString styleCopyRight() const
+ {
+ return m_copyRightStyle;
+ }
+
+ inline QString format() const
+ {
+ return m_format;
+ }
+
+ // Optional properties, not needed to construct a provider
+ void setStyleCopyRight(const QString &copyright)
+ {
+ m_copyRightStyle = copyright;
+ }
+
+ 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);
+ }
+
+ 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;
+
+ int paramsLUT[3]; //Lookup table to handle possibly shuffled x,y,z
+ QString paramsSep[2]; // what goes in between %x, %y and %z
+ };
+
+ enum Status {Idle,
+ Resolving,
+ Valid,
+ Invalid };
+
+ QGeoTileProviderOsm(const QString &urlRedir,
+ QNetworkAccessManager *nm,
+ const QGeoMapType &mapType,
+ const TileProvider &providerFallback);
+
+ ~QGeoTileProviderOsm();
+
+
+
+ QUrl tileAddress(int x, int y, int z) const;
+ QString mapCopyRight() const;
+ QString dataCopyRight() const;
+ QString styleCopyRight() const;
+ QString format() const;
+ const QGeoMapType &mapType() const;
+ bool isValid() const;
+ bool isResolved() const;
+
+Q_SIGNALS:
+ void resolutionFinished(const QGeoTileProviderOsm *provider);
+ void resolutionError(const QGeoTileProviderOsm *provider, QNetworkReply::NetworkError error);
+
+public Q_SLOTS:
+ void onNetworkReplyFinished();
+ void onNetworkReplyError(QNetworkReply::NetworkError error);
+ void resolveProvider();
+
+protected:
+ void disableRedirection();
+ void handleError(QNetworkReply::NetworkError error);
+
+ QNetworkAccessManager *m_nm;
+ QUrl m_urlRedirector; // The URL from where to fetch the URL template
+ TileProvider m_provider;
+ TileProvider m_providerFallback;
+ QGeoMapType m_mapType;
+ Status m_status;
+ QTimer m_retryTimer;
+};
+
+QT_END_NAMESPACE
+
+#endif // QTILEPROVIDEROSM_H