1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2015 The Qt Company Ltd. |
4 | ** Contact: http://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the QtLocation module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL3$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see http://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at http://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPLv3 included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 3 requirements |
23 | ** will be met: https://www.gnu.org/licenses/lgpl.html. |
24 | ** |
25 | ** GNU General Public License Usage |
26 | ** Alternatively, this file may be used under the terms of the GNU |
27 | ** General Public License version 2.0 or later as published by the Free |
28 | ** Software Foundation and appearing in the file LICENSE.GPL included in |
29 | ** the packaging of this file. Please review the following information to |
30 | ** ensure the GNU General Public License version 2.0 requirements will be |
31 | ** met: http://www.gnu.org/licenses/gpl-2.0.html. |
32 | ** |
33 | ** $QT_END_LICENSE$ |
34 | ** |
35 | ****************************************************************************/ |
36 | |
37 | #include "qgeotilefetcher_nokia.h" |
38 | #include "qgeomapreply_nokia.h" |
39 | #include "qgeotiledmap_nokia.h" |
40 | #include "qgeotiledmappingmanagerengine_nokia.h" |
41 | #include "qgeonetworkaccessmanager.h" |
42 | #include "qgeouriprovider.h" |
43 | #include "uri_constants.h" |
44 | |
45 | #include <QtLocation/private/qgeotilespec_p.h> |
46 | |
47 | #include <QDebug> |
48 | #include <QSize> |
49 | #include <QDir> |
50 | #include <QUrl> |
51 | #include <QTime> |
52 | |
53 | #include <map> |
54 | |
55 | QT_BEGIN_NAMESPACE |
56 | |
57 | namespace |
58 | { |
59 | QString sizeToStr(int size) |
60 | { |
61 | if (size > 256) |
62 | return QStringLiteral("512" ); |
63 | else if (size > 128) |
64 | return QStringLiteral("256" ); |
65 | else |
66 | return QStringLiteral("128" ); // 128 pixel tiles are deprecated. |
67 | } |
68 | |
69 | bool isAerialType(const QString mapScheme) |
70 | { |
71 | return mapScheme.startsWith(s: "satellite" ) || mapScheme.startsWith(s: "hybrid" ) || mapScheme.startsWith(s: "terrain" ); |
72 | } |
73 | } |
74 | QGeoTileFetcherNokia::QGeoTileFetcherNokia(const QVariantMap ¶meters, |
75 | QGeoNetworkAccessManager *networkManager, |
76 | QGeoTiledMappingManagerEngineNokia *engine, |
77 | const QSize &tileSize, |
78 | int ppi) |
79 | : QGeoTileFetcher(engine), m_engineNokia(engine), m_networkManager(networkManager), m_ppi(ppi), m_copyrightsReply(0), |
80 | m_baseUriProvider(new QGeoUriProvider(this, parameters, QStringLiteral("here.mapping.host" ), MAP_TILES_HOST)), |
81 | m_aerialUriProvider(new QGeoUriProvider(this, parameters, QStringLiteral("here.mapping.host.aerial" ), MAP_TILES_HOST_AERIAL)) |
82 | { |
83 | Q_ASSERT(networkManager); |
84 | m_tileSize = qMax(a: tileSize.width(), b: tileSize.height()); |
85 | m_networkManager->setParent(this); |
86 | |
87 | m_applicationId = parameters.value(QStringLiteral("here.app_id" )).toString(); |
88 | m_token = parameters.value(QStringLiteral("here.token" )).toString(); |
89 | } |
90 | |
91 | QGeoTileFetcherNokia::~QGeoTileFetcherNokia() |
92 | { |
93 | } |
94 | |
95 | QGeoTiledMapReply *QGeoTileFetcherNokia::getTileImage(const QGeoTileSpec &spec) |
96 | { |
97 | // TODO add error detection for if request.connectivityMode() != QGraphicsGeoMap::OnlineMode |
98 | int ppi = m_ppi; |
99 | if ((spec.mapId() == 2) || (spec.mapId() == 12) || (spec.mapId() == 21)) { |
100 | ppi = 72; // HiDpi apparently not supported for these maps |
101 | } else if ((spec.mapId() >= 7 && spec.mapId() <= 11) |
102 | || (spec.mapId() == 14) |
103 | || (spec.mapId() == 16) |
104 | || (spec.mapId() == 18) |
105 | || (spec.mapId() == 20)) { |
106 | ppi = 250; // LoDpi apparently not supported for these maps |
107 | } |
108 | |
109 | QString rawRequest = getRequestString(spec, ppi); |
110 | if (rawRequest.isEmpty()) { |
111 | return new QGeoTiledMapReply(QGeoTiledMapReply::UnknownError, |
112 | tr(s: "Mapping manager no longer exists" ), this); |
113 | } |
114 | |
115 | QNetworkRequest netRequest((QUrl(rawRequest))); // The extra pair of parens disambiguates this from a function declaration |
116 | netRequest.setAttribute(code: QNetworkRequest::HttpPipeliningAllowedAttribute, value: true); |
117 | |
118 | QNetworkReply *netReply = m_networkManager->get(request: netRequest); |
119 | |
120 | QGeoTiledMapReply *mapReply = new QGeoMapReplyNokia(netReply, spec); |
121 | |
122 | return mapReply; |
123 | } |
124 | |
125 | QString QGeoTileFetcherNokia::getRequestString(const QGeoTileSpec &spec, int ppi) |
126 | { |
127 | if (!m_engineNokia) |
128 | return QString(); |
129 | |
130 | static const QString http("http://" ); |
131 | static const QString path("/maptile/2.1/maptile/newest/" ); |
132 | static const QChar slash('/'); |
133 | |
134 | QString requestString = http; |
135 | |
136 | const QString mapScheme = m_engineNokia->getScheme(mapId: spec.mapId()); |
137 | if (isAerialType(mapScheme)) |
138 | requestString += m_aerialUriProvider->getCurrentHost(); |
139 | else |
140 | requestString += m_baseUriProvider->getCurrentHost(); |
141 | |
142 | requestString += path; |
143 | requestString += mapScheme; |
144 | requestString += slash; |
145 | requestString += QString::number(spec.zoom()); |
146 | requestString += slash; |
147 | requestString += QString::number(spec.x()); |
148 | requestString += slash; |
149 | requestString += QString::number(spec.y()); |
150 | requestString += slash; |
151 | requestString += ((ppi > 72)) ? sizeToStr(size: m_tileSize * 2) : sizeToStr(size: m_tileSize); |
152 | static const QString slashpng("/png8" ); |
153 | requestString += slashpng; |
154 | |
155 | if (!m_token.isEmpty() && !m_applicationId.isEmpty()) { // TODO: remove the if |
156 | requestString += "?token=" ; |
157 | requestString += m_token; |
158 | |
159 | requestString += "&app_id=" ; |
160 | requestString += m_applicationId; |
161 | } |
162 | |
163 | requestString += "&ppi=" + QString::number(ppi); |
164 | |
165 | requestString += "&lg=" ; |
166 | requestString += getLanguageString(); |
167 | return requestString; |
168 | } |
169 | |
170 | QString QGeoTileFetcherNokia::getLanguageString() const |
171 | { |
172 | if (!m_engineNokia) |
173 | return QStringLiteral("ENG" ); |
174 | |
175 | QLocale locale = m_engineNokia.data()->locale(); |
176 | |
177 | // English is the default, where no ln is specified. We hardcode the languages |
178 | // here even though the entire list is updated automagically from the server. |
179 | // The current languages are Arabic, Chinese, Simplified Chinese, English |
180 | // French, German, Italian, Polish, Russian and Spanish. The default is English. |
181 | // These are actually available from the same host under the URL: /maptiler/v2/info |
182 | |
183 | switch (locale.language()) { |
184 | case QLocale::Arabic: |
185 | return QStringLiteral("ARA" ); |
186 | case QLocale::Chinese: |
187 | if (locale.script() == QLocale::TraditionalChineseScript) |
188 | return QStringLiteral("CHI" ); |
189 | else |
190 | return QStringLiteral("CHT" ); |
191 | case QLocale::Dutch: |
192 | return QStringLiteral("DUT" ); |
193 | case QLocale::French: |
194 | return QStringLiteral("FRE" ); |
195 | case QLocale::German: |
196 | return QStringLiteral("GER" ); |
197 | case QLocale::Gaelic: |
198 | return QStringLiteral("GLE" ); |
199 | case QLocale::Greek: |
200 | return QStringLiteral("GRE" ); |
201 | case QLocale::Hebrew: |
202 | return QStringLiteral("HEB" ); |
203 | case QLocale::Hindi: |
204 | return QStringLiteral("HIN" ); |
205 | case QLocale::Indonesian: |
206 | return QStringLiteral("IND" ); |
207 | case QLocale::Italian: |
208 | return QStringLiteral("ITA" ); |
209 | case QLocale::Persian: |
210 | return QStringLiteral("PER" ); |
211 | case QLocale::Polish: |
212 | return QStringLiteral("POL" ); |
213 | case QLocale::Portuguese: |
214 | return QStringLiteral("POR" ); |
215 | case QLocale::Russian: |
216 | return QStringLiteral("RUS" ); |
217 | case QLocale::Sinhala: |
218 | return QStringLiteral("SIN" ); |
219 | case QLocale::Spanish: |
220 | return QStringLiteral("SPA" ); |
221 | case QLocale::Thai: |
222 | return QStringLiteral("THA" ); |
223 | case QLocale::Turkish: |
224 | return QStringLiteral("TUR" ); |
225 | case QLocale::Ukrainian: |
226 | return QStringLiteral("UKR" ); |
227 | case QLocale::Urdu: |
228 | return QStringLiteral("URD" ); |
229 | case QLocale::Vietnamese: |
230 | return QStringLiteral("VIE" ); |
231 | |
232 | default: |
233 | return QStringLiteral("ENG" ); |
234 | } |
235 | // No "lg" param means that we want English. |
236 | } |
237 | |
238 | QString QGeoTileFetcherNokia::token() const |
239 | { |
240 | return m_token; |
241 | } |
242 | |
243 | QString QGeoTileFetcherNokia::applicationId() const |
244 | { |
245 | return m_applicationId; |
246 | } |
247 | |
248 | void QGeoTileFetcherNokia::copyrightsFetched() |
249 | { |
250 | if (m_engineNokia && m_copyrightsReply->error() == QNetworkReply::NoError) { |
251 | QMetaObject::invokeMethod(obj: m_engineNokia.data(), |
252 | member: "loadCopyrightsDescriptorsFromJson" , |
253 | type: Qt::QueuedConnection, |
254 | Q_ARG(QByteArray, m_copyrightsReply->readAll())); |
255 | } |
256 | |
257 | m_copyrightsReply->deleteLater(); |
258 | } |
259 | |
260 | void QGeoTileFetcherNokia::versionFetched() |
261 | { |
262 | if (m_engineNokia && m_versionReply->error() == QNetworkReply::NoError) { |
263 | QMetaObject::invokeMethod(obj: m_engineNokia.data(), |
264 | member: "parseNewVersionInfo" , |
265 | type: Qt::QueuedConnection, |
266 | Q_ARG(QByteArray, m_versionReply->readAll())); |
267 | } |
268 | |
269 | m_versionReply->deleteLater(); |
270 | } |
271 | |
272 | void QGeoTileFetcherNokia::fetchCopyrightsData() |
273 | { |
274 | QString copyrightUrl = QStringLiteral("http://" ); |
275 | |
276 | copyrightUrl += m_baseUriProvider->getCurrentHost(); |
277 | copyrightUrl += QStringLiteral("/maptile/2.1/copyright/newest?output=json" ); |
278 | |
279 | if (!token().isEmpty()) { |
280 | copyrightUrl += QStringLiteral("&token=" ); |
281 | copyrightUrl += token(); |
282 | } |
283 | |
284 | if (!applicationId().isEmpty()) { |
285 | copyrightUrl += QStringLiteral("&app_id=" ); |
286 | copyrightUrl += applicationId(); |
287 | } |
288 | |
289 | QNetworkRequest netRequest((QUrl(copyrightUrl))); |
290 | m_copyrightsReply = m_networkManager->get(request: netRequest); |
291 | if (m_copyrightsReply->error() != QNetworkReply::NoError) { |
292 | qWarning() << __FUNCTION__ << m_copyrightsReply->errorString(); |
293 | m_copyrightsReply->deleteLater(); |
294 | return; |
295 | } |
296 | |
297 | if (m_copyrightsReply->isFinished()) { |
298 | copyrightsFetched(); |
299 | } else { |
300 | connect(sender: m_copyrightsReply, SIGNAL(finished()), receiver: this, SLOT(copyrightsFetched())); |
301 | } |
302 | } |
303 | |
304 | void QGeoTileFetcherNokia::fetchVersionData() |
305 | { |
306 | QString versionUrl = QStringLiteral("http://" ); |
307 | |
308 | versionUrl += m_baseUriProvider->getCurrentHost(); |
309 | versionUrl += QStringLiteral("/maptile/2.1/version" ); |
310 | |
311 | if (!token().isEmpty()) { |
312 | versionUrl += QStringLiteral("?token=" ); |
313 | versionUrl += token(); |
314 | } |
315 | |
316 | if (!applicationId().isEmpty()) { |
317 | versionUrl += QStringLiteral("&app_id=" ); |
318 | versionUrl += applicationId(); |
319 | } |
320 | |
321 | QNetworkRequest netRequest((QUrl(versionUrl))); |
322 | m_versionReply = m_networkManager->get(request: netRequest); |
323 | |
324 | if (m_versionReply->error() != QNetworkReply::NoError) { |
325 | qWarning() << __FUNCTION__ << m_versionReply->errorString(); |
326 | m_versionReply->deleteLater(); |
327 | return; |
328 | } |
329 | |
330 | if (m_versionReply->isFinished()) |
331 | versionFetched(); |
332 | else |
333 | connect(sender: m_versionReply, SIGNAL(finished()), receiver: this, SLOT(versionFetched())); |
334 | } |
335 | |
336 | QT_END_NAMESPACE |
337 | |