diff options
author | Liang Qi <liang.qi@qt.io> | 2016-11-24 19:36:23 +0100 |
---|---|---|
committer | Liang Qi <liang.qi@qt.io> | 2016-11-24 19:36:23 +0100 |
commit | e2ece6d1283926c5a91362933719f3d10efa2ed5 (patch) | |
tree | 5fa62a28a909fd74dbbe31fcba29dc3c5f8e74bb /src | |
parent | f0c46685091fade417f118bfdc8ccdcbb4e9b9ce (diff) | |
parent | 78c73ebf88fbb97ebb796fc71e76232af5c8f1d3 (diff) | |
download | qtlocation-5.7.tar.gz |
Merge remote-tracking branch 'origin/5.6' into 5.75.7
Change-Id: I49b1b3fc94819b5a7f2fd1ab2481a1d8ea41586b
Diffstat (limited to 'src')
15 files changed, 610 insertions, 684 deletions
diff --git a/src/imports/location/qdeclarativegeomap.cpp b/src/imports/location/qdeclarativegeomap.cpp index 53d607fb..dbea220f 100644 --- a/src/imports/location/qdeclarativegeomap.cpp +++ b/src/imports/location/qdeclarativegeomap.cpp @@ -890,6 +890,9 @@ void QDeclarativeGeoMap::fitViewportToGeoShape() QGeoRectangle rect = m_region; topLeft = rect.topLeft(); bottomRight = rect.bottomRight(); + if (bottomRight.longitude() < topLeft.longitude()) + bottomRight.setLongitude(bottomRight.longitude() + 360.0); + break; } case QGeoShape::CircleType: diff --git a/src/location/maps/qgeorouteparser_p_p.h b/src/location/maps/qgeorouteparser_p_p.h index 7bf41f87..63c773eb 100644 --- a/src/location/maps/qgeorouteparser_p_p.h +++ b/src/location/maps/qgeorouteparser_p_p.h @@ -37,6 +37,17 @@ #ifndef QGEOROUTEPARSER_P_P_H #define QGEOROUTEPARSER_P_P_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include <QtCore/private/qobject_p.h> #include <QtCore/QUrl> #include <QtLocation/qgeoroutereply.h> 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 6dcb28da..67b7e70f 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; diff --git a/src/plugins/geoservices/osm/qgeoroutereplyosm.cpp b/src/plugins/geoservices/osm/qgeoroutereplyosm.cpp index da28317f..c640e595 100644 --- a/src/plugins/geoservices/osm/qgeoroutereplyosm.cpp +++ b/src/plugins/geoservices/osm/qgeoroutereplyosm.cpp @@ -80,13 +80,6 @@ void QGeoRouteReplyOsm::networkReplyFinished() return; } - if (m_reply->error() != QNetworkReply::NoError) { - setError(QGeoRouteReply::CommunicationError, m_reply->errorString()); - m_reply->deleteLater(); - m_reply = 0; - return; - } - QGeoRoutingManagerEngineOsm *engine = qobject_cast<QGeoRoutingManagerEngineOsm *>(parent()); const QGeoRouteParser *parser = engine->routeParser(); diff --git a/src/plugins/position/winrt/qgeopositioninfosource_winrt.cpp b/src/plugins/position/winrt/qgeopositioninfosource_winrt.cpp index 245d855e..33523493 100644 --- a/src/plugins/position/winrt/qgeopositioninfosource_winrt.cpp +++ b/src/plugins/position/winrt/qgeopositioninfosource_winrt.cpp @@ -343,7 +343,7 @@ void QGeoPositionInfoSourceWinRT::virtualPositionUpdate() // We can only do this if we received a valid position before if (d->lastPosition.isValid()) { QGeoPositionInfo sent = d->lastPosition; - sent.setTimestamp(QDateTime::currentDateTime()); + sent.setTimestamp(sent.timestamp().addMSecs(updateInterval())); d->lastPosition = sent; emit positionUpdated(sent); } @@ -486,7 +486,24 @@ HRESULT QGeoPositionInfoSourceWinRT::onPositionChanged(IGeolocator *locator, IPo currentInfo.setAttribute(QGeoPositionInfo::GroundSpeed, value); } - currentInfo.setTimestamp(QDateTime::currentDateTime()); + DateTime dateTime; + hr = coord->get_Timestamp(&dateTime); + + if (dateTime.UniversalTime > 0) { + ULARGE_INTEGER uLarge; + uLarge.QuadPart = dateTime.UniversalTime; + FILETIME fileTime; + fileTime.dwHighDateTime = uLarge.HighPart; + fileTime.dwLowDateTime = uLarge.LowPart; + SYSTEMTIME systemTime; + if (FileTimeToSystemTime(&fileTime, &systemTime)) { + currentInfo.setTimestamp(QDateTime(QDate(systemTime.wYear, systemTime.wMonth, + systemTime.wDay), + QTime(systemTime.wHour, systemTime.wMinute, + systemTime.wSecond, systemTime.wMilliseconds), + Qt::UTC)); + } + } emit nativePositionUpdate(currentInfo); |