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
qgeocodingmanagerengine_nokia.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
3
10
11#include <QtPositioning/QGeoAddress>
12#include <QtPositioning/QGeoCoordinate>
13#include <QtPositioning/QGeoCircle>
14#include <QtPositioning/QGeoRectangle>
15#include <QtPositioning/QGeoShape>
16
17#include <QUrl>
18#include <QMap>
19#include <QStringList>
20
22
24 QGeoNetworkAccessManager *networkManager,
25 const QVariantMap &parameters,
26 QGeoServiceProvider::Error *error,
27 QString *errorString)
28 : QGeoCodingManagerEngine(parameters)
29 , m_networkManager(networkManager)
30 , m_uriProvider(new QGeoUriProvider(this, parameters, QStringLiteral("here.geocoding.host"), GEOCODING_HOST))
31 , m_reverseGeocodingUriProvider(new QGeoUriProvider(this, parameters, QStringLiteral("here.reversegeocoding.host"), REVERSE_GEOCODING_HOST))
32{
33 Q_ASSERT(networkManager);
34 m_networkManager->setParent(this);
35
36 if (parameters.contains(QStringLiteral("here.apiKey")))
37 m_apiKey = parameters.value(QStringLiteral("here.apiKey")).toString();
38
39 if (error)
40 *error = QGeoServiceProvider::NoError;
41
42 if (errorString)
43 *errorString = "";
44}
45
47
48QString QGeoCodingManagerEngineNokia::getAuthenticationString() const
49{
50 QString authenticationString;
51
52 if (!m_apiKey.isEmpty()) {
53 authenticationString += "?apiKey=";
54 authenticationString += m_apiKey;
55 }
56
57 return authenticationString;
58}
59
60
62 const QGeoShape &bounds)
63{
64 QString requestString = "https://";
65 requestString += m_uriProvider->getCurrentHost();
66 requestString += "/6.2/geocode.json";
67
68 requestString += getAuthenticationString();
69 requestString += "&gen=9";
70
71 requestString += "&language=";
72 requestString += languageToMarc(locale().language());
73
74 bool manualBoundsRequired = false;
75 if (bounds.type() == QGeoShape::UnknownType) {
76 manualBoundsRequired = true;
77 } else if (bounds.type() == QGeoShape::CircleType) {
78 QGeoCircle circ(bounds);
79 if (circ.isValid()) {
80 requestString += "?prox=";
81 requestString += trimDouble(circ.center().latitude());
82 requestString += ",";
83 requestString += trimDouble(circ.center().longitude());
84 requestString += ",";
85 requestString += trimDouble(circ.radius());
86 }
87 } else {
88 QGeoRectangle rect = bounds.boundingGeoRectangle();
89 if (rect.isValid()) {
90 requestString += "&bbox=";
91 requestString += trimDouble(rect.topLeft().latitude());
92 requestString += ",";
93 requestString += trimDouble(rect.topLeft().longitude());
94 requestString += ";";
95 requestString += trimDouble(rect.bottomRight().latitude());
96 requestString += ",";
97 requestString += trimDouble(rect.bottomRight().longitude());
98 }
99 }
100
101 if (address.country().isEmpty()) {
102 QStringList parts;
103
104 if (!address.state().isEmpty())
105 parts << address.state();
106
107 if (!address.city().isEmpty())
108 parts << address.city();
109
110 if (!address.postalCode().isEmpty())
111 parts << address.postalCode();
112
113 if (!address.street().isEmpty())
114 parts << address.street();
115
116 requestString += "&searchtext=";
117 requestString += parts.join("+").replace(' ', '+');
118 } else {
119 requestString += "&country=";
120 requestString += address.country();
121
122 if (!address.state().isEmpty()) {
123 requestString += "&state=";
124 requestString += address.state();
125 }
126
127 if (!address.city().isEmpty()) {
128 requestString += "&city=";
129 requestString += address.city();
130 }
131
132 if (!address.postalCode().isEmpty()) {
133 requestString += "&postalcode=";
134 requestString += address.postalCode();
135 }
136
137 if (!address.street().isEmpty()) {
138 requestString += "&street=";
139 requestString += address.street();
140 }
141 }
142
143 return geocode(requestString, bounds, manualBoundsRequired);
144}
145
147 int limit,
148 int offset,
149 const QGeoShape &bounds)
150{
151 QString requestString = "https://";
152 requestString += m_uriProvider->getCurrentHost();
153 requestString += "/6.2/geocode.json";
154
155 requestString += getAuthenticationString();
156 requestString += "&gen=9";
157
158 requestString += "&language=";
159 requestString += languageToMarc(locale().language());
160
161 requestString += "&searchtext=";
162 requestString += QString(address).replace(' ', '+');
163
164 if (limit > 0) {
165 requestString += "&maxresults=";
166 requestString += QString::number(limit);
167 }
168 if (offset > 0) {
169 // We cannot do this precisely, since HERE doesn't allow
170 // precise result-set offset to be supplied; instead, it
171 // returns "pages" of results at a time.
172 // So, we tell HERE which page of results we want, and the
173 // client has to filter out duplicates if they changed
174 // the limit param since the last call.
175 requestString += "&pageinformation=";
176 requestString += QString::number(offset/limit);
177 }
178
179 bool manualBoundsRequired = false;
180 if (bounds.type() == QGeoShape::RectangleType) {
181 QGeoRectangle rect(bounds);
182 if (rect.isValid()) {
183 requestString += "&bbox=";
184 requestString += trimDouble(rect.topLeft().latitude());
185 requestString += ",";
186 requestString += trimDouble(rect.topLeft().longitude());
187 requestString += ";";
188 requestString += trimDouble(rect.bottomRight().latitude());
189 requestString += ",";
190 requestString += trimDouble(rect.bottomRight().longitude());
191 }
192 } else if (bounds.type() == QGeoShape::CircleType) {
193 QGeoCircle circ(bounds);
194 if (circ.isValid()) {
195 requestString += "?prox=";
196 requestString += trimDouble(circ.center().latitude());
197 requestString += ",";
198 requestString += trimDouble(circ.center().longitude());
199 requestString += ",";
200 requestString += trimDouble(circ.radius());
201 }
202 } else {
203 manualBoundsRequired = true;
204 }
205
206 return geocode(requestString, bounds, manualBoundsRequired, limit, offset);
207}
208
209QGeoCodeReply *QGeoCodingManagerEngineNokia::geocode(QString requestString,
210 const QGeoShape &bounds,
211 bool manualBoundsRequired,
212 int limit,
213 int offset)
214{
216 m_networkManager->get(QNetworkRequest(QUrl(requestString))),
217 limit, offset, bounds, manualBoundsRequired, this);
218
219 connect(reply, &QGeoCodeReplyNokia::finished,
220 this, &QGeoCodingManagerEngineNokia::placesFinished);
221
222 connect(reply, &QGeoCodeReplyNokia::errorOccurred,
223 this, &QGeoCodingManagerEngineNokia::placesError);
224
225 return reply;
226}
227
229 const QGeoShape &bounds)
230{
231 QString requestString = "https://";
232 requestString += m_reverseGeocodingUriProvider->getCurrentHost();
233 requestString += "/6.2/reversegeocode.json";
234
235 requestString += getAuthenticationString();
236 requestString += "&gen=9";
237
238 requestString += "&mode=retrieveAddresses";
239
240 requestString += "&prox=";
241 requestString += trimDouble(coordinate.latitude());
242 requestString += ",";
243 requestString += trimDouble(coordinate.longitude());
244
245 bool manualBoundsRequired = false;
246 if (bounds.type() == QGeoShape::CircleType) {
247 QGeoCircle circ(bounds);
248 if (circ.isValid() && circ.center() == coordinate) {
249 requestString += ",";
250 requestString += trimDouble(circ.radius());
251 } else {
252 manualBoundsRequired = true;
253 }
254 } else {
255 manualBoundsRequired = true;
256 }
257
258 requestString += "&language=";
259 requestString += languageToMarc(locale().language());
260
261 return geocode(requestString, bounds, manualBoundsRequired);
262}
263
264QString QGeoCodingManagerEngineNokia::trimDouble(double degree, int decimalDigits)
265{
266 QString sDegree = QString::number(degree, 'g', decimalDigits);
267
268 int index = sDegree.indexOf('.');
269
270 if (index == -1)
271 return sDegree;
272 else
273 return QString::number(degree, 'g', decimalDigits + index);
274}
275
276void QGeoCodingManagerEngineNokia::placesFinished()
277{
278 QGeoCodeReply *reply = qobject_cast<QGeoCodeReply *>(sender());
279
280 if (!reply)
281 return;
282
283 if (receivers(SIGNAL(finished(QGeoCodeReply*))) == 0) {
284 reply->deleteLater();
285 return;
286 }
287
288 emit finished(reply);
289}
290
291void QGeoCodingManagerEngineNokia::placesError(QGeoCodeReply::Error error, const QString &errorString)
292{
293 QGeoCodeReply *reply = qobject_cast<QGeoCodeReply *>(sender());
294
295 if (!reply)
296 return;
297
298 if (receivers(SIGNAL(errorOccurred(QGeoCodeReply*,QGeoCodeReply::Error,QString))) == 0) {
299 reply->deleteLater();
300 return;
301 }
302
303 emit errorOccurred(reply, error, errorString);
304}
305
306QString QGeoCodingManagerEngineNokia::languageToMarc(QLocale::Language language)
307{
308 uint offset = 3 * (uint(language));
309 if (language == QLocale::C || offset + 3 > sizeof(marc_language_code_list))
310 return QLatin1String("eng");
311
312 const unsigned char *c = marc_language_code_list + offset;
313 if (c[0] == 0)
314 return QLatin1String("eng");
315
316 QString code(3, Qt::Uninitialized);
317 code[0] = ushort(c[0]);
318 code[1] = ushort(c[1]);
319 code[2] = ushort(c[2]);
320
321 return code;
322}
323
324QT_END_NAMESPACE
QGeoCodeReply * geocode(const QString &searchString, int limit, int offset, const QGeoShape &bounds) override
Begins geocoding for a location matching address.
QGeoCodeReply * reverseGeocode(const QGeoCoordinate &coordinate, const QGeoShape &bounds) override
Begins the reverse geocoding of coordinate.
QGeoCodeReply * geocode(const QGeoAddress &address, const QGeoShape &bounds) override
Begins the geocoding of address.
static QT_BEGIN_NAMESPACE const unsigned char marc_language_code_list[]