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 {
sizeToStr(int size)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 
isAerialType(const QString mapScheme)69     bool isAerialType(const QString mapScheme)
70     {
71         return mapScheme.startsWith("satellite") || mapScheme.startsWith("hybrid") || mapScheme.startsWith("terrain");
72     }
73 }
QGeoTileFetcherNokia(const QVariantMap & parameters,QGeoNetworkAccessManager * networkManager,QGeoTiledMappingManagerEngineNokia * engine,const QSize & tileSize,int ppi)74 QGeoTileFetcherNokia::QGeoTileFetcherNokia(const QVariantMap &parameters,
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(tileSize.width(), 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 
~QGeoTileFetcherNokia()91 QGeoTileFetcherNokia::~QGeoTileFetcherNokia()
92 {
93 }
94 
getTileImage(const QGeoTileSpec & spec)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("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(QNetworkRequest::HttpPipeliningAllowedAttribute, true);
117 
118     QNetworkReply *netReply = m_networkManager->get(netRequest);
119 
120     QGeoTiledMapReply *mapReply = new QGeoMapReplyNokia(netReply, spec);
121 
122     return mapReply;
123 }
124 
getRequestString(const QGeoTileSpec & spec,int ppi)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(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(m_tileSize * 2) : sizeToStr(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 
getLanguageString() const170 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 
token() const238 QString QGeoTileFetcherNokia::token() const
239 {
240     return m_token;
241 }
242 
applicationId() const243 QString QGeoTileFetcherNokia::applicationId() const
244 {
245     return m_applicationId;
246 }
247 
copyrightsFetched()248 void QGeoTileFetcherNokia::copyrightsFetched()
249 {
250     if (m_engineNokia && m_copyrightsReply->error() == QNetworkReply::NoError) {
251         QMetaObject::invokeMethod(m_engineNokia.data(),
252                                   "loadCopyrightsDescriptorsFromJson",
253                                   Qt::QueuedConnection,
254                                   Q_ARG(QByteArray, m_copyrightsReply->readAll()));
255     }
256 
257     m_copyrightsReply->deleteLater();
258 }
259 
versionFetched()260 void QGeoTileFetcherNokia::versionFetched()
261 {
262     if (m_engineNokia && m_versionReply->error() == QNetworkReply::NoError) {
263         QMetaObject::invokeMethod(m_engineNokia.data(),
264                                   "parseNewVersionInfo",
265                                   Qt::QueuedConnection,
266                                   Q_ARG(QByteArray, m_versionReply->readAll()));
267     }
268 
269     m_versionReply->deleteLater();
270 }
271 
fetchCopyrightsData()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(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(m_copyrightsReply, SIGNAL(finished()), this, SLOT(copyrightsFetched()));
301     }
302 }
303 
fetchVersionData()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(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(m_versionReply, SIGNAL(finished()), this, SLOT(versionFetched()));
334 }
335 
336 QT_END_NAMESPACE
337