Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qgeotilerequestmanager.cpp
Go to the documentation of this file.
1// Copyright (C) 2015 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
8
9#include <QtCore/QPointer>
10#include <QtCore/QTimer>
11
12QT_BEGIN_NAMESPACE
13
14class RetryFuture;
15
17{
18public:
19 explicit QGeoTileRequestManagerPrivate(QGeoTiledMap *map, QGeoTiledMappingManagerEngine *engine);
21
22 QGeoTiledMap *m_map;
24
25 QMap<QGeoTileSpec, QSharedPointer<QGeoTileTexture> > requestTiles(const QSet<QGeoTileSpec> &tiles);
26 void tileError(const QGeoTileSpec &tile, const QString &errorString);
27
31
32 void tileFetched(const QGeoTileSpec &spec);
33};
34
35QGeoTileRequestManager::QGeoTileRequestManager(QGeoTiledMap *map, QGeoTiledMappingManagerEngine *engine)
36 : d_ptr(new QGeoTileRequestManagerPrivate(map, engine))
37{
38
39}
40
41QGeoTileRequestManager::~QGeoTileRequestManager()
42{
43
44}
45
46QMap<QGeoTileSpec, QSharedPointer<QGeoTileTexture> > QGeoTileRequestManager::requestTiles(const QSet<QGeoTileSpec> &tiles)
47{
48 return d_ptr->requestTiles(tiles);
49}
50
51void QGeoTileRequestManager::tileFetched(const QGeoTileSpec &spec)
52{
53 d_ptr->tileFetched(spec);
54}
55
56QSharedPointer<QGeoTileTexture> QGeoTileRequestManager::tileTexture(const QGeoTileSpec &spec)
57{
58 if (d_ptr->m_engine)
59 return d_ptr->m_engine->getTileTexture(spec);
60 else
61 return QSharedPointer<QGeoTileTexture>();
62}
63
64void QGeoTileRequestManager::tileError(const QGeoTileSpec &tile, const QString &errorString)
65{
66 d_ptr->tileError(tile, errorString);
67}
68
69QGeoTileRequestManagerPrivate::QGeoTileRequestManagerPrivate(QGeoTiledMap *map,QGeoTiledMappingManagerEngine *engine)
70 : m_map(map),
72{
73}
74
78
80{
81 QSet<QGeoTileSpec> cancelTiles = m_requested - tiles;
82 QSet<QGeoTileSpec> requestTiles = tiles - m_requested;
83 QSet<QGeoTileSpec> cached;
84// int tileSize = tiles.size();
85// int newTiles = requestTiles.size();
86
87 typedef QSet<QGeoTileSpec>::const_iterator iter;
88
89 QMap<QGeoTileSpec, QSharedPointer<QGeoTileTexture> > cachedTex;
90
91 // remove tiles in cache from request tiles
92 if (!m_engine.isNull()) {
93 iter i = requestTiles.constBegin();
94 iter end = requestTiles.constEnd();
95 for (; i != end; ++i) {
96 QGeoTileSpec tile = *i;
97 QSharedPointer<QGeoTileTexture> tex = m_engine->getTileTexture(tile);
98 if (tex) {
99 if (!tex->image.isNull())
100 cachedTex.insert(tile, tex);
101 cached.insert(tile);
102 } else {
103 // Try to use textures from lower zoom levels, but still request the proper tile
104 QGeoTileSpec spec = tile;
105 const int endRange = qMax(0, tile.zoom() - 4); // Using up to 4 zoom levels up. 4 is arbitrary.
106 for (int z = tile.zoom() - 1; z >= endRange; z--) {
107 int denominator = 1 << (tile.zoom() - z);
108 spec.setZoom(z);
109 spec.setX(tile.x() / denominator);
110 spec.setY(tile.y() / denominator);
111 QSharedPointer<QGeoTileTexture> t = m_engine->getTileTexture(spec);
112 if (t && !t->image.isNull()) {
113 cachedTex.insert(tile, t);
114 break;
115 }
116 }
117 }
118 }
119 }
120
121 requestTiles -= cached;
122
123 m_requested -= cancelTiles;
124 m_requested += requestTiles;
125
126// qDebug() << "required # tiles: " << tileSize << ", new tiles: " << newTiles << ", total server requests: " << requested_.size();
127
128 if (!requestTiles.isEmpty() || !cancelTiles.isEmpty()) {
129 if (!m_engine.isNull()) {
130// qDebug() << "new server requests: " << requestTiles.size() << ", server cancels: " << cancelTiles.size();
131 m_engine->updateTileRequests(m_map, requestTiles, cancelTiles);
132
133 // Remove any cancelled tiles from the error retry hash to avoid
134 // re-using the numbers for a totally different request cycle.
135 iter i = cancelTiles.constBegin();
136 iter end = cancelTiles.constEnd();
137 for (; i != end; ++i) {
138 m_retries.remove(*i);
139 m_futures.remove(*i);
140 }
141 }
142 }
143
144 return cachedTex;
145}
146
147void QGeoTileRequestManagerPrivate::tileFetched(const QGeoTileSpec &spec)
148{
149 m_map->updateTile(spec);
150 m_requested.remove(spec);
151 m_retries.remove(spec);
152 m_futures.remove(spec);
153}
154
155// Represents a tile that needs to be retried after a certain period of time
156class RetryFuture : public QObject
157{
159public:
161
162public Q_SLOTS:
163 void retry();
164
165private:
166 QGeoTileSpec m_tile;
167 QGeoTiledMap *m_map;
168 QPointer<QGeoTiledMappingManagerEngine> m_engine;
169};
170
171RetryFuture::RetryFuture(const QGeoTileSpec &tile, QGeoTiledMap *map, QGeoTiledMappingManagerEngine* engine, QObject *parent)
172 : QObject(parent), m_tile(tile), m_map(map), m_engine(engine)
173{}
174
175void RetryFuture::retry()
176{
177 QSet<QGeoTileSpec> requestTiles;
178 QSet<QGeoTileSpec> cancelTiles;
179 requestTiles.insert(m_tile);
180 if (!m_engine.isNull())
181 m_engine->updateTileRequests(m_map, requestTiles, cancelTiles);
182}
183
184void QGeoTileRequestManagerPrivate::tileError(const QGeoTileSpec &tile, const QString &errorString)
185{
186 if (m_requested.contains(tile)) {
187 int count = m_retries.value(tile, 0);
188 m_retries.insert(tile, count + 1);
189
190 if (count >= 5) {
191 qWarning("QGeoTileRequestManager: Failed to fetch tile (%d,%d,%d) 5 times, giving up. "
192 "Last error message was: '%s'",
193 tile.x(), tile.y(), tile.zoom(), qPrintable(errorString));
194 m_requested.remove(tile);
195 m_retries.remove(tile);
196 m_futures.remove(tile);
197
198 } else {
199 // Exponential time backoff when retrying
200 int delay = (1 << count) * 500;
201
202 QSharedPointer<RetryFuture> future(new RetryFuture(tile,m_map,m_engine));
203 m_futures.insert(tile, future);
204
205 QTimer::singleShot(delay, future.data(), &RetryFuture::retry);
206 // Passing .data() to singleShot is ok -- Qt will clean up the
207 // connection if the target qobject is deleted
208 }
209 }
210}
211
212QT_END_NAMESPACE
213
214#include "qgeotilerequestmanager.moc"
QMap< QGeoTileSpec, QSharedPointer< QGeoTileTexture > > requestTiles(const QSet< QGeoTileSpec > &tiles)
void tileError(const QGeoTileSpec &tile, const QString &errorString)
void tileFetched(const QGeoTileSpec &spec)
QGeoTileRequestManagerPrivate(QGeoTiledMap *map, QGeoTiledMappingManagerEngine *engine)
QHash< QGeoTileSpec, int > m_retries
QPointer< QGeoTiledMappingManagerEngine > m_engine
QHash< QGeoTileSpec, QSharedPointer< RetryFuture > > m_futures