Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qgeotileproviderosm.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 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
3
5
6#include <QtCore/QJsonDocument>
7#include <QtCore/QJsonObject>
8#include <QDebug>
9
11
12static const int maxValidZoom = 30;
13static const QDateTime defaultTs = QDateTime::fromString(QStringLiteral("2016-06-01T00:00:00"), Qt::ISODate);
14
15static void setSSL(QGeoMapType &mapType, bool isHTTPS)
16{
17 QVariantMap metadata = mapType.metadata();
18 metadata["isHTTPS"] = isHTTPS;
19
20 mapType = QGeoMapType(mapType.style(), mapType.name(), mapType.description(), mapType.mobile(),
21 mapType.night(), mapType.mapId(), mapType.pluginName(), mapType.cameraCapabilities(),
22 metadata);
23}
24
26 const QList<TileProvider *> &providers,
27 const QGeoCameraCapabilities &cameraCapabilities)
28 : m_nm(nm),
29 m_provider(nullptr),
30 m_mapType(mapType),
31 m_status(Idle),
32 m_cameraCapabilities(cameraCapabilities)
33{
34 for (int i = 0; i < providers.size(); ++i) {
35 TileProvider *p = providers[i];
36 if (!m_provider)
39 }
40
41 if (!m_provider || m_provider->isValid())
43
46
48}
49
51{
52}
53
55{
56 if (m_status != Resolved || !m_provider)
57 return QUrl();
58 return m_provider->tileAddress(x, y, z);
59}
60
62{
63 if (m_status != Resolved || !m_provider)
64 return QString();
65 return m_provider->mapCopyRight();
66}
67
69{
70 if (m_status != Resolved || !m_provider)
71 return QString();
72 return m_provider->dataCopyRight();
73}
74
76{
77 if (m_status != Resolved || !m_provider)
78 return QString();
79 return m_provider->styleCopyRight();
80}
81
83{
84 if (m_status != Resolved || !m_provider)
85 return QString();
86 return m_provider->format();
87}
88
90{
91 if (m_status != Resolved || !m_provider)
92 return 0;
94}
95
97{
98 if (m_status != Resolved || !m_provider)
99 return 20;
101}
102
104{
105 if (!m_provider)
106 return false;
107 return m_provider->isHighDpi();
108}
109
111{
112 if (!m_provider)
113 return QDateTime();
114 return m_provider->timestamp();
115}
116
118{
120}
121
123{
124 return m_mapType;
125}
126
128{
129 if (m_status != Resolved || !m_provider)
130 return false;
131 return m_provider->isValid();
132}
133
135{
136 return (m_status == Resolved);
137}
138
140{
141 if (m_status == Resolved || m_status == Resolving)
142 return;
143
145 // Provider can't be null while on Idle status.
149}
150
152{
153 if (m_provider && m_provider->isValid())
154 return;
155 bool found = false;
157 if (p->isValid() && !found) {
158 m_provider = p;
160 found = true;
161 }
162 p->disconnect(this);
163 }
165}
166
168{
169 Q_UNUSED(provider);
170 // provider and m_provider are the same, at this point. m_status is Resolving.
173}
174
176{
177 Q_UNUSED(provider);
178 // provider and m_provider are the same at this point. m_status is Resolving.
179 if (!m_provider || m_provider->isInvalid()) {
180 m_provider = nullptr;
182 if (m_providerId >= m_providerList.size() -1) { // no hope left
183 emit resolutionError(this);
184 return;
185 }
186 // Advance the pointer in the provider list, and possibly start resolution on the next in the list.
187 for (int i = m_providerId + 1; i < m_providerList.size(); ++i) {
188 m_providerId = i;
190 if (!p->isInvalid()) {
191 m_provider = p;
192 if (!p->isValid()) {
193 m_status = Idle;
194#if 0 // leaving triggering the retry to the tile fetcher, instead of constantly spinning it in here.
196 p->resolveProvider();
197#endif
199 }
200 break;
201 }
202 }
203 if (!m_provider)
204 emit resolutionError(this);
205 } else if (m_provider->isValid()) {
208 } else { // still not resolved. But network error is recoverable.
209 m_status = Idle;
210#if 0 // leaving triggering the retry to the tile fetcher
212#endif
213 }
214}
215
217{
218 // Set proper min/max ZoomLevel coming from the json, if available.
221
225
226 if (m_provider && m_provider->isValid())
228}
229
231{
232 if (!provider)
233 return;
234 std::unique_ptr<TileProvider> p(provider);
235 if (provider->status() == TileProvider::Invalid)
236 return; // if the provider is already resolved and invalid, no point in adding it.
237
238 provider = p.release();
239 provider->setNetworkManager(m_nm);
240 provider->setParent(this);
241 m_providerList.append(provider);
242 if (!m_provider)
243 m_provider = provider;
244}
245
246
247/*
248 Class TileProvder
249*/
250
251static void sort2(int &a, int &b)
252{
253 if (a > b) {
254 int temp=a;
255 a=b;
256 b=temp;
257 }
258}
259
260TileProvider::TileProvider() : m_status(Invalid), m_nm(nullptr), m_timestamp(defaultTs), m_highDpi(false)
261{
262
263}
264
265TileProvider::TileProvider(const QUrl &urlRedirector, bool highDpi)
266: m_status(Idle), m_urlRedirector(urlRedirector), m_nm(nullptr), m_timestamp(defaultTs), m_highDpi(highDpi)
267{
270}
271
273 const QString &format,
274 const QString &copyRightMap,
275 const QString &copyRightData,
276 bool highDpi,
277 int minimumZoomLevel,
278 int maximumZoomLevel)
279: m_status(Invalid), m_nm(nullptr), m_urlTemplate(urlTemplate),
280 m_format(format), m_copyRightMap(copyRightMap), m_copyRightData(copyRightData),
281 m_minimumZoomLevel(minimumZoomLevel), m_maximumZoomLevel(maximumZoomLevel), m_timestamp(defaultTs), m_highDpi(highDpi)
282{
284}
285
287{
288}
289
291{
292 if (!m_nm)
293 return;
294
295 switch (m_status) {
296 case Resolving:
297 case Invalid:
298 case Valid:
299 return;
300 case Idle:
302 break;
303 }
304
315}
316
318{
319 switch (error) {
330 // Errors we don't expect to recover from in the near future, which
331 // prevent accessing the redirection info but not the actual providers.
333 default:
334 //qWarning() << "QGeoTileProviderOsm network error:" << error;
335 break;
336 }
337}
338
340{
341 QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
343
344 switch (m_status) {
345 case Resolving:
346 m_status = Idle;
347 case Idle: // should not happen
348 case Invalid: // should not happen
349 break;
350 case Valid: // should not happen
352 return;
353 }
354
355 QObject errorEmitter;
356 QMetaObject::Connection errorEmitterConnection = connect(&errorEmitter, &QObject::destroyed, [this](){ this->resolutionError(this); });
357
358 if (reply->error() != QNetworkReply::NoError) {
360 return;
361 }
363
364 /*
365 * The content of a provider information file must be in JSON format, containing
366 * (as of Qt 5.6.2) the following fields:
367 *
368 * {
369 * "Enabled" : bool, (optional)
370 * "UrlTemplate" : "<url template>", (mandatory)
371 * "ImageFormat" : "<image format>", (mandatory)
372 * "MapCopyRight" : "<copyright>", (mandatory)
373 * "DataCopyRight" : "<copyright>", (mandatory)
374 * "StyleCopyRight" : "<copyright>", (optional)
375 * "MinimumZoomLevel" : <minimumZoomLevel>, (optional)
376 * "MaximumZoomLevel" : <maximumZoomLevel>, (optional)
377 * "Timestamp" : <timestamp>, (optional)
378 * }
379 *
380 * Enabled is optional, and allows to temporarily disable a tile provider if it becomes
381 * unavailable, without making the osm plugin fire requests to it. Default is true.
382 *
383 * MinimumZoomLevel and MaximumZoomLevel are also optional, and allow to prevent invalid tile
384 * requests to the providers, if they do not support the specific ZL. Default is 0 and 20,
385 * respectively.
386 *
387 * UrlTemplate is required, and is the tile url template, with %x, %y and %z as
388 * placeholders for the actual parameters.
389 * Example:
390 * http://localhost:8080/maps/%z/%x/%y.png
391 *
392 * ImageFormat is required, and is the format of the tile.
393 * Examples:
394 * "png", "jpg"
395 *
396 * MapCopyRight is required and is the string that will be displayed in the "Map (c)" part
397 * of the on-screen copyright notice. Can be an empty string.
398 * Example:
399 * "<a href='http://www.mapquest.com/'>MapQuest</a>"
400 *
401 * DataCopyRight is required and is the string that will be displayed in the "Data (c)" part
402 * of the on-screen copyright notice. Can be an empty string.
403 * Example:
404 * "<a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors"
405 *
406 * StyleCopyRight is optional and is the string that will be displayed in the optional "Style (c)" part
407 * of the on-screen copyright notice.
408 *
409 * Timestamp is optional, and if set will cause QtLocation to clear the content of the cache older
410 * than this timestamp. The purpose is to prevent mixing tiles from different providers in the cache
411 * upon provider change. The value must be a string in ISO 8601 format (see Qt::ISODate)
412 */
413
416 if (error.error != QJsonParseError::NoError) {
417 qWarning() << "QGeoTileProviderOsm: Error parsing redirection data: "<<error.errorString() << "at "<<m_urlRedirector;
418 return;
419 }
420 if (!d.isObject()) {
421 qWarning() << "QGeoTileProviderOsm: Invalid redirection data" << "at "<<m_urlRedirector;
422 return;
423 }
424 const QJsonObject json = d.object();
425 const QJsonValue urlTemplate = json.value(QLatin1String("UrlTemplate"));
426 const QJsonValue imageFormat = json.value(QLatin1String("ImageFormat"));
427 const QJsonValue copyRightMap = json.value(QLatin1String("MapCopyRight"));
428 const QJsonValue copyRightData = json.value(QLatin1String("DataCopyRight"));
429 if ( urlTemplate == QJsonValue::Undefined
430 || imageFormat == QJsonValue::Undefined
431 || copyRightMap == QJsonValue::Undefined
432 || copyRightData == QJsonValue::Undefined
433 || !urlTemplate.isString()
434 || !imageFormat.isString()
435 || !copyRightMap.isString()
436 || !copyRightData.isString()) {
437 qWarning() << "QGeoTileProviderOsm: Incomplete redirection data" << "at "<<m_urlRedirector;
438 return;
439 }
440
441 m_urlTemplate = urlTemplate.toString();
442 m_format = imageFormat.toString();
443 m_copyRightMap = copyRightMap.toString();
444 m_copyRightData = copyRightData.toString();
445
446 const QJsonValue enabled = json.value(QLatin1String("Enabled"));
447 if (enabled.isBool() && ! enabled.toBool()) {
448 qWarning() << "QGeoTileProviderOsm: Tileserver disabled" << "at "<<m_urlRedirector;
449 return;
450 }
451
452 const QJsonValue copyRightStyle = json.value(QLatin1String("StyleCopyRight"));
453 if (copyRightStyle != QJsonValue::Undefined && copyRightStyle.isString())
454 m_copyRightStyle = copyRightStyle.toString();
455
458 const QJsonValue minZoom = json.value(QLatin1String("MinimumZoomLevel"));
459 if (minZoom.isDouble())
460 m_minimumZoomLevel = qBound(0, int(minZoom.toDouble()), maxValidZoom);
461 const QJsonValue maxZoom = json.value(QLatin1String("MaximumZoomLevel"));
462 if (maxZoom.isDouble())
463 m_maximumZoomLevel = qBound(0, int(maxZoom.toDouble()), maxValidZoom);
464
465 const QJsonValue ts = json.value(QLatin1String("Timestamp"));
466 if (ts.isString())
467 m_timestamp = QDateTime::fromString(ts.toString(), Qt::ISODate);
468
470 if (isValid()) {
471 QObject::disconnect(errorEmitterConnection);
473 }
474}
475
477{
478 if (m_status == Resolving)
479 m_status = Idle;
480
482 static_cast<QNetworkReply *>(sender())->deleteLater();
483 emit resolutionError(this);
484}
485
487{
489 return;
490
491 if (m_format.isEmpty())
492 return;
493
494 if (m_minimumZoomLevel < 0 || m_minimumZoomLevel > 30)
495 return;
496
497 if (m_maximumZoomLevel < 0 || m_maximumZoomLevel > 30 || m_maximumZoomLevel < m_minimumZoomLevel)
498 return;
499
500 // Currently supporting only %x, %y and &z
501 int offset[3];
503 if (offset[0] < 0)
504 return;
505
507 if (offset[1] < 0)
508 return;
509
511 if (offset[2] < 0)
512 return;
513
514 int sortedOffsets[3];
515 std::copy(offset, offset + 3, sortedOffsets);
516 sort2(sortedOffsets[0] ,sortedOffsets[1]);
517 sort2(sortedOffsets[1] ,sortedOffsets[2]);
518 sort2(sortedOffsets[0] ,sortedOffsets[1]);
519
520 int min = sortedOffsets[0];
521 int max = sortedOffsets[2];
522 int mid = sortedOffsets[1];
523
524 // Initing LUT
525 for (int i=0; i<3; i++) {
526 if (offset[0] == sortedOffsets[i])
527 paramsLUT[i] = 0;
528 else if (offset[1] == sortedOffsets[i])
529 paramsLUT[i] = 1;
530 else
531 paramsLUT[i] = 2;
532 }
533
534 m_urlPrefix = m_urlTemplate.mid(0 , min);
535 m_urlSuffix = m_urlTemplate.mid(max + 2, m_urlTemplate.size() - max - 2);
536
537 paramsSep[0] = m_urlTemplate.mid(min + 2, mid - min - 2);
538 paramsSep[1] = m_urlTemplate.mid(mid + 2, max - mid - 2);
539 m_status = Valid;
540}
541
543{
544 return m_status == Valid;
545}
546
548{
549 return m_status == Invalid;
550}
551
553{
554 return (m_status == Valid || m_status == Invalid);
555}
556
558{
559 return m_copyRightMap;
560}
561
563{
564 return m_copyRightData;
565}
566
568{
569 return m_copyRightStyle;
570}
571
573{
574 return m_format;
575}
576
578{
579 return m_minimumZoomLevel;
580}
581
583{
584 return m_maximumZoomLevel;
585}
586
588{
589 return m_timestamp;
590}
591
593{
594 return m_highDpi;
595}
596
598{
599 return m_urlTemplate.startsWith(QStringLiteral("https"));
600}
601
603{
604 m_copyRightStyle = copyright;
605}
606
608{
610}
611
612QUrl TileProvider::tileAddress(int x, int y, int z) const
613{
614 if (z < m_minimumZoomLevel || z > m_maximumZoomLevel)
615 return QUrl();
616 int params[3] = { x, y, z};
617 QString url;
618 url += m_urlPrefix;
620 url += paramsSep[0];
622 url += paramsSep[1];
624 url += m_urlSuffix;
625 return QUrl(url);
626}
627
629{
630 m_nm = nm;
631}
632
634{
635 return m_status;
636}
637
638
\inmodule QtCore\reentrant
Definition qdatetime.h:257
void setMaximumZoomLevel(double maximumZoomLevel)
void setMinimumZoomLevel(double minimumZoomLevel)
QML_STRUCTURED_VALUEMapStyle style
QVariantMap metadata
QByteArray pluginName() const
int mapId() const
QString description
QGeoCameraCapabilities cameraCapabilities
QGeoTileProviderOsm(QNetworkAccessManager *nm, const QGeoMapType &mapType, const QList< TileProvider * > &providers, const QGeoCameraCapabilities &cameraCapabilities)
QNetworkAccessManager * m_nm
void onResolutionFinished(TileProvider *provider)
QString dataCopyRight() const
const QGeoMapType & mapType() const
QGeoCameraCapabilities m_cameraCapabilities
QGeoCameraCapabilities cameraCapabilities() const
QDateTime timestamp() const
void onResolutionError(TileProvider *provider)
QList< TileProvider * > m_providerList
void addProvider(TileProvider *provider)
void resolutionFinished(const QGeoTileProviderOsm *provider)
QString styleCopyRight() const
void resolutionError(const QGeoTileProviderOsm *provider)
QUrl tileAddress(int x, int y, int z) const
QByteArray readAll()
Reads all remaining data from the device, and returns it as a byte array.
\inmodule QtCore\reentrant
static QJsonDocument fromJson(const QByteArray &json, QJsonParseError *error=nullptr)
Parses json as a UTF-8 encoded JSON document, and creates a QJsonDocument from it.
\inmodule QtCore\reentrant
Definition qjsonobject.h:20
QJsonValue value(const QString &key) const
Returns a QJsonValue representing the value for the key key.
\inmodule QtCore\reentrant
Definition qjsonvalue.h:24
bool isString() const
Returns true if the value contains a string.
Definition qjsonvalue.h:74
bool isDouble() const
Returns true if the value contains a double.
Definition qjsonvalue.h:73
double toDouble(double defaultValue=0) const
Converts the value to a double and returns it.
QString toString() const
Converts the value to a QString and returns it.
Definition qlist.h:74
qsizetype size() const noexcept
Definition qlist.h:386
void append(parameter_type t)
Definition qlist.h:441
\inmodule QtCore Represents a handle to a signal-slot (or signal-functor) connection.
The QNetworkAccessManager class allows the application to send network requests and receive replies.
QNetworkReply * get(const QNetworkRequest &request)
Posts a request to obtain the contents of the target request and returns a new QNetworkReply object o...
The QNetworkReply class contains the data and headers for a request sent with QNetworkAccessManager.
void errorOccurred(QNetworkReply::NetworkError)
NetworkError error() const
Returns the error that was found during the processing of this request.
NetworkError
Indicates all possible error conditions found during the processing of the request.
@ ContentOperationNotPermittedError
@ OperationNotImplementedError
@ AuthenticationRequiredError
void finished()
This signal is emitted when the reply has finished processing.
The QNetworkRequest class holds a request to be sent with QNetworkAccessManager.
void setHeader(KnownHeaders header, const QVariant &value)
Sets the value of the known header header to be value, overriding any previously set headers.
void setAttribute(Attribute code, const QVariant &value)
Sets the attribute associated with code code to be value value.
void setUrl(const QUrl &url)
Sets the URL this network request is referring to be url.
\inmodule QtCore
Definition qobject.h:90
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2823
QObject * sender() const
Returns a pointer to the object that sent the signal, if called in a slot activated by a signal; othe...
Definition qobject.cpp:2521
void setParent(QObject *parent)
Makes the object a child of parent.
Definition qobject.cpp:2142
static bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *member)
\threadsafe
Definition qobject.cpp:3099
void destroyed(QObject *=nullptr)
This signal is emitted immediately before the object obj is destroyed, after any instances of QPointe...
void deleteLater()
\threadsafe
Definition qobject.cpp:2352
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
bool startsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string starts with s; otherwise returns false.
Definition qstring.cpp:5299
qsizetype size() const
Returns the number of characters in this string.
Definition qstring.h:182
QString mid(qsizetype position, qsizetype n=-1) const
Returns a string that contains n characters of this string, starting at the specified position index.
Definition qstring.cpp:5204
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:1083
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:7822
static QString static QString qsizetype indexOf(QChar c, qsizetype from=0, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition qstring.cpp:4420
\inmodule QtCore
Definition qurl.h:94
bool isValid() const
Returns true if the URL is non-empty and valid; otherwise returns false.
Definition qurl.cpp:1874
int minimumZoomLevel() const
void handleError(QNetworkReply::NetworkError error)
void onNetworkReplyError(QNetworkReply::NetworkError error)
int maximumZoomLevel() const
QString styleCopyRight() const
QString dataCopyRight() const
void resolutionFinished(TileProvider *provider)
bool isResolved() const
Status status() const
void setStyleCopyRight(const QString &copyright)
void setNetworkManager(QNetworkAccessManager *nm)
QString mapCopyRight() const
QUrl tileAddress(int x, int y, int z) const
QNetworkAccessManager * m_nm
QString format() const
const QDateTime & timestamp() const
void resolutionError(TileProvider *provider)
void setTimestamp(const QDateTime &timestamp)
Combined button and popup list for selecting options.
@ ISODate
#define QByteArrayLiteral(str)
Definition qbytearray.h:52
DBusConnection const char DBusError * error
static void sort2(int &a, int &b)
static const QDateTime defaultTs
static void setSSL(QGeoMapType &mapType, bool isHTTPS)
static QT_BEGIN_NAMESPACE const int maxValidZoom
#define qWarning
Definition qlogging.h:162
@ Invalid
constexpr const T & qBound(const T &min, const T &val, const T &max)
Definition qminmax.h:44
GLboolean GLboolean GLboolean b
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat z
GLint GLint GLint GLint GLint x
[0]
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLenum GLsizei const GLuint GLboolean enabled
GLenum GLuint GLintptr offset
GLint GLsizei GLsizei GLenum format
GLint y
void ** params
GLfloat GLfloat p
[1]
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
#define QStringLiteral(str)
#define emit
#define Q_UNUSED(x)
QUrl url("example.com")
[constructor-url-reference]
QObject::connect nullptr
QNetworkRequest request(url)
QNetworkReply * reply
\inmodule QtCore\reentrant
qsizetype indexOf(const AT &t, qsizetype from=0) const noexcept
Definition qlist.h:955