From 91568e6301653a6e5e41a45b60eca53a2a9001b1 Mon Sep 17 00:00:00 2001 From: Alex Blasche Date: Thu, 3 Nov 2016 11:17:59 +0100 Subject: Avoid qmake warning about missing private header note Change-Id: Iec1652e68a8170f3064f1ff345085ece2867c1f3 Reviewed-by: Paolo Angelelli --- src/location/maps/qgeorouteparser_p_p.h | 11 +++++++++++ 1 file changed, 11 insertions(+) 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 #include #include -- cgit v1.2.1 From e0c93fc1530f1a325f2ac514fb61e6b9f78872d0 Mon Sep 17 00:00:00 2001 From: Maurice Kalinowski Date: Mon, 24 Oct 2016 11:02:20 +0200 Subject: winrt: Use backend provided timestamps IGeoCoordinate does provide a timestamp in system time. This value should be used to provide a timestamp to be forwarded to the user. In case the information provided is invalid, an invalid QDateTime is used for the position update. Task-number: QTBUG-56623 Change-Id: If476b41e5fd183edf33742d8e4401236a32c6037 Reviewed-by: Oliver Wolff Reviewed-by: Alex Blasche --- .../position/winrt/qgeopositioninfosource_winrt.cpp | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/plugins/position/winrt/qgeopositioninfosource_winrt.cpp b/src/plugins/position/winrt/qgeopositioninfosource_winrt.cpp index 5dbbacb5..4564c76a 100644 --- a/src/plugins/position/winrt/qgeopositioninfosource_winrt.cpp +++ b/src/plugins/position/winrt/qgeopositioninfosource_winrt.cpp @@ -331,7 +331,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); } @@ -474,7 +474,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); -- cgit v1.2.1 From 026d16d6eb7697966c562cc568930a2f3de315a6 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Thu, 3 Nov 2016 18:19:36 +0100 Subject: remove dependencies from sync.profile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit the CI obtains them from the qt5 super repo nowadays. Change-Id: I87087feffb23cf5553a6bb56bf8723924c4f2b14 Reviewed-by: Jędrzej Nowacki --- sync.profile | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/sync.profile b/sync.profile index fa9885a4..2a80bd03 100644 --- a/sync.profile +++ b/sync.profile @@ -4,17 +4,3 @@ ); %moduleheaders = ( # restrict the module headers to those found in relative path ); -# Module dependencies. -# Every module that is required to build this module should have one entry. -# Each of the module version specifiers can take one of the following values: -# - A specific Git revision. -# - any git symbolic ref resolvable from the module's repository (e.g. "refs/heads/master" to track master branch) -# - an empty string to use the same branch under test (dependencies will become "refs/heads/master" if we are in the master branch) -# -%dependencies = ( - "qtbase" => "", - "qtxmlpatterns" => "", - "qtdeclarative" => "", - "qtquickcontrols" => "", - "qtserialport" => "", -); -- cgit v1.2.1 From c1755c75f8d54a27ff931a049d6fd9718c0be6bb Mon Sep 17 00:00:00 2001 From: Alex Blasche Date: Thu, 3 Nov 2016 12:38:58 +0100 Subject: Remove duplicated but otherwise harmless code Change-Id: I35f53f136ba6a4c7d62a82f41ee193963159a392 Reviewed-by: Paolo Angelelli --- src/plugins/geoservices/osm/qgeoroutereplyosm.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/plugins/geoservices/osm/qgeoroutereplyosm.cpp b/src/plugins/geoservices/osm/qgeoroutereplyosm.cpp index 701d1224..a020ce6e 100644 --- a/src/plugins/geoservices/osm/qgeoroutereplyosm.cpp +++ b/src/plugins/geoservices/osm/qgeoroutereplyosm.cpp @@ -74,13 +74,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(parent()); const QGeoRouteParser *parser = engine->routeParser(); -- cgit v1.2.1 From 81f626f062d95abe49fcb7d8f098e54646c04034 Mon Sep 17 00:00:00 2001 From: Paolo Angelelli Date: Wed, 9 Nov 2016 17:45:50 +0100 Subject: Fix for QDeclarativeGeoMap::fitViewportToGeoShape and QGeoRectangle The current implementation fails to fit if the QGeoRectangle shape crosses the dateline. The problem does not happen with QGeoCircle. This patch fixes the problem. Change-Id: I043e9ff433f81a07f434112fe19449aec7ec94f6 Task-number: QTBUG-57027 Reviewed-by: Alex Blasche --- src/imports/location/qdeclarativegeomap.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/imports/location/qdeclarativegeomap.cpp b/src/imports/location/qdeclarativegeomap.cpp index 7e8e1728..34697836 100644 --- a/src/imports/location/qdeclarativegeomap.cpp +++ b/src/imports/location/qdeclarativegeomap.cpp @@ -810,6 +810,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: -- cgit v1.2.1 From 78c73ebf88fbb97ebb796fc71e76232af5c8f1d3 Mon Sep 17 00:00:00 2001 From: Chris Adams Date: Fri, 4 Nov 2016 15:14:07 +1000 Subject: 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 --- src/plugins/geoservices/nokia/nokia.pro | 4 +- .../geoservices/nokia/qgeocodejsonparser.cpp | 413 +++++++++++++++ src/plugins/geoservices/nokia/qgeocodejsonparser.h | 75 +++ .../geoservices/nokia/qgeocodereply_nokia.cpp | 17 +- .../geoservices/nokia/qgeocodereply_nokia.h | 3 +- .../geoservices/nokia/qgeocodexmlparser.cpp | 573 --------------------- src/plugins/geoservices/nokia/qgeocodexmlparser.h | 88 ---- .../nokia/qgeocodingmanagerengine_nokia.cpp | 194 ++++--- .../nokia/qgeocodingmanagerengine_nokia.h | 5 +- .../nokia/qplacemanagerengine_nokiav2.cpp | 2 +- src/plugins/geoservices/nokia/uri_constants.cpp | 5 +- src/plugins/geoservices/nokia/uri_constants.h | 3 +- 12 files changed, 642 insertions(+), 740 deletions(-) create mode 100644 src/plugins/geoservices/nokia/qgeocodejsonparser.cpp create mode 100644 src/plugins/geoservices/nokia/qgeocodejsonparser.h delete mode 100644 src/plugins/geoservices/nokia/qgeocodexmlparser.cpp delete mode 100644 src/plugins/geoservices/nokia/qgeocodexmlparser.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 +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +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 *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/qgeocodejsonparser.h b/src/plugins/geoservices/nokia/qgeocodejsonparser.h new file mode 100644 index 00000000..03251775 --- /dev/null +++ b/src/plugins/geoservices/nokia/qgeocodejsonparser.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QGEOCODEJSONPARSER_H +#define QGEOCODEJSONPARSER_H + +#include +#include + +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QGeoCodeJsonParser : public QObject, public QRunnable +{ + Q_OBJECT + +public: + void setBounds(const QGeoShape &bounds); + void parse(const QByteArray &data); + void run(); + +signals: + void results(const QList &locations); + void error(const QString &errorString); + +private: + QJsonDocument m_document; + QByteArray m_data; + QGeoShape m_bounds; + QList m_results; + QString m_errorString; +}; + +QT_END_NAMESPACE + +#endif 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 @@ -45,9 +45,15 @@ Q_DECLARE_METATYPE(QList) 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 >(); @@ -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)), this, SLOT(appendResults(QList))); 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 -#include -#include -#include -#include -#include - -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() -{ - /* - - - - - - - - - - - - - - - - - - */ - - 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) -{ - /* - - - - - - - - - - - - - - - - */ - - 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) -{ - /* - - - - - - - - - - - - - - */ - - 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) -{ - /* - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - - 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) -{ - /* - - - - - - - */ - - 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) -{ - /* - - - - - - - - - - - - - - - - - - - - - */ - - 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/qgeocodexmlparser.h b/src/plugins/geoservices/nokia/qgeocodexmlparser.h deleted file mode 100644 index 83a4b598..00000000 --- a/src/plugins/geoservices/nokia/qgeocodexmlparser.h +++ /dev/null @@ -1,88 +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$ -** -****************************************************************************/ - -#ifndef QGEOCODEXMLPARSER_H -#define QGEOCODEXMLPARSER_H - -#include -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -class QGeoLocation; -class QGeoAddress; -class QGeoRectangle; -class QGeoCoordinate; -class QXmlStreamReader; - -class QGeoCodeXmlParser : public QObject, public QRunnable -{ - Q_OBJECT - -public: - QGeoCodeXmlParser(); - ~QGeoCodeXmlParser(); - - void setBounds(const QGeoShape &bounds); - void parse(const QByteArray &data); - void run(); - -signals: - void results(const QList &locations); - 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; - QByteArray m_data; - QXmlStreamReader *m_reader; - - QList m_results; - QString m_errorString; -}; - -QT_END_NAMESPACE - -#endif 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 -#include +#include +#include +#include +#include +#include + #include #include #include @@ -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(&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; -- cgit v1.2.1