diff options
author | Alex Blasche <alexander.blasche@qt.io> | 2016-12-05 12:43:52 +0100 |
---|---|---|
committer | Alex Blasche <alexander.blasche@qt.io> | 2016-12-05 12:43:52 +0100 |
commit | 335116ea024f51e1693bba39f78e15131870f1b0 (patch) | |
tree | 148ccdb4703b4a35afb1b0e3875573b1eb90d0ce /src/plugins/geoservices/osm | |
parent | 5e4bc1fe908896e9b90e8ad9c3896f35b5ec37be (diff) | |
parent | ba9b7b9ef674d93680070f6c4bb1053d0d2325dd (diff) | |
download | qtlocation-335116ea024f51e1693bba39f78e15131870f1b0.tar.gz |
Merge remote-tracking branch 'gerrit/5.8' into dev
Conflicts:
src/imports/location/qdeclarativegeomap.cpp
src/location/maps/maps.pri
src/location/maps/qgeomap_p_p.h
src/plugins/geoservices/nokia/qgeocodereply_nokia.cpp
src/plugins/geoservices/osm/qgeoroutereplyosm.cpp
Change-Id: I18d31cff9233648178fe3e2636ce294026dfaeb7
Diffstat (limited to 'src/plugins/geoservices/osm')
5 files changed, 227 insertions, 43 deletions
diff --git a/src/plugins/geoservices/osm/qgeofiletilecacheosm.cpp b/src/plugins/geoservices/osm/qgeofiletilecacheosm.cpp index 5028a82b..a563cced 100644 --- a/src/plugins/geoservices/osm/qgeofiletilecacheosm.cpp +++ b/src/plugins/geoservices/osm/qgeofiletilecacheosm.cpp @@ -45,13 +45,16 @@ QT_BEGIN_NAMESPACE -QGeoFileTileCacheOsm::QGeoFileTileCacheOsm(const QVector<QGeoTileProviderOsm *> &providers, const QString &offlineDirectory, const QString &directory, QObject *parent) -: QGeoFileTileCache(directory, parent), m_offlineDirectory(offlineDirectory), - m_requestCancel(0), m_providers(providers) +QGeoFileTileCacheOsm::QGeoFileTileCacheOsm(const QVector<QGeoTileProviderOsm *> &providers, + const QString &offlineDirectory, + const QString &directory, + QObject *parent) +: QGeoFileTileCache(directory, parent), m_offlineDirectory(offlineDirectory), m_requestCancel(0), m_providers(providers) { m_highDpi.resize(providers.size()); for (int i = 0; i < providers.size(); i++) { m_highDpi[i] = providers[i]->isHighDpi(); + m_mapIdFutures[providers[i]->mapType().mapId()].isFinished(); // To construct a default future for this mapId connect(providers[i], &QGeoTileProviderOsm::resolutionFinished, this, &QGeoFileTileCacheOsm::onProviderResolutionFinished); connect(providers[i], &QGeoTileProviderOsm::resolutionError, this, &QGeoFileTileCacheOsm::onProviderResolutionFinished); } @@ -61,6 +64,8 @@ QGeoFileTileCacheOsm::~QGeoFileTileCacheOsm() { m_requestCancel = 1; m_future.waitForFinished(); + for (const QGeoTileProviderOsm *p : m_providers) + m_mapIdFutures[p->mapType().mapId()].waitForFinished(); } QSharedPointer<QGeoTileTexture> QGeoFileTileCacheOsm::get(const QGeoTileSpec &spec) @@ -75,9 +80,10 @@ QSharedPointer<QGeoTileTexture> QGeoFileTileCacheOsm::get(const QGeoTileSpec &sp void QGeoFileTileCacheOsm::onProviderResolutionFinished(const QGeoTileProviderOsm *provider) { + clearObsoleteTiles(provider); Q_UNUSED(provider) for (int i = 0; i < m_providers.size(); i++) { - if (m_providers[i]->isHighDpi() != m_highDpi[i]) { + if (m_providers[i]->isHighDpi() != m_highDpi[i]) { // e.g., HiDpi was requested but only LoDpi is available int mapId = m_providers[i]->mapType().mapId(); m_highDpi[i] = m_providers[i]->isHighDpi(); @@ -85,17 +91,60 @@ void QGeoFileTileCacheOsm::onProviderResolutionFinished(const QGeoTileProviderOs dropTiles(mapId); loadTiles(mapId); + // reload offline registry for mapId i + m_mapIdFutures[mapId] = QtConcurrent::run(this, &QGeoFileTileCacheOsm::initOfflineRegistry, mapId); + // send signal to clear scene in all maps created through this provider that use the reloaded tiles emit mapDataUpdated(mapId); } } } +// On resolution error the provider is removed ONLY if there is no enabled hardcoded fallback. +// Hardcoded fallbacks also have a timestamp, that can get updated with Qt releases. +void QGeoFileTileCacheOsm::onProviderResolutionError(const QGeoTileProviderOsm *provider, QNetworkReply::NetworkError error) +{ + Q_UNUSED(error) + clearObsoleteTiles(provider); // this still removes tiles who happen to be older than qgeotileproviderosm.cpp defaultTs +} + void QGeoFileTileCacheOsm::init() { + if (directory_.isEmpty()) + directory_ = baseLocationCacheDirectory(); + QDir::root().mkpath(directory_); + + // find max mapId + int max = 0; + for (auto p: m_providers) + if (p->mapType().mapId() > max) + max = p->mapType().mapId(); + // Create a mapId to maxTimestamp LUT.. + m_maxMapIdTimestamps.resize(max+1); // initializes to invalid QDateTime + + // .. by finding the newest file in each tileset (tileset = mapId). + QDir dir(directory_); + QStringList formats; + formats << QLatin1String("*.*"); + QStringList files = dir.entryList(formats, QDir::Files); + + for (const QString &tileFileName : files) { + QGeoTileSpec spec = filenameToTileSpec(tileFileName); + if (spec.zoom() == -1) + continue; + QFileInfo fi(dir.filePath(tileFileName)); + if (fi.lastModified() > m_maxMapIdTimestamps[spec.mapId()]) + m_maxMapIdTimestamps[spec.mapId()] = fi.lastModified(); + } + + // Base class ::init() QGeoFileTileCache::init(); + + for (QGeoTileProviderOsm * p: m_providers) + clearObsoleteTiles(p); + if (!m_offlineDirectory.isEmpty()) - m_future = QtConcurrent::run(this, &QGeoFileTileCacheOsm::initOfflineRegistry); + m_future = QtConcurrent::run(this, &QGeoFileTileCacheOsm::initOfflineRegistry, -1); } QSharedPointer<QGeoTileTexture> QGeoFileTileCacheOsm::getFromOfflineStorage(const QGeoTileSpec &spec) @@ -159,7 +208,7 @@ void QGeoFileTileCacheOsm::loadTiles(int mapId) } } -void QGeoFileTileCacheOsm::initOfflineRegistry() +void QGeoFileTileCacheOsm::initOfflineRegistry(int mapId) { // Dealing with duplicates: picking the newest QMap<QString, QPair<QString, QDateTime> > fileDates; // key is filename, value is <filepath, lastmodified> @@ -173,11 +222,33 @@ void QGeoFileTileCacheOsm::initOfflineRegistry() return; } + // Clear the content of the index. Entirely (at startup), or selectively (when a provider resolution changes the highDpi status). + if (mapId < 0) { + storageLock.lock(); + m_tilespecToOfflineFilepath.clear(); + storageLock.unlock(); + } else { + QList<QGeoTileSpec> toRemove; + for (auto i = m_tilespecToOfflineFilepath.constBegin(); i != m_tilespecToOfflineFilepath.constEnd(); ++i) { + if (i.key().mapId() == mapId) + toRemove.append(i.key()); + } + storageLock.lock(); + for (const auto &i : toRemove) + m_tilespecToOfflineFilepath.remove(i); + storageLock.unlock(); + } + if (m_requestCancel) + return; + + // Fill the index entirely or selectively int count = 0; - for (auto i= fileDates.begin(); i != fileDates.end(); ++i) { + for (auto i= fileDates.constBegin(); i != fileDates.constEnd(); ++i) { QGeoTileSpec spec = filenameToTileSpec(i.key()); if (spec.zoom() == -1) continue; + if (mapId >= 0 && spec.mapId() != mapId) // if mapId != -1, pick up only those files with that mapId. + continue; count++; storageLock.lock(); m_tilespecToOfflineFilepath[spec] = i.value().first; @@ -185,7 +256,7 @@ void QGeoFileTileCacheOsm::initOfflineRegistry() if (m_requestCancel) return; } - qWarning() << "OSM Offline tiles: "<<count; + //qInfo() << "OSM plugin has found and is using "<< count <<" offline tiles"; } QString QGeoFileTileCacheOsm::tileSpecToFilename(const QGeoTileSpec &spec, const QString &format, const QString &directory) const @@ -264,4 +335,26 @@ QGeoTileSpec QGeoFileTileCacheOsm::filenameToTileSpec(const QString &filename) c numbers.at(4)); } +void QGeoFileTileCacheOsm::clearObsoleteTiles(const QGeoTileProviderOsm *p) +{ + // process initialized providers, and connect the others + + if (p->isResolved()) { + if (m_maxMapIdTimestamps[p->mapType().mapId()].isValid() && // there are tiles in the cache + p->timestamp() > m_maxMapIdTimestamps[p->mapType().mapId()]) { // and they are older than the provider + qInfo() << "provider for " << p->mapType().name() << " timestamp: " << p->timestamp() + << " -- data last modified: " << m_maxMapIdTimestamps[p->mapType().mapId()] << ". Clearing."; + clearMapId(p->mapType().mapId()); + m_maxMapIdTimestamps[p->mapType().mapId()] = p->timestamp(); // don't do it again. + } + } else { + connect(p, &QGeoTileProviderOsm::resolutionFinished, + this, &QGeoFileTileCacheOsm::onProviderResolutionFinished); +#if 0 // If resolution fails, better not try to remove anything. Beside, on error, resolutionFinished is also emitted. + connect(p, &QGeoTileProviderOsm::resolutionError, + this, &QGeoFileTileCacheOsm::onProviderResolutionError); +#endif + } +} + QT_END_NAMESPACE diff --git a/src/plugins/geoservices/osm/qgeofiletilecacheosm.h b/src/plugins/geoservices/osm/qgeofiletilecacheosm.h index 52d57747..d26cad4a 100644 --- a/src/plugins/geoservices/osm/qgeofiletilecacheosm.h +++ b/src/plugins/geoservices/osm/qgeofiletilecacheosm.h @@ -49,7 +49,10 @@ class QGeoFileTileCacheOsm : public QGeoFileTileCache { Q_OBJECT public: - QGeoFileTileCacheOsm(const QVector<QGeoTileProviderOsm *> &providers, const QString &offlineDirectory = QString(), const QString &directory = QString(), QObject *parent = 0); + QGeoFileTileCacheOsm(const QVector<QGeoTileProviderOsm *> &providers, + const QString &offlineDirectory = QString(), + const QString &directory = QString(), + QObject *parent = 0); ~QGeoFileTileCacheOsm(); QSharedPointer<QGeoTileTexture> get(const QGeoTileSpec &spec) Q_DECL_OVERRIDE; @@ -59,6 +62,7 @@ Q_SIGNALS: protected Q_SLOTS: void onProviderResolutionFinished(const QGeoTileProviderOsm *provider); + void onProviderResolutionError(const QGeoTileProviderOsm *provider, QNetworkReply::NetworkError error); protected: void init() Q_DECL_OVERRIDE; @@ -68,15 +72,18 @@ protected: void dropTiles(int mapId); void loadTiles(int mapId); - void initOfflineRegistry(); + void initOfflineRegistry(int mapId = -1); + void clearObsoleteTiles(const QGeoTileProviderOsm *p); QString m_offlineDirectory; QHash<QGeoTileSpec, QString> m_tilespecToOfflineFilepath; QAtomicInt m_requestCancel; QFuture<void> m_future; + QMap<int, QFuture<void>> m_mapIdFutures; QMutex storageLock; QVector<QGeoTileProviderOsm *> m_providers; QVector<bool> m_highDpi; + QVector<QDateTime> m_maxMapIdTimestamps; }; QT_END_NAMESPACE diff --git a/src/plugins/geoservices/osm/qgeotiledmappingmanagerengineosm.cpp b/src/plugins/geoservices/osm/qgeotiledmappingmanagerengineosm.cpp index f8e18de9..ff79c261 100644 --- a/src/plugins/geoservices/osm/qgeotiledmappingmanagerengineosm.cpp +++ b/src/plugins/geoservices/osm/qgeotiledmappingmanagerengineosm.cpp @@ -70,7 +70,10 @@ QGeoTiledMappingManagerEngineOsm::QGeoTiledMappingManagerEngineOsm(const QVarian customAddress = QStringLiteral("http://") + customAddress; if (customAddress[customAddress.length()-1] != QLatin1Char('/')) customAddress += QLatin1Char('/'); - domain = customAddress; + if (QUrl(customAddress).isValid()) + domain = customAddress; + else + qWarning() << "Invalid custom providers repository address: " << customAddress; } bool highdpi = false; @@ -105,37 +108,50 @@ QGeoTiledMappingManagerEngineOsm::QGeoTiledMappingManagerEngineOsm(const QVarian providers_terrain.push_back(new TileProvider(domain + "terrain")); providers_hiking.push_back(new TileProvider(domain + "hiking")); // Backups + const QDateTime defaultTs = QDateTime::fromString(QStringLiteral("2016-06-01T00:00:00"), Qt::ISODate); 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_street.back()->setTimestamp(defaultTs); + + // No available open access satellite backup with satisfactory level of details at the present. + 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_cycle.back()->setTimestamp(defaultTs); + 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_transit.back()->setTimestamp(defaultTs); + 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_nighttransit.back()->setTimestamp(defaultTs); + 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_terrain.back()->setTimestamp(defaultTs); + 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"))); + providers_hiking.back()->setTimestamp(defaultTs); /* QGeoTileProviderOsms setup */ @@ -208,15 +224,8 @@ QGeoTiledMappingManagerEngineOsm::QGeoTiledMappingManagerEngineOsm(const QVarian } updateMapTypes(); - 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); - } - - - setTileFetcher(tileFetcher); + /* TILE CACHE */ if (parameters.contains(QStringLiteral("osm.mapping.cache.directory"))) { m_cacheDirectory = parameters.value(QStringLiteral("osm.mapping.cache.directory")).toString(); } else { @@ -225,19 +234,38 @@ QGeoTiledMappingManagerEngineOsm::QGeoTiledMappingManagerEngineOsm(const QVarian } if (parameters.contains(QStringLiteral("osm.mapping.offline.directory"))) m_offlineDirectory = parameters.value(QStringLiteral("osm.mapping.offline.directory")).toString(); - - QAbstractGeoTileCache *tileCache = new QGeoFileTileCacheOsm(m_providers, m_offlineDirectory, m_cacheDirectory); - - // 50mb of disk cache by default to minimize n. of accesses to public OSM servers - tileCache->setMaxDiskUsage(50 * 1024 * 1024); - + QGeoFileTileCacheOsm *tileCache = new QGeoFileTileCacheOsm(m_providers, m_offlineDirectory, m_cacheDirectory); + + /* + * Disk cache setup -- defaults to ByteSize (old behavior) + */ + if (parameters.contains(QStringLiteral("osm.mapping.cache.disk.cost_strategy"))) { + QString cacheStrategy = parameters.value(QStringLiteral("osm.mapping.cache.disk.cost_strategy")).toString().toLower(); + if (cacheStrategy == QLatin1String("bytesize")) + tileCache->setCostStrategyDisk(QGeoFileTileCache::ByteSize); + else + tileCache->setCostStrategyDisk(QGeoFileTileCache::Unitary); + } else { + tileCache->setCostStrategyDisk(QGeoFileTileCache::ByteSize); + } if (parameters.contains(QStringLiteral("osm.mapping.cache.disk.size"))) { bool ok = false; int cacheSize = parameters.value(QStringLiteral("osm.mapping.cache.disk.size")).toString().toInt(&ok); if (ok) tileCache->setMaxDiskUsage(cacheSize); + } + + /* + * Memory cache setup -- defaults to ByteSize (old behavior) + */ + if (parameters.contains(QStringLiteral("osm.mapping.cache.memory.cost_strategy"))) { + QString cacheStrategy = parameters.value(QStringLiteral("osm.mapping.cache.memory.cost_strategy")).toString().toLower(); + if (cacheStrategy == QLatin1String("bytesize")) + tileCache->setCostStrategyMemory(QGeoFileTileCache::ByteSize); + else + tileCache->setCostStrategyMemory(QGeoFileTileCache::Unitary); } else { - tileCache->setMaxDiskUsage(100 * 1024 * 1024); + tileCache->setCostStrategyMemory(QGeoFileTileCache::ByteSize); } if (parameters.contains(QStringLiteral("osm.mapping.cache.memory.size"))) { bool ok = false; @@ -245,14 +273,38 @@ QGeoTiledMappingManagerEngineOsm::QGeoTiledMappingManagerEngineOsm(const QVarian if (ok) tileCache->setMaxMemoryUsage(cacheSize); } + + /* + * Texture cache setup -- defaults to ByteSize (old behavior) + */ + if (parameters.contains(QStringLiteral("osm.mapping.cache.texture.cost_strategy"))) { + QString cacheStrategy = parameters.value(QStringLiteral("osm.mapping.cache.texture.cost_strategy")).toString().toLower(); + if (cacheStrategy == QLatin1String("bytesize")) + tileCache->setCostStrategyTexture(QGeoFileTileCache::ByteSize); + else + tileCache->setCostStrategyTexture(QGeoFileTileCache::Unitary); + } else { + tileCache->setCostStrategyTexture(QGeoFileTileCache::ByteSize); + } if (parameters.contains(QStringLiteral("osm.mapping.cache.texture.size"))) { bool ok = false; int cacheSize = parameters.value(QStringLiteral("osm.mapping.cache.texture.size")).toString().toInt(&ok); if (ok) tileCache->setExtraTextureUsage(cacheSize); } + + setTileCache(tileCache); + + /* TILE FETCHER */ + 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); + } + setTileFetcher(tileFetcher); + *error = QGeoServiceProvider::NoError; errorString->clear(); } diff --git a/src/plugins/geoservices/osm/qgeotileproviderosm.cpp b/src/plugins/geoservices/osm/qgeotileproviderosm.cpp index 0d99c828..1989c44f 100644 --- a/src/plugins/geoservices/osm/qgeotileproviderosm.cpp +++ b/src/plugins/geoservices/osm/qgeotileproviderosm.cpp @@ -43,6 +43,7 @@ QT_BEGIN_NAMESPACE static const int maxValidZoom = 30; +static const QDateTime defaultTs = QDateTime::fromString(QStringLiteral("2016-06-01T00:00:00"), Qt::ISODate); QGeoTileProviderOsm::QGeoTileProviderOsm(QNetworkAccessManager *nm, const QGeoMapType &mapType, @@ -120,6 +121,13 @@ bool QGeoTileProviderOsm::isHighDpi() const return m_provider->isHighDpi(); } +const QDateTime QGeoTileProviderOsm::timestamp() const +{ + if (!m_provider) + return QDateTime(); + return m_provider->timestamp(); +} + const QGeoMapType &QGeoTileProviderOsm::mapType() const { return m_mapType; @@ -190,8 +198,10 @@ void QGeoTileProviderOsm::onResolutionError(TileProvider *provider) m_provider = p; if (!p->isValid()) { m_status = Idle; -// m_status = Resolving; -// p->resolveProvider(); +#if 0 // leaving triggering the retry to the tile fetcher, instead of constantly spinning it in here. + m_status = Resolving; + p->resolveProvider(); +#endif emit resolutionRequired(); } break; @@ -204,7 +214,9 @@ void QGeoTileProviderOsm::onResolutionError(TileProvider *provider) emit resolutionFinished(this); } else { // still not resolved. But network error is recoverable. m_status = Idle; - //m_provider->resolveProvider(); +#if 0 // leaving triggering the retry to the tile fetcher + m_provider->resolveProvider(); +#endif } } @@ -226,7 +238,7 @@ void QGeoTileProviderOsm::addProvider(TileProvider *provider) /* - QGeoTileProviderOsm::TileProvder + Class TileProvder */ static void sort2(int &a, int &b) @@ -238,13 +250,13 @@ static void sort2(int &a, int &b) } } -TileProvider::TileProvider() : m_status(Invalid), m_nm(nullptr), m_highDpi(false) +TileProvider::TileProvider() : m_status(Invalid), m_nm(nullptr), m_timestamp(defaultTs), m_highDpi(false) { } TileProvider::TileProvider(const QUrl &urlRedirector, bool highDpi) -: m_status(Idle), m_urlRedirector(urlRedirector), m_nm(nullptr), m_highDpi(highDpi) +: m_status(Idle), m_urlRedirector(urlRedirector), m_nm(nullptr), m_timestamp(defaultTs), m_highDpi(highDpi) { if (!m_urlRedirector.isValid()) m_status = Invalid; @@ -259,7 +271,7 @@ TileProvider::TileProvider(const QString &urlTemplate, 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), m_highDpi(highDpi) + m_minimumZoomLevel(minimumZoomLevel), m_maximumZoomLevel(maximumZoomLevel), m_timestamp(defaultTs), m_highDpi(highDpi) { setupProvider(); } @@ -352,6 +364,7 @@ void TileProvider::onNetworkReplyFinished() * "StyleCopyRight" : "<copyright>", (optional) * "MinimumZoomLevel" : <minimumZoomLevel>, (optional) * "MaximumZoomLevel" : <maximumZoomLevel>, (optional) + * "Timestamp" : <timestamp>, (optional) * } * * Enabled is optional, and allows to temporarily disable a tile provider if it becomes @@ -361,27 +374,31 @@ void TileProvider::onNetworkReplyFinished() * requests to the providers, if they do not support the specific ZL. Default is 0 and 20, * respectively. * - * <server address template> is required, and is the tile url template, with %x, %y and %z as + * UrlTemplate 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. + * ImageFormat 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 + * 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 + * 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 + * StyleCopyRight is optional and is the string that will be displayed in the optional "Style (c)" part * of the on-screen copyright notice. + * + * Timestamp is optional, and if set will cause QtLocation to clear the content of the cache older + * than this timestamp. The purpose is to prevent mixing tiles from different providers in the cache + * upon provider change. The value must be a string in ISO 8601 format (see Qt::ISODate) */ QJsonParseError error; @@ -435,6 +452,10 @@ void TileProvider::onNetworkReplyFinished() if (maxZoom.isDouble()) m_maximumZoomLevel = qBound(0, int(maxZoom.toDouble()), maxValidZoom); + const QJsonValue ts = json.value(QLatin1String("Timestamp")); + if (ts.isString()) + m_timestamp = QDateTime::fromString(ts.toString(), Qt::ISODate); + setupProvider(); if (isValid()) { QObject::disconnect(errorEmitterConnection); @@ -553,6 +574,11 @@ int TileProvider::maximumZoomLevel() const return m_maximumZoomLevel; } +const QDateTime &TileProvider::timestamp() const +{ + return m_timestamp; +} + bool TileProvider::isHighDpi() const { return m_highDpi; @@ -563,6 +589,11 @@ void TileProvider::setStyleCopyRight(const QString ©right) m_copyRightStyle = copyright; } +void TileProvider::setTimestamp(const QDateTime ×tamp) +{ + m_timestamp = timestamp; +} + QUrl TileProvider::tileAddress(int x, int y, int z) const { if (z < m_minimumZoomLevel || z > m_maximumZoomLevel) @@ -591,7 +622,3 @@ TileProvider::Status TileProvider::status() const QT_END_NAMESPACE - - - - diff --git a/src/plugins/geoservices/osm/qgeotileproviderosm.h b/src/plugins/geoservices/osm/qgeotileproviderosm.h index cea832f0..b8647244 100644 --- a/src/plugins/geoservices/osm/qgeotileproviderosm.h +++ b/src/plugins/geoservices/osm/qgeotileproviderosm.h @@ -48,6 +48,7 @@ #include <algorithm> #include <QtCore/QJsonDocument> #include <QtCore/QJsonObject> +#include <QDateTime> QT_BEGIN_NAMESPACE @@ -90,11 +91,13 @@ public: inline QString format() const; inline int minimumZoomLevel() const; inline int maximumZoomLevel() const; + inline const QDateTime ×tamp() const; inline bool isHighDpi() const; QUrl tileAddress(int x, int y, int z) const; // Optional properties, not needed to construct a provider void setStyleCopyRight(const QString ©right); + void setTimestamp(const QDateTime ×tamp); Status m_status; QUrl m_urlRedirector; // The URL from where to fetch the URL template in case of a provider to resolve. @@ -108,6 +111,7 @@ public: QString m_urlSuffix; int m_minimumZoomLevel; int m_maximumZoomLevel; + QDateTime m_timestamp; bool m_highDpi; int paramsLUT[3]; //Lookup table to handle possibly shuffled x,y,z @@ -152,6 +156,7 @@ public: const QGeoMapType &mapType() const; bool isValid() const; bool isResolved() const; + const QDateTime timestamp() const; Q_SIGNALS: void resolutionFinished(const QGeoTileProviderOsm *provider); |