summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Adams <chris.adams@jollamobile.com>2016-11-04 15:14:07 +1000
committerAlex Blasche <alexander.blasche@qt.io>2016-11-16 06:36:23 +0000
commit78c73ebf88fbb97ebb796fc71e76232af5c8f1d3 (patch)
treeb225fea6cf830aa3b32eb316387e23de29f9f5df
parent81f626f062d95abe49fcb7d8f098e54646c04034 (diff)
downloadqtlocation-78c73ebf88fbb97ebb796fc71e76232af5c8f1d3.tar.gz
Update "nokia" geoservices plugin to use HERE APIs
The old Nokia URL endpoints are being deprecated. This commit updates the "nokia" plugin to use the modern HERE API endpoints. It also removes the (now nonexistent) China-specific URLs. Change-Id: Ieaf75cef1538d0ebb6a22623fc041ab504cf491f Reviewed-by: Alex Blasche <alexander.blasche@qt.io>
-rw-r--r--src/plugins/geoservices/nokia/nokia.pro4
-rw-r--r--src/plugins/geoservices/nokia/qgeocodejsonparser.cpp413
-rw-r--r--src/plugins/geoservices/nokia/qgeocodejsonparser.h (renamed from src/plugins/geoservices/nokia/qgeocodexmlparser.h)33
-rw-r--r--src/plugins/geoservices/nokia/qgeocodereply_nokia.cpp17
-rw-r--r--src/plugins/geoservices/nokia/qgeocodereply_nokia.h3
-rw-r--r--src/plugins/geoservices/nokia/qgeocodexmlparser.cpp573
-rw-r--r--src/plugins/geoservices/nokia/qgeocodingmanagerengine_nokia.cpp194
-rw-r--r--src/plugins/geoservices/nokia/qgeocodingmanagerengine_nokia.h5
-rw-r--r--src/plugins/geoservices/nokia/qplacemanagerengine_nokiav2.cpp2
-rw-r--r--src/plugins/geoservices/nokia/uri_constants.cpp5
-rw-r--r--src/plugins/geoservices/nokia/uri_constants.h3
11 files changed, 577 insertions, 675 deletions
diff --git a/src/plugins/geoservices/nokia/nokia.pro b/src/plugins/geoservices/nokia/nokia.pro
index cd340f50..1aa31123 100644
--- a/src/plugins/geoservices/nokia/nokia.pro
+++ b/src/plugins/geoservices/nokia/nokia.pro
@@ -10,7 +10,7 @@ contains(QT_CONFIG, location-china-support) {
HEADERS += \
qgeocodereply_nokia.h \
- qgeocodexmlparser.h \
+ qgeocodejsonparser.h \
qgeocodingmanagerengine_nokia.h \
qgeotiledmappingmanagerengine_nokia.h \
qgeotilefetcher_nokia.h \
@@ -31,7 +31,7 @@ HEADERS += \
SOURCES += \
qgeocodereply_nokia.cpp \
- qgeocodexmlparser.cpp \
+ qgeocodejsonparser.cpp \
qgeocodingmanagerengine_nokia.cpp \
qgeotiledmappingmanagerengine_nokia.cpp \
qgeotilefetcher_nokia.cpp \
diff --git a/src/plugins/geoservices/nokia/qgeocodejsonparser.cpp b/src/plugins/geoservices/nokia/qgeocodejsonparser.cpp
new file mode 100644
index 00000000..128f7fd2
--- /dev/null
+++ b/src/plugins/geoservices/nokia/qgeocodejsonparser.cpp
@@ -0,0 +1,413 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qgeocodejsonparser.h"
+
+#include <QtPositioning/QGeoShape>
+#include <QtPositioning/QGeoRectangle>
+#include <QtPositioning/QGeoAddress>
+#include <QtPositioning/QGeoCoordinate>
+
+#include <QtCore/QThreadPool>
+#include <QtCore/QJsonObject>
+#include <QtCore/QJsonArray>
+#include <QtCore/QJsonParseError>
+#include <QtCore/QVariantMap>
+
+#include <QtDebug>
+
+QT_BEGIN_NAMESPACE
+
+namespace {
+
+/*
+ Checks that the given Location object contains the information
+ we need and is not malformed in any way. We expect a Location
+ object of the following form:
+
+ "Location": {
+ "Address": {
+ "AdditionalData": [
+ {
+ "key": "CountryName",
+ "value": "Australia"
+ },
+ {
+ "key": "StateName",
+ "value": "New South Wales"
+ }
+ ],
+ "City": "Sydney",
+ "Country": "AUS",
+ "District": "Casula",
+ "Label": "Casula, Sydney, NSW, Australia",
+ "PostalCode": "2170",
+ "State": "NSW"
+ },
+ "DisplayPosition": {
+ "Latitude": -33.949509999999997,
+ "Longitude": 150.90386000000001
+ },
+ "LocationId": "NT_5UQ89lKoiI4DIYbOrIR0-D",
+ "LocationType": "area",
+ "MapReference": {
+ "CityId": "1469266800",
+ "CountryId": "1469256839",
+ "DistrictId": "1469267758",
+ "MapId": "NXAM16130",
+ "MapReleaseDate": "2016-10-05",
+ "MapVersion": "Q1/2016",
+ "ReferenceId": "868383156",
+ "SideOfStreet": "neither",
+ "StateId": "1469256831"
+ },
+ "MapView": {
+ "BottomRight": {
+ "Latitude": -33.966839999999998,
+ "Longitude": 150.91875999999999
+ },
+ "TopLeft": {
+ "Latitude": -33.937440000000002,
+ "Longitude": 150.87457000000001
+ }
+ }
+ }
+
+*/
+bool checkLocation(const QJsonObject &loc, QString *errorString)
+{
+ QJsonObject::const_iterator ait = loc.constFind(QLatin1String("Address"));
+ if (ait == loc.constEnd()) {
+ *errorString = QLatin1String("Expected Address element within Location object");
+ return false;
+ } else if (!ait.value().isObject()) {
+ *errorString = QLatin1String("Expected Address object within Location object");
+ return false;
+ }
+
+ QJsonObject::const_iterator dpit = loc.constFind(QLatin1String("DisplayPosition"));
+ if (dpit == loc.constEnd()) {
+ *errorString = QLatin1String("Expected DisplayPosition element within Location object");
+ return false;
+ } else if (!dpit.value().isObject()) {
+ *errorString = QLatin1String("Expected DisplayPosition object within Location object");
+ return false;
+ }
+ QJsonObject displayPosition = dpit.value().toObject();
+ QJsonObject::const_iterator latit = displayPosition.constFind(QLatin1String("Latitude"));
+ if (latit == displayPosition.constEnd()) {
+ *errorString = QLatin1String("Expected Latitude element within Location.DisplayPosition object");
+ return false;
+ } else if (!latit.value().isDouble()) {
+ *errorString = QLatin1String("Expected Latitude double within Location.DisplayPosition object");
+ return false;
+ }
+ QJsonObject::const_iterator lonit = displayPosition.constFind(QLatin1String("Longitude"));
+ if (lonit == displayPosition.constEnd()) {
+ *errorString = QLatin1String("Expected Longitude element within Location.DisplayPosition object");
+ return false;
+ } else if (!lonit.value().isDouble()) {
+ *errorString = QLatin1String("Expected Longitude double within Location.DisplayPosition object");
+ return false;
+ }
+
+ QJsonObject::const_iterator mvit = loc.constFind(QLatin1String("MapView"));
+ if (mvit == loc.constEnd()) {
+ *errorString = QLatin1String("Expected MapView element within Location object");
+ return false;
+ } else if (!mvit.value().isObject()) {
+ *errorString = QLatin1String("Expected MapView object within Location object");
+ return false;
+ }
+ QJsonObject mapView = mvit.value().toObject();
+ QJsonObject::const_iterator brit = mapView.constFind(QLatin1String("BottomRight"));
+ if (brit == mapView.constEnd()) {
+ *errorString = QLatin1String("Expected BottomRight element within Location.MapView object");
+ return false;
+ } else if (!brit.value().isObject()) {
+ *errorString = QLatin1String("Expected BottomRight object within Location.MapView object");
+ return false;
+ }
+ QJsonObject bottomRight = brit.value().toObject();
+ QJsonObject::const_iterator brlatit = bottomRight.constFind(QLatin1String("Latitude"));
+ if (brlatit == bottomRight.constEnd()) {
+ *errorString = QLatin1String("Expected Latitude element within Location.MapView.BottomRight object");
+ return false;
+ } else if (!brlatit.value().isDouble()) {
+ *errorString = QLatin1String("Expected Latitude double within Location.MapView.BottomRight object");
+ return false;
+ }
+ QJsonObject::const_iterator brlonit = bottomRight.constFind(QLatin1String("Longitude"));
+ if (brlonit == bottomRight.constEnd()) {
+ *errorString = QLatin1String("Expected Longitude element within Location.MapView.BottomRight object");
+ return false;
+ } else if (!brlonit.value().isDouble()) {
+ *errorString = QLatin1String("Expected Longitude double within Location.MapView.BottomRight object");
+ return false;
+ }
+ QJsonObject::const_iterator tlit = mapView.constFind(QLatin1String("TopLeft"));
+ if (tlit == mapView.constEnd()) {
+ *errorString = QLatin1String("Expected TopLeft element within Location.MapView object");
+ return false;
+ } else if (!tlit.value().isObject()) {
+ *errorString = QLatin1String("Expected TopLeft object within Location.MapView object");
+ return false;
+ }
+ QJsonObject topLeft = tlit.value().toObject();
+ QJsonObject::const_iterator tllatit = topLeft.constFind(QLatin1String("Latitude"));
+ if (tllatit == topLeft.constEnd()) {
+ *errorString = QLatin1String("Expected Latitude element within Location.MapView.TopLeft object");
+ return false;
+ } else if (!tllatit.value().isDouble()) {
+ *errorString = QLatin1String("Expected Latitude double within Location.MapView.TopLeft object");
+ return false;
+ }
+ QJsonObject::const_iterator tllonit = topLeft.constFind(QLatin1String("Longitude"));
+ if (tllonit == bottomRight.constEnd()) {
+ *errorString = QLatin1String("Expected Longitude element within Location.MapView.TopLeft object");
+ return false;
+ } else if (!tllonit.value().isDouble()) {
+ *errorString = QLatin1String("Expected Longitude double within Location.MapView.TopLeft object");
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ Checks that the given document contains the required information
+ and is not malformed in any way. We expect a document like the
+ following:
+
+ {
+ "Response": {
+ "MetaInfo": {
+ "Timestamp": "2016-10-18T08:42:04.369+0000"
+ },
+ "View": [
+ {
+ "ViewId": 0,
+ "_type": "SearchResultsViewType",
+ "Result": [
+ {
+ "Direction": 72.099999999999994,
+ "Distance": -1885.2,
+ "Location": {
+ // OMITTED FOR BREVITY
+ },
+ "MatchLevel": "district",
+ "MatchQuality": {
+ "City": 1,
+ "Country": 1,
+ "District": 1,
+ "PostalCode": 1,
+ "State": 1
+ },
+ "Relevance": 1
+ }
+ ]
+ }
+ ]
+ }
+ }
+*/
+bool checkDocument(const QJsonDocument &doc, QString *errorString)
+{
+ if (!doc.isObject()) {
+ *errorString = QLatin1String("Expected JSON document containing object");
+ return false;
+ }
+
+ QJsonObject rootObject = doc.object();
+ QJsonObject::const_iterator it = rootObject.constFind(QLatin1String("Response"));
+ if (it == rootObject.constEnd()) {
+ *errorString = QLatin1String("Expected Response element within root object");
+ return false;
+ } else if (!it.value().isObject()) {
+ *errorString = QLatin1String("Expected Response object within root object");
+ return false;
+ }
+
+ QJsonObject response = it.value().toObject();
+ QJsonObject::const_iterator rit = response.constFind(QLatin1String("View"));
+ if (rit == response.constEnd()) {
+ *errorString = QLatin1String("Expected View element within Response object");
+ return false;
+ } else if (!rit.value().isArray()) {
+ *errorString = QLatin1String("Expected View array within Response object");
+ return false;
+ }
+
+ QJsonArray view = rit.value().toArray();
+ Q_FOREACH (const QJsonValue &viewElement, view) {
+ if (!viewElement.isObject()) {
+ *errorString = QLatin1String("Expected View array element to be object");
+ return false;
+ }
+
+ QJsonObject viewObject = viewElement.toObject();
+ QJsonObject::const_iterator voit = viewObject.constFind(QLatin1String("Result"));
+ if (voit == viewObject.constEnd()) {
+ *errorString = QLatin1String("Expected Result element within View array object element");
+ return false;
+ } else if (!voit.value().isArray()) {
+ *errorString = QLatin1String("Expected Result array within View array object element");
+ return false;
+ }
+
+ QJsonArray result = voit.value().toArray();
+ Q_FOREACH (const QJsonValue &resultElement, result) {
+ if (!resultElement.isObject()) {
+ *errorString = QLatin1String("Expected Result array element to be object");
+ return false;
+ }
+
+ QJsonObject resultObject = resultElement.toObject();
+ QJsonObject::const_iterator roit = resultObject.constFind("Location");
+ if (roit == resultObject.constEnd()) {
+ *errorString = QLatin1String("Expected Location element in Result array element object");
+ return false;
+ } else if (!roit.value().isObject()) {
+ *errorString = QLatin1String("Expected Location object in Result array element object");
+ return false;
+ }
+
+ QJsonObject location = roit.value().toObject();
+ if (!checkLocation(location, errorString)) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+bool parseLocation(const QJsonObject &obj, const QGeoShape &bounds, QGeoLocation *loc)
+{
+ QJsonObject displayPosition = obj.value("DisplayPosition").toObject();
+ QGeoCoordinate coordinate = QGeoCoordinate(displayPosition.value("Latitude").toDouble(), displayPosition.value("Longitude").toDouble());
+ if (bounds.isValid() && !bounds.contains(coordinate)) {
+ // manual bounds check failed, location can be omitted from results.
+ return false;
+ }
+
+ QGeoAddress address;
+ QJsonObject addr = obj.value("Address").toObject();
+ address.setCountryCode(addr.value("Country").toString());
+ address.setState(addr.value("State").toString());
+ address.setCounty(addr.value("County").toString());
+ address.setCity(addr.value("City").toString());
+ address.setDistrict(addr.value("District").toString());
+ QString houseNumber = addr.value("HouseNumber").toString();
+ QString street = addr.value("Street").toString();
+ address.setStreet(houseNumber.isEmpty() ? street : QString("%1 %2").arg(houseNumber, street));
+ address.setPostalCode(addr.value("PostalCode").toString());
+ QString label = addr.value("Label").toString().trimmed();
+ if (!label.isEmpty()) {
+ address.setText(label);
+ }
+ QJsonArray additionalData = addr.value("AdditionalData").toArray();
+ Q_FOREACH (const QJsonValue &adv, additionalData) {
+ if (adv.isObject()) {
+ const QJsonObject &ado(adv.toObject());
+ if (ado.value("key").toString() == QLatin1String("CountryName")) {
+ address.setCountry(ado.value("value").toString());
+ }
+ }
+ }
+
+ QGeoRectangle boundingBox;
+ QJsonObject mapView = obj.value("MapView").toObject();
+ QJsonObject bottomRight = mapView.value("BottomRight").toObject();
+ QJsonObject topLeft = mapView.value("TopLeft").toObject();
+ boundingBox.setBottomRight(QGeoCoordinate(bottomRight.value("Latitude").toDouble(), bottomRight.value("Longitude").toDouble()));
+ boundingBox.setTopLeft(QGeoCoordinate(topLeft.value("Latitude").toDouble(), topLeft.value("Longitude").toDouble()));
+
+ loc->setAddress(address);
+ loc->setCoordinate(coordinate);
+ loc->setBoundingBox(boundingBox);
+
+ return true;
+}
+
+void parseDocument(const QJsonDocument &doc, const QGeoShape &bounds, QList<QGeoLocation> *locs)
+{
+ QJsonArray view = doc.object().value("Response").toObject().value("View").toArray();
+ Q_FOREACH (const QJsonValue &viewElement, view) {
+ QJsonArray result = viewElement.toObject().value("Result").toArray();
+ Q_FOREACH (const QJsonValue &resultElement, result) {
+ QGeoLocation location;
+ if (parseLocation(resultElement.toObject().value("Location").toObject(), bounds, &location)) {
+ locs->append(location);
+ }
+ }
+ }
+}
+
+} // namespace
+
+void QGeoCodeJsonParser::setBounds(const QGeoShape &bounds)
+{
+ m_bounds = bounds;
+}
+
+void QGeoCodeJsonParser::parse(const QByteArray &data)
+{
+ m_data = data;
+ QThreadPool::globalInstance()->start(this);
+}
+
+void QGeoCodeJsonParser::run()
+{
+ // parse the document.
+ QJsonParseError perror;
+ m_document = QJsonDocument::fromJson(m_data, &perror);
+ if (perror.error != QJsonParseError::NoError) {
+ m_errorString = perror.errorString();
+ } else {
+ // ensure that the response is valid and contains the information we need.
+ if (checkDocument(m_document, &m_errorString)) {
+ // extract the location results from the response.
+ parseDocument(m_document, m_bounds, &m_results);
+ emit results(m_results);
+ return;
+ }
+ }
+
+ emit error(m_errorString);
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/geoservices/nokia/qgeocodexmlparser.h b/src/plugins/geoservices/nokia/qgeocodejsonparser.h
index 83a4b598..03251775 100644
--- a/src/plugins/geoservices/nokia/qgeocodexmlparser.h
+++ b/src/plugins/geoservices/nokia/qgeocodejsonparser.h
@@ -34,31 +34,26 @@
**
****************************************************************************/
-#ifndef QGEOCODEXMLPARSER_H
-#define QGEOCODEXMLPARSER_H
+#ifndef QGEOCODEJSONPARSER_H
+#define QGEOCODEJSONPARSER_H
+
+#include <QtPositioning/QGeoShape>
+#include <QtPositioning/QGeoLocation>
#include <QtCore/QObject>
#include <QtCore/QRunnable>
+#include <QtCore/QJsonDocument>
+#include <QtCore/QByteArray>
#include <QtCore/QString>
#include <QtCore/QList>
-#include <QtPositioning/QGeoShape>
QT_BEGIN_NAMESPACE
-class QGeoLocation;
-class QGeoAddress;
-class QGeoRectangle;
-class QGeoCoordinate;
-class QXmlStreamReader;
-
-class QGeoCodeXmlParser : public QObject, public QRunnable
+class QGeoCodeJsonParser : public QObject, public QRunnable
{
Q_OBJECT
public:
- QGeoCodeXmlParser();
- ~QGeoCodeXmlParser();
-
void setBounds(const QGeoShape &bounds);
void parse(const QByteArray &data);
void run();
@@ -68,17 +63,9 @@ signals:
void error(const QString &errorString);
private:
- bool parseRootElement();
- bool parsePlace(QGeoLocation *location);
- bool parseLocation(QGeoLocation *location);
- bool parseAddress(QGeoAddress *address);
- bool parseBoundingBox(QGeoRectangle *bounds);
- bool parseCoordinate(QGeoCoordinate *coordinate, const QString &elementName);
-
- QGeoShape m_bounds;
+ QJsonDocument m_document;
QByteArray m_data;
- QXmlStreamReader *m_reader;
-
+ QGeoShape m_bounds;
QList<QGeoLocation> m_results;
QString m_errorString;
};
diff --git a/src/plugins/geoservices/nokia/qgeocodereply_nokia.cpp b/src/plugins/geoservices/nokia/qgeocodereply_nokia.cpp
index 73d2d4c3..e99b9815 100644
--- a/src/plugins/geoservices/nokia/qgeocodereply_nokia.cpp
+++ b/src/plugins/geoservices/nokia/qgeocodereply_nokia.cpp
@@ -35,7 +35,7 @@
****************************************************************************/
#include "qgeocodereply_nokia.h"
-#include "qgeocodexmlparser.h"
+#include "qgeocodejsonparser.h"
#include "qgeoerror_messages.h"
#include <QtPositioning/QGeoShape>
@@ -45,9 +45,15 @@ Q_DECLARE_METATYPE(QList<QGeoLocation>)
QT_BEGIN_NAMESPACE
+// manualBoundsRequired will be true if the parser has to manually
+// check if a given result lies within the viewport bounds,
+// and false if the bounds information was able to be supplied
+// to the server in the request (so it should not return any
+// out-of-bounds results).
QGeoCodeReplyNokia::QGeoCodeReplyNokia(QNetworkReply *reply, int limit, int offset,
- const QGeoShape &viewport, QObject *parent)
-: QGeoCodeReply(parent), m_reply(reply), m_parsing(false)
+ const QGeoShape &viewport, bool manualBoundsRequired,
+ QObject *parent)
+: QGeoCodeReply(parent), m_reply(reply), m_parsing(false), m_manualBoundsRequired(manualBoundsRequired)
{
qRegisterMetaType<QList<QGeoLocation> >();
@@ -87,8 +93,9 @@ void QGeoCodeReplyNokia::networkFinished()
if (m_reply->error() != QNetworkReply::NoError)
return;
- QGeoCodeXmlParser *parser = new QGeoCodeXmlParser;
- parser->setBounds(viewport());
+ QGeoCodeJsonParser *parser = new QGeoCodeJsonParser; // QRunnable, autoDelete = true.
+ if (m_manualBoundsRequired)
+ parser->setBounds(viewport());
connect(parser, SIGNAL(results(QList<QGeoLocation>)),
this, SLOT(appendResults(QList<QGeoLocation>)));
connect(parser, SIGNAL(error(QString)), this, SLOT(parseError(QString)));
diff --git a/src/plugins/geoservices/nokia/qgeocodereply_nokia.h b/src/plugins/geoservices/nokia/qgeocodereply_nokia.h
index 85726fca..0d0c47d1 100644
--- a/src/plugins/geoservices/nokia/qgeocodereply_nokia.h
+++ b/src/plugins/geoservices/nokia/qgeocodereply_nokia.h
@@ -46,7 +46,7 @@ class QGeoCodeReplyNokia : public QGeoCodeReply
{
Q_OBJECT
public:
- QGeoCodeReplyNokia(QNetworkReply *reply, int limit, int offset, const QGeoShape &viewport, QObject *parent = 0);
+ QGeoCodeReplyNokia(QNetworkReply *reply, int limit, int offset, const QGeoShape &viewport, bool manualBoundsRequired, QObject *parent = 0);
~QGeoCodeReplyNokia();
void abort();
@@ -60,6 +60,7 @@ private Q_SLOTS:
private:
QNetworkReply *m_reply;
bool m_parsing;
+ bool m_manualBoundsRequired;
};
QT_END_NAMESPACE
diff --git a/src/plugins/geoservices/nokia/qgeocodexmlparser.cpp b/src/plugins/geoservices/nokia/qgeocodexmlparser.cpp
deleted file mode 100644
index 89738869..00000000
--- a/src/plugins/geoservices/nokia/qgeocodexmlparser.cpp
+++ /dev/null
@@ -1,573 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
-**
-** This file is part of the QtLocation module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL3$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPLv3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or later as published by the Free
-** Software Foundation and appearing in the file LICENSE.GPL included in
-** the packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 2.0 requirements will be
-** met: http://www.gnu.org/licenses/gpl-2.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qgeocodexmlparser.h"
-
-#include <QtCore/QXmlStreamReader>
-#include <QtCore/QThreadPool>
-#include <QtPositioning/QGeoLocation>
-#include <QtPositioning/QGeoAddress>
-#include <QtPositioning/QGeoCoordinate>
-#include <QtPositioning/QGeoRectangle>
-
-QT_BEGIN_NAMESPACE
-
-QGeoCodeXmlParser::QGeoCodeXmlParser()
-{
-}
-
-QGeoCodeXmlParser::~QGeoCodeXmlParser()
-{
-}
-
-void QGeoCodeXmlParser::setBounds(const QGeoShape &bounds)
-{
- m_bounds = bounds;
-}
-
-void QGeoCodeXmlParser::parse(const QByteArray &data)
-{
- m_data = data;
- QThreadPool::globalInstance()->start(this);
-}
-
-void QGeoCodeXmlParser::run()
-{
- m_reader = new QXmlStreamReader(m_data);
-
- if (!parseRootElement())
- emit error(m_reader->errorString());
- else
- emit results(m_results);
-
- delete m_reader;
- m_reader = 0;
-}
-
-bool QGeoCodeXmlParser::parseRootElement()
-{
- /*
- <xsd:element name="places">
- <xsd:complexType>
- <xsd:sequence>
- <xsd:element minOccurs="0" maxOccurs="unbounded" name="place" type="gc:Place"/>
- </xsd:sequence>
- <xsd:attribute name="resultCode" type="gc:ResultCodes"/>
- <xsd:attribute name="resultDescription" type="xsd:string"/>
- <xsd:attribute name="resultsTotal" type="xsd:nonNegativeInteger"/>
- </xsd:complexType>
- </xsd:element>
-
- <xsd:simpleType name="ResultCodes">
- <xsd:restriction base="xsd:string">
- <xsd:enumeration value="OK"/>
- <xsd:enumeration value="FAILED"/>
- </xsd:restriction>
- </xsd:simpleType>
- */
-
- if (m_reader->readNextStartElement()) {
- if (m_reader->name() == "places") {
- if (m_reader->attributes().hasAttribute("resultCode")) {
- QStringRef result = m_reader->attributes().value("resultCode");
- if (result == "FAILED") {
- QString resultDesc = m_reader->attributes().value("resultDescription").toString();
- if (resultDesc.isEmpty())
- resultDesc = "The attribute \"resultCode\" of the element \"places\" indicates that the request failed.";
-
- m_reader->raiseError(resultDesc);
-
- return false;
- } else if (result != "OK") {
- m_reader->raiseError(QString("The attribute \"resultCode\" of the element \"places\" has an unknown value (value was %1).").arg(result.toString()));
- return false;
- }
- }
-
- while (m_reader->readNextStartElement()) {
- if (m_reader->name() == "place") {
- QGeoLocation location;
-
- if (!parsePlace(&location))
- return false;
-
- if (!m_bounds.isValid() || m_bounds.contains(location.coordinate()))
- m_results.append(location);
- } else {
- m_reader->raiseError(QString("The element \"places\" did not expect a child element named \"%1\".").arg(m_reader->name().toString()));
- return false;
- }
- }
- } else {
- m_reader->raiseError(QString("The root element is expected to have the name \"places\" (root element was named \"%1\").").arg(m_reader->name().toString()));
- return false;
- }
- } else {
- m_reader->raiseError("Expected a root element named \"places\" (no root element found).");
- return false;
- }
-
- if (m_reader->readNextStartElement()) {
- m_reader->raiseError(QString("A single root element named \"places\" was expected (second root element was named \"%1\")").arg(m_reader->name().toString()));
- return false;
- }
-
- return true;
-}
-
-
-//Note: the term Place here is semi-confusing since
-// the xml 'place' is actually a location ie coord + address
-bool QGeoCodeXmlParser::parsePlace(QGeoLocation *location)
-{
- /*
- <xsd:complexType name="Place">
- <xsd:all>
- <xsd:element name="location" type="gc:Location"/>
- <xsd:element minOccurs="0" name="address" type="gc:Address"/>
- <xsd:element minOccurs="0" name="alternatives" type="gc:Alternatives"/>
- </xsd:all>
- <xsd:attribute name="title" type="xsd:string" use="required"/>
- <xsd:attribute name="language" type="gc:LanguageCode" use="required"/>
- </xsd:complexType>
-
- <xsd:simpleType name="LanguageCode">
- <xsd:restriction base="xsd:string">
- <xsd:length value="3"/>
- </xsd:restriction>
- </xsd:simpleType>
- */
-
- Q_ASSERT(m_reader->isStartElement() && m_reader->name() == "place");
-
- if (!m_reader->attributes().hasAttribute("title")) {
- m_reader->raiseError("The element \"place\" did not have the required attribute \"title\".");
- return false;
- }
-
- if (!m_reader->attributes().hasAttribute("language")) {
- //m_reader->raiseError("The element \"place\" did not have the required attribute \"language\".");
- //return false;
- } else {
- QString lang = m_reader->attributes().value("language").toString();
-
- if (lang.length() != 3) {
- m_reader->raiseError(QString("The attribute \"language\" of the element \"place\" was not of length 3 (length was %1).").arg(lang.length()));
- return false;
- }
- }
-
- bool parsedLocation = false;
- bool parsedAddress = false;
- bool parsedAlternatives = false;
-
- while (m_reader->readNextStartElement()) {
- QString name = m_reader->name().toString();
- if (name == "location") {
- if (parsedLocation) {
- m_reader->raiseError("The element \"place\" has multiple child elements named \"location\" (exactly one expected)");
- return false;
- }
-
- if (!parseLocation(location))
- return false;
-
- parsedLocation = true;
- } else if (name == "address") {
- if (parsedAddress) {
- m_reader->raiseError("The element \"place\" has multiple child elements named \"address\" (at most one expected)");
- return false;
- }
-
- QGeoAddress address;
- if (!parseAddress(&address))
- return false;
- else
- location->setAddress(address);
-
- location->setAddress(address);
-
- parsedAddress = true;
- } else if (name == "alternatives") {
- if (parsedAlternatives) {
- m_reader->raiseError("The element \"place\" has multiple child elements named \"alternatives\" (at most one expected)");
- return false;
- }
-
- // skip alternatives for now
- // need to work out if we have a use for them at all
- // and how to store them if we get them
- m_reader->skipCurrentElement();
-
- parsedAlternatives = true;
- } else {
- m_reader->raiseError(QString("The element \"place\" did not expect a child element named \"%1\".").arg(m_reader->name().toString()));
- return false;
- }
- }
-
- if (!parsedLocation) {
- m_reader->raiseError("The element \"place\" has no child elements named \"location\" (exactly one expected)");
- return false;
- }
-
- return true;
-}
-
-//Note: the term Place here is semi-confusing since
-// the xml 'location' is actually a parital location i.e coord
-// as opposed to coord + address
-bool QGeoCodeXmlParser::parseLocation(QGeoLocation *location)
-{
- /*
- <xsd:complexType name="Location">
- <xsd:all>
- <xsd:element name="position" type="gc:GeoCoord"/>
- <xsd:element minOccurs="0" name="boundingBox" type="gc:GeoBox"/>
- </xsd:all>
- </xsd:complexType>
-
- <xsd:complexType name="GeoBox">
- <xsd:sequence>
- <xsd:element name="topLeft" type="gc:GeoCoord"/>
- <xsd:element name="bottomRight" type="gc:GeoCoord"/>
- </xsd:sequence>
- </xsd:complexType>
- */
-
- Q_ASSERT(m_reader->isStartElement() && m_reader->name() == "location");
-
- bool parsedPosition = false;
- bool parsedBounds = false;
-
- while (m_reader->readNextStartElement()) {
- QString name = m_reader->name().toString();
- if (name == "position") {
- if (parsedPosition) {
- m_reader->raiseError("The element \"location\" has multiple child elements named \"position\" (exactly one expected)");
- return false;
- }
-
- QGeoCoordinate coord;
- if (!parseCoordinate(&coord, "position"))
- return false;
-
- location->setCoordinate(coord);
-
- parsedPosition = true;
- } else if (name == "boundingBox") {
- if (parsedBounds) {
- m_reader->raiseError("The element \"location\" has multiple child elements named \"boundingBox\" (at most one expected)");
- return false;
- }
-
- QGeoRectangle bounds;
-
- if (!parseBoundingBox(&bounds))
- return false;
-
- location->setBoundingBox(bounds);
-
- parsedBounds = true;
- } else {
- m_reader->raiseError(QString("The element \"location\" did not expect a child element named \"%1\".").arg(m_reader->name().toString()));
- return false;
- }
- }
-
- if (!parsedPosition) {
- m_reader->raiseError("The element \"location\" has no child elements named \"position\" (exactly one expected)");
- return false;
- }
-
- return true;
-}
-
-bool QGeoCodeXmlParser::parseAddress(QGeoAddress *address)
-{
- /*
- <xsd:complexType name="Address">
- <xsd:sequence>
- <xsd:element minOccurs="0" maxOccurs="1" name="country" type="xsd:string"/>
- <xsd:element minOccurs="0" maxOccurs="1" name="countryCode" type="gc:CountryCode"/>
- <xsd:element minOccurs="0" maxOccurs="1" name="state" type="xsd:string"/>
- <xsd:element minOccurs="0" maxOccurs="1" name="county" type="xsd:string"/>
- <xsd:element minOccurs="0" maxOccurs="1" name="city" type="xsd:string"/>
- <xsd:element minOccurs="0" maxOccurs="1" name="district" type="xsd:string"/>
- <xsd:element minOccurs="0" maxOccurs="1" name="thoroughfare" type="gc:Thoroughfare"/>
- <xsd:element minOccurs="0" maxOccurs="1" name="postCode" type="xsd:string"/>
- </xsd:sequence>
- <xsd:attribute name="type" type="xsd:string"/>
- </xsd:complexType>
-
- <xsd:simpleType name="CountryCode">
- <xsd:restriction base="xsd:string">
- <xsd:length value="3" fixed="true"/>
- </xsd:restriction>
- </xsd:simpleType>
-
- <xsd:complexType name="Thoroughfare">
- <xsd:sequence>
- <xsd:element minOccurs="0" name="name" type="xsd:string"/>
- <xsd:element minOccurs="0" name="number" type="xsd:string"/>
- </xsd:sequence>
- </xsd:complexType>
- */
-
- Q_ASSERT(m_reader->isStartElement() && m_reader->name() == "address");
-
- // currently ignoring the type of the address
-
- if (!m_reader->readNextStartElement())
- return true;
-
- if (m_reader->name() == "country") {
- address->setCountry(m_reader->readElementText());
- if (!m_reader->readNextStartElement())
- return true;
- }
-
- if (m_reader->name() == "countryCode") {
- address->setCountryCode(m_reader->readElementText());
-
- if (address->countryCode().length() != 3) {
- m_reader->raiseError(QString("The text of the element \"countryCode\" was not of length 3 (length was %1).").arg(address->countryCode().length()));
- return false;
- }
-
- if (!m_reader->readNextStartElement())
- return true;
- }
-
- if (m_reader->name() == "state") {
- address->setState(m_reader->readElementText());
- if (!m_reader->readNextStartElement())
- return true;
- }
-
- if (m_reader->name() == "county") {
- address->setCounty(m_reader->readElementText());
- if (!m_reader->readNextStartElement())
- return true;
- }
-
- if (m_reader->name() == "city") {
- address->setCity(m_reader->readElementText());
- if (!m_reader->readNextStartElement())
- return true;
- }
-
- if (m_reader->name() == "district") {
- address->setDistrict(m_reader->readElementText());
- if (!m_reader->readNextStartElement())
- return true;
- }
-
- bool inThoroughfare = false;
-
- if (m_reader->name() == "thoroughfare") {
- inThoroughfare = m_reader->readNextStartElement();
-
- if (inThoroughfare && (m_reader->name() == "name")) {
- address->setStreet(m_reader->readElementText());
- if (!m_reader->readNextStartElement())
- inThoroughfare = false;
- }
-
- if (inThoroughfare && (m_reader->name() == "number")) {
- address->setStreet(m_reader->readElementText() + ' ' + address->street());
- if (!m_reader->readNextStartElement())
- inThoroughfare = false;
- }
-
- if (inThoroughfare) {
- m_reader->raiseError(QString("The element \"thoroughFare\" did not expect the child element \"%1\" at this point (unknown child element or child element out of order).").arg(m_reader->name().toString()));
- return false;
- }
-
- if (!m_reader->readNextStartElement())
- return true;
- }
-
- if (m_reader->name() == "postCode") {
- address->setPostalCode(m_reader->readElementText());
- if (!m_reader->readNextStartElement())
- return true;
- }
-
- m_reader->raiseError(QString("The element \"address\" did not expect the child element \"%1\" at this point (unknown child element or child element out of order).").arg(m_reader->name().toString()));
- return false;
-}
-
-bool QGeoCodeXmlParser::parseBoundingBox(QGeoRectangle *bounds)
-{
- /*
- <xsd:complexType name="GeoBox">
- <xsd:sequence>
- <xsd:element name="topLeft" type="gc:GeoCoord"/>
- <xsd:element name="bottomRight" type="gc:GeoCoord"/>
- </xsd:sequence>
- </xsd:complexType>
- */
-
- Q_ASSERT(m_reader->isStartElement() && m_reader->name() == "boundingBox");
-
- if (!m_reader->readNextStartElement()) {
- m_reader->raiseError("The element \"boundingBox\" was expected to have 2 child elements (0 found)");
- return false;
- }
-
- QGeoCoordinate nw;
-
- if (m_reader->name() == "topLeft") {
- if (!parseCoordinate(&nw, "topLeft"))
- return false;
- } else {
- m_reader->raiseError(QString("The element \"boundingBox\" expected this child element to be named \"topLeft\" (found an element named \"%1\")").arg(m_reader->name().toString()));
- return false;
- }
-
- if (!m_reader->readNextStartElement()) {
- m_reader->raiseError("The element \"boundingBox\" was expected to have 2 child elements (1 found)");
- return false;
- }
-
- QGeoCoordinate se;
-
- if (m_reader->name() == "bottomRight") {
- if (!parseCoordinate(&se, "bottomRight"))
- return false;
- } else {
- m_reader->raiseError(QString("The element \"boundingBox\" expected this child element to be named \"bottomRight\" (found an element named \"%1\")").arg(m_reader->name().toString()));
- return false;
- }
-
- if (m_reader->readNextStartElement()) {
- m_reader->raiseError("The element \"boundingBox\" was expected to have 2 child elements (more than 2 found)");
- return false;
- }
-
- *bounds = QGeoRectangle(nw, se);
-
- return true;
-}
-
-bool QGeoCodeXmlParser::parseCoordinate(QGeoCoordinate *coordinate, const QString &elementName)
-{
- /*
- <xsd:complexType name="GeoCoord">
- <xsd:sequence>
- <xsd:element name="latitude" type="gc:Latitude"/>
- <xsd:element name="longitude" type="gc:Longitude"/>
- </xsd:sequence>
- </xsd:complexType>
-
- <xsd:simpleType name="Latitude">
- <xsd:restriction base="xsd:float">
- <xsd:minInclusive value="-90.0"/>
- <xsd:maxInclusive value="90.0"/>
- </xsd:restriction>
- </xsd:simpleType>
-
- <xsd:simpleType name="Longitude">
- <xsd:restriction base="xsd:float">
- <xsd:minInclusive value="-180.0"/>
- <xsd:maxInclusive value="180.0"/>
- </xsd:restriction>
- </xsd:simpleType>
- */
-
- Q_ASSERT(m_reader->isStartElement() && m_reader->name() == elementName);
-
- if (!m_reader->readNextStartElement()) {
- m_reader->raiseError(QString("The element \"%1\" was expected to have 2 child elements (0 found)").arg(elementName));
- return false;
- }
-
- if (m_reader->name() == "latitude") {
- bool ok = false;
- QString s = m_reader->readElementText();
- double lat = s.toDouble(&ok);
-
- if (!ok) {
- m_reader->raiseError(QString("The element \"latitude\" expected a value convertable to type float (value was \"%1\")").arg(s));
- return false;
- }
-
- if (lat < -90.0 || 90.0 < lat) {
- m_reader->raiseError(QString("The element \"latitude\" expected a value between -90.0 and 90.0 inclusive (value was %1)").arg(lat));
- return false;
- }
-
- coordinate->setLatitude(lat);
- } else {
- m_reader->raiseError(QString("The element \"%1\" expected this child element to be named \"latitude\" (found an element named \"%2\")").arg(elementName).arg(m_reader->name().toString()));
- }
-
- if (!m_reader->readNextStartElement()) {
- m_reader->raiseError(QString("The element \"%1\" was expected to have 2 child elements (1 found)").arg(elementName));
- return false;
- }
-
- if (m_reader->name() == "longitude") {
- bool ok = false;
- QString s = m_reader->readElementText();
- double lng = s.toDouble(&ok);
-
- if (!ok) {
- m_reader->raiseError(QString("The element \"longitude\" expected a value convertable to type float (value was \"%1\")").arg(s));
- return false;
- }
-
- if (lng < -180.0 || 180.0 < lng) {
- m_reader->raiseError(QString("The element \"longitude\" expected a value between -180.0 and 180.0 inclusive (value was %1)").arg(lng));
- return false;
- }
-
- coordinate->setLongitude(lng);
- } else {
- m_reader->raiseError(QString("The element \"%1\" expected this child element to be named \"longitude\" (found an element named \"%2\")").arg(elementName).arg(m_reader->name().toString()));
- }
-
- if (m_reader->readNextStartElement()) {
- m_reader->raiseError(QString("The element \"%1\" was expected to have 2 child elements (more than 2 found)").arg(elementName));
- return false;
- }
-
- return true;
-}
-
-QT_END_NAMESPACE
diff --git a/src/plugins/geoservices/nokia/qgeocodingmanagerengine_nokia.cpp b/src/plugins/geoservices/nokia/qgeocodingmanagerengine_nokia.cpp
index 2e0eae42..b3c74a63 100644
--- a/src/plugins/geoservices/nokia/qgeocodingmanagerengine_nokia.cpp
+++ b/src/plugins/geoservices/nokia/qgeocodingmanagerengine_nokia.cpp
@@ -41,8 +41,12 @@
#include "qgeouriprovider.h"
#include "uri_constants.h"
-#include <qgeoaddress.h>
-#include <qgeocoordinate.h>
+#include <QtPositioning/QGeoAddress>
+#include <QtPositioning/QGeoCoordinate>
+#include <QtPositioning/QGeoCircle>
+#include <QtPositioning/QGeoRectangle>
+#include <QtPositioning/QGeoShape>
+
#include <QUrl>
#include <QMap>
#include <QStringList>
@@ -56,7 +60,8 @@ QGeoCodingManagerEngineNokia::QGeoCodingManagerEngineNokia(
QString *errorString)
: QGeoCodingManagerEngine(parameters)
, m_networkManager(networkManager)
- , m_uriProvider(new QGeoUriProvider(this, parameters, QStringLiteral("here.geocoding.host"), GEOCODING_HOST, GEOCODING_HOST_CN))
+ , m_uriProvider(new QGeoUriProvider(this, parameters, QStringLiteral("here.geocoding.host"), GEOCODING_HOST))
+ , m_reverseGeocodingUriProvider(new QGeoUriProvider(this, parameters, QStringLiteral("here.reversegeocoding.host"), REVERSE_GEOCODING_HOST))
{
Q_ASSERT(networkManager);
m_networkManager->setParent(this);
@@ -81,7 +86,7 @@ QString QGeoCodingManagerEngineNokia::getAuthenticationString() const
QString authenticationString;
if (!m_token.isEmpty() && !m_applicationId.isEmpty()) {
- authenticationString += "?token=";
+ authenticationString += "?app_code=";
authenticationString += m_token;
authenticationString += "&app_id=";
@@ -95,15 +100,43 @@ QString QGeoCodingManagerEngineNokia::getAuthenticationString() const
QGeoCodeReply *QGeoCodingManagerEngineNokia::geocode(const QGeoAddress &address,
const QGeoShape &bounds)
{
- QString requestString = "http://";
+ QString requestString = "https://";
requestString += m_uriProvider->getCurrentHost();
- requestString += "/geocoder/gc/2.0";
+ requestString += "/6.2/geocode.json";
requestString += getAuthenticationString();
+ requestString += "&gen=9";
- requestString += "&lg=";
+ requestString += "&language=";
requestString += languageToMarc(locale().language());
+ bool manualBoundsRequired = false;
+ if (bounds.type() == QGeoShape::RectangleType) {
+ QGeoRectangle rect(bounds);
+ if (rect.isValid()) {
+ requestString += "&bbox=";
+ requestString += trimDouble(rect.topLeft().latitude());
+ requestString += ",";
+ requestString += trimDouble(rect.topLeft().longitude());
+ requestString += ";";
+ requestString += trimDouble(rect.bottomRight().latitude());
+ requestString += ",";
+ requestString += trimDouble(rect.bottomRight().longitude());
+ }
+ } else if (bounds.type() == QGeoShape::CircleType) {
+ QGeoCircle circ(bounds);
+ if (circ.isValid()) {
+ requestString += "?prox=";
+ requestString += trimDouble(circ.center().latitude());
+ requestString += ",";
+ requestString += trimDouble(circ.center().longitude());
+ requestString += ",";
+ requestString += trimDouble(circ.radius());
+ }
+ } else {
+ manualBoundsRequired = true;
+ }
+
if (address.country().isEmpty()) {
QStringList parts;
@@ -119,8 +152,8 @@ QGeoCodeReply *QGeoCodingManagerEngineNokia::geocode(const QGeoAddress &address,
if (!address.street().isEmpty())
parts << address.street();
- requestString += "&obloc=";
- requestString += parts.join(" ");
+ requestString += "&searchtext=";
+ requestString += parts.join("+").replace(' ', '+');
} else {
requestString += "&country=";
requestString += address.country();
@@ -136,7 +169,7 @@ QGeoCodeReply *QGeoCodingManagerEngineNokia::geocode(const QGeoAddress &address,
}
if (!address.postalCode().isEmpty()) {
- requestString += "&zip=";
+ requestString += "&postalcode=";
requestString += address.postalCode();
}
@@ -146,39 +179,7 @@ QGeoCodeReply *QGeoCodingManagerEngineNokia::geocode(const QGeoAddress &address,
}
}
-
- // TODO?
- // street number has been removed from QGeoAddress
- // do we need to try to split it out from QGeoAddress::street
- // in order to geocode properly
-
- // Old code:
-// if (!address.streetNumber().isEmpty()) {
-// requestString += "&number=";
-// requestString += address.streetNumber();
-// }
-
- return geocode(requestString, bounds);
-}
-
-QGeoCodeReply *QGeoCodingManagerEngineNokia::reverseGeocode(const QGeoCoordinate &coordinate,
- const QGeoShape &bounds)
-{
- QString requestString = "http://";
- requestString += m_uriProvider->getCurrentHost();
- requestString += "/geocoder/rgc/2.0";
-
- requestString += getAuthenticationString();
-
- requestString += "&long=";
- requestString += trimDouble(coordinate.longitude());
- requestString += "&lat=";
- requestString += trimDouble(coordinate.latitude());
-
- requestString += "&lg=";
- requestString += languageToMarc(locale().language());
-
- return geocode(requestString, bounds);
+ return geocode(requestString, bounds, manualBoundsRequired);
}
QGeoCodeReply *QGeoCodingManagerEngineNokia::geocode(const QString &address,
@@ -186,52 +187,119 @@ QGeoCodeReply *QGeoCodingManagerEngineNokia::geocode(const QString &address,
int offset,
const QGeoShape &bounds)
{
- QString requestString = "http://";
+ QString requestString = "https://";
requestString += m_uriProvider->getCurrentHost();
- requestString += "/geocoder/gc/2.0";
+ requestString += "/6.2/geocode.json";
requestString += getAuthenticationString();
+ requestString += "&gen=9";
- requestString += "&lg=";
+ requestString += "&language=";
requestString += languageToMarc(locale().language());
- requestString += "&obloc=";
- requestString += address;
+ requestString += "&searchtext=";
+ requestString += QString(address).replace(' ', '+');
if (limit > 0) {
- requestString += "&total=";
+ requestString += "&maxresults=";
requestString += QString::number(limit);
}
-
if (offset > 0) {
- requestString += "&offset=";
- requestString += QString::number(offset);
+ // We cannot do this precisely, since HERE doesn't allow
+ // precise result-set offset to be supplied; instead, it
+ // returns "pages" of results at a time.
+ // So, we tell HERE which page of results we want, and the
+ // client has to filter out duplicates if they changed
+ // the limit param since the last call.
+ requestString += "&pageinformation=";
+ requestString += QString::number(offset/limit);
}
- return geocode(requestString, bounds, limit, offset);
+ bool manualBoundsRequired = false;
+ if (bounds.type() == QGeoShape::RectangleType) {
+ QGeoRectangle rect(bounds);
+ if (rect.isValid()) {
+ requestString += "&bbox=";
+ requestString += trimDouble(rect.topLeft().latitude());
+ requestString += ",";
+ requestString += trimDouble(rect.topLeft().longitude());
+ requestString += ";";
+ requestString += trimDouble(rect.bottomRight().latitude());
+ requestString += ",";
+ requestString += trimDouble(rect.bottomRight().longitude());
+ }
+ } else if (bounds.type() == QGeoShape::CircleType) {
+ QGeoCircle circ(bounds);
+ if (circ.isValid()) {
+ requestString += "?prox=";
+ requestString += trimDouble(circ.center().latitude());
+ requestString += ",";
+ requestString += trimDouble(circ.center().longitude());
+ requestString += ",";
+ requestString += trimDouble(circ.radius());
+ }
+ } else {
+ manualBoundsRequired = true;
+ }
+
+ return geocode(requestString, bounds, manualBoundsRequired, limit, offset);
}
QGeoCodeReply *QGeoCodingManagerEngineNokia::geocode(QString requestString,
const QGeoShape &bounds,
+ bool manualBoundsRequired,
int limit,
int offset)
{
- QNetworkReply *networkReply = m_networkManager->get(QNetworkRequest(QUrl(requestString)));
- QGeoCodeReplyNokia *reply = new QGeoCodeReplyNokia(networkReply, limit, offset, bounds, this);
+ QGeoCodeReplyNokia *reply = new QGeoCodeReplyNokia(
+ m_networkManager->get(QNetworkRequest(QUrl(requestString))),
+ limit, offset, bounds, manualBoundsRequired, this);
- connect(reply,
- SIGNAL(finished()),
- this,
- SLOT(placesFinished()));
+ connect(reply, &QGeoCodeReplyNokia::finished,
+ this, &QGeoCodingManagerEngineNokia::placesFinished);
- connect(reply,
- SIGNAL(error(QGeoCodeReply::Error,QString)),
- this,
- SLOT(placesError(QGeoCodeReply::Error,QString)));
+ connect(reply, static_cast<void (QGeoCodeReply::*)(QGeoCodeReply::Error, const QString &)>(&QGeoCodeReplyNokia::error),
+ this, &QGeoCodingManagerEngineNokia::placesError);
return reply;
}
+QGeoCodeReply *QGeoCodingManagerEngineNokia::reverseGeocode(const QGeoCoordinate &coordinate,
+ const QGeoShape &bounds)
+{
+ QString requestString = "https://";
+ requestString += m_reverseGeocodingUriProvider->getCurrentHost();
+ requestString += "/6.2/reversegeocode.json";
+
+ requestString += getAuthenticationString();
+ requestString += "&gen=9";
+
+ requestString += "&mode=retrieveAddresses";
+
+ requestString += "&prox=";
+ requestString += trimDouble(coordinate.latitude());
+ requestString += ",";
+ requestString += trimDouble(coordinate.longitude());
+
+ bool manualBoundsRequired = false;
+ if (bounds.type() == QGeoShape::CircleType) {
+ QGeoCircle circ(bounds);
+ if (circ.isValid() && circ.center() == coordinate) {
+ requestString += ",";
+ requestString += trimDouble(circ.radius());
+ } else {
+ manualBoundsRequired = true;
+ }
+ } else {
+ manualBoundsRequired = true;
+ }
+
+ requestString += "&language=";
+ requestString += languageToMarc(locale().language());
+
+ return geocode(requestString, bounds, manualBoundsRequired);
+}
+
QString QGeoCodingManagerEngineNokia::trimDouble(double degree, int decimalDigits)
{
QString sDegree = QString::number(degree, 'g', decimalDigits);
diff --git a/src/plugins/geoservices/nokia/qgeocodingmanagerengine_nokia.h b/src/plugins/geoservices/nokia/qgeocodingmanagerengine_nokia.h
index baa91907..9e1564aa 100644
--- a/src/plugins/geoservices/nokia/qgeocodingmanagerengine_nokia.h
+++ b/src/plugins/geoservices/nokia/qgeocodingmanagerengine_nokia.h
@@ -75,14 +75,15 @@ private Q_SLOTS:
private:
static QString trimDouble(double degree, int decimalDigits = 10);
- QGeoCodeReply *geocode(QString requestString, const QGeoShape &bounds, int limit = -1, int offset = 0);
+ QGeoCodeReply *geocode(QString requestString, const QGeoShape &bounds, bool manualBoundsRequired = true, int limit = -1, int offset = 0);
QString languageToMarc(QLocale::Language language);
QString getAuthenticationString() const;
QGeoNetworkAccessManager *m_networkManager;
+ QGeoUriProvider *m_uriProvider;
+ QGeoUriProvider *m_reverseGeocodingUriProvider;
QString m_token;
QString m_applicationId;
- QGeoUriProvider *m_uriProvider;
};
QT_END_NAMESPACE
diff --git a/src/plugins/geoservices/nokia/qplacemanagerengine_nokiav2.cpp b/src/plugins/geoservices/nokia/qplacemanagerengine_nokiav2.cpp
index ac20c262..10d304ec 100644
--- a/src/plugins/geoservices/nokia/qplacemanagerengine_nokiav2.cpp
+++ b/src/plugins/geoservices/nokia/qplacemanagerengine_nokiav2.cpp
@@ -200,7 +200,7 @@ QPlaceManagerEngineNokiaV2::QPlaceManagerEngineNokiaV2(
QString *errorString)
: QPlaceManagerEngine(parameters)
, m_manager(networkManager)
- , m_uriProvider(new QGeoUriProvider(this, parameters, QStringLiteral("here.places.host"), PLACES_HOST, PLACES_HOST_CN))
+ , m_uriProvider(new QGeoUriProvider(this, parameters, QStringLiteral("here.places.host"), PLACES_HOST))
{
Q_ASSERT(networkManager);
m_manager->setParent(this);
diff --git a/src/plugins/geoservices/nokia/uri_constants.cpp b/src/plugins/geoservices/nokia/uri_constants.cpp
index 8a075328..8db47beb 100644
--- a/src/plugins/geoservices/nokia/uri_constants.cpp
+++ b/src/plugins/geoservices/nokia/uri_constants.cpp
@@ -38,10 +38,9 @@
QT_BEGIN_NAMESPACE
const QString ROUTING_HOST = QLatin1String("route.api.here.com");
-const QString GEOCODING_HOST = QLatin1String("loc.desktop.maps.svc.ovi.com");
-const QString GEOCODING_HOST_CN = QLatin1String("pr.geo.maps.svc.nokia.com.cn");
+const QString GEOCODING_HOST = QLatin1String("geocoder.api.here.com");
+const QString REVERSE_GEOCODING_HOST = QLatin1String("reverse.geocoder.api.here.com");
const QString PLACES_HOST = QLatin1String("places.api.here.com");
-const QString PLACES_HOST_CN = QLatin1String("places.nlp.nokia.com.cn");
const QString MAP_TILES_HOST = QLatin1String("1-4.base.maps.api.here.com");
const QString MAP_TILES_HOST_AERIAL = QLatin1String("1-4.aerial.maps.api.here.com");
diff --git a/src/plugins/geoservices/nokia/uri_constants.h b/src/plugins/geoservices/nokia/uri_constants.h
index 151a4aa4..b2133fe3 100644
--- a/src/plugins/geoservices/nokia/uri_constants.h
+++ b/src/plugins/geoservices/nokia/uri_constants.h
@@ -43,9 +43,8 @@ QT_BEGIN_NAMESPACE
extern const QString ROUTING_HOST;
extern const QString GEOCODING_HOST;
-extern const QString GEOCODING_HOST_CN;
+extern const QString REVERSE_GEOCODING_HOST;
extern const QString PLACES_HOST;
-extern const QString PLACES_HOST_CN;
extern const QString MAP_TILES_HOST;
extern const QString MAP_TILES_HOST_AERIAL;