1/****************************************************************************
2**
3** Copyright (C) 2013-2018 Esri <contracts@esri.com>
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtLocation module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "placesearchreply_esri.h"
41#include "placemanagerengine_esri.h"
42
43#include <QtCore/QJsonDocument>
44#include <QtCore/QJsonArray>
45#include <QtCore/QJsonObject>
46#include <QtNetwork/QNetworkReply>
47#include <QtPositioning/QGeoCircle>
48#include <QtPositioning/QGeoRectangle>
49#include <QtLocation/QPlaceResult>
50#include <QtLocation/QPlaceSearchRequest>
51#include <QtLocation/private/qplacesearchrequest_p.h>
52
53static const QString kCandidatesKey(QStringLiteral("candidates"));
54static const QString kAttributesKey(QStringLiteral("attributes"));
55static const QString kAddressKey(QStringLiteral("address"));
56static const QString kLongLabelKey(QStringLiteral("LongLabel"));
57static const QString kCityKey(QStringLiteral("City"));
58static const QString kCountryKey(QStringLiteral("Country"));
59static const QString kRegionKey(QStringLiteral("Region"));
60static const QString kPostalKey(QStringLiteral("Postal"));
61static const QString kStAddrKey(QStringLiteral("StAddr"));
62static const QString kStateKey(QStringLiteral("State"));
63static const QString kDistrictKey(QStringLiteral("District"));
64static const QString kLocationKey(QStringLiteral("location"));
65static const QString kXKey(QStringLiteral("x"));
66static const QString kYKey(QStringLiteral("y"));
67static const QString kDistanceKey(QStringLiteral("Distance"));
68static const QString kPhoneKey(QStringLiteral("Phone"));
69static const QString kExtentKey(QStringLiteral("extent"));
70static const QString kXminKey(QStringLiteral("xmin"));
71static const QString kYminKey(QStringLiteral("ymin"));
72static const QString kXmaxKey(QStringLiteral("xmax"));
73static const QString kYmaxKey(QStringLiteral("ymax"));
74
75QT_BEGIN_NAMESPACE
76
77PlaceSearchReplyEsri::PlaceSearchReplyEsri(const QPlaceSearchRequest &request, QNetworkReply *reply,
78 const QHash<QString, QString> &candidateFields,
79 const QHash<QString, QString> &countries, PlaceManagerEngineEsri *parent) :
80 QPlaceSearchReply(parent), m_candidateFields(candidateFields), m_countries(countries)
81{
82 Q_ASSERT(parent);
83 if (!reply) {
84 setError(errorCode: UnknownError, QStringLiteral("Null reply"));
85 return;
86 }
87 setRequest(request);
88
89 connect(sender: reply, SIGNAL(finished()), receiver: this, SLOT(replyFinished()));
90 connect(sender: reply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), receiver: this, SLOT(networkError(QNetworkReply::NetworkError)));
91 connect(sender: this, signal: &QPlaceReply::aborted, receiver: reply, slot: &QNetworkReply::abort);
92 connect(sender: this, signal: &QObject::destroyed, receiver: reply, slot: &QObject::deleteLater);
93}
94
95PlaceSearchReplyEsri::~PlaceSearchReplyEsri()
96{
97}
98
99void PlaceSearchReplyEsri::setError(QPlaceReply::Error errorCode, const QString &errorString)
100{
101 QPlaceReply::setError(error: errorCode, errorString);
102 emit error(error: errorCode, errorString);
103 setFinished(true);
104 emit finished();
105}
106
107void PlaceSearchReplyEsri::replyFinished()
108{
109 QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
110 reply->deleteLater();
111
112 if (reply->error() != QNetworkReply::NoError)
113 return;
114
115 QJsonDocument document = QJsonDocument::fromJson(json: reply->readAll());
116 if (!document.isObject())
117 {
118 setError(errorCode: ParseError, errorString: tr(s: "Response parse error"));
119 return;
120 }
121
122 QJsonValue suggestions = document.object().value(key: kCandidatesKey);
123 if (!suggestions.isArray())
124 {
125 setError(errorCode: ParseError, errorString: tr(s: "Response parse error"));
126 return;
127 }
128
129 QJsonArray resultsArray = suggestions.toArray();
130
131 QList<QPlaceSearchResult> results;
132 for (int i = 0; i < resultsArray.count(); ++i)
133 {
134 QJsonObject item = resultsArray.at(i).toObject();
135 QPlaceResult placeResult = parsePlaceResult(item);
136 results.append(t: placeResult);
137 }
138
139 setResults(results);
140 setFinished(true);
141 emit finished();
142}
143
144void PlaceSearchReplyEsri::networkError(QNetworkReply::NetworkError error)
145{
146 Q_UNUSED(error)
147 QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
148 reply->deleteLater();
149 setError(errorCode: QPlaceReply::CommunicationError, errorString: reply->errorString());
150}
151
152QPlaceResult PlaceSearchReplyEsri::parsePlaceResult(const QJsonObject &item) const
153{
154 QPlace place;
155 QHash<QString, QString> keys;
156
157 // set attributes
158 const QJsonObject attributes = item.value(key: kAttributesKey).toObject();
159 for (const QString &key: attributes.keys())
160 {
161 const QString value = attributes.value(key).toVariant().toString();
162 if (!value.isEmpty())
163 {
164 QPlaceAttribute attribute;
165 attribute.setLabel(m_candidateFields.value(akey: key, adefaultValue: key)); // local name or key
166 attribute.setText(value);
167 place.setExtendedAttribute(attributeType: key, attribute);
168 keys.insert(akey: key, avalue: value);
169 }
170 }
171
172 if (keys.contains(akey: kPhoneKey))
173 {
174 QPlaceContactDetail contactDetail;
175 contactDetail.setLabel(m_candidateFields.value(akey: kPhoneKey, adefaultValue: kPhoneKey)); // local name or key
176 contactDetail.setValue(keys.value(akey: kPhoneKey));
177 place.appendContactDetail(contactType: QPlaceContactDetail::Phone, detail: contactDetail);
178 }
179
180 // set address
181 QGeoAddress geoAddress;
182 geoAddress.setCity(keys.value(akey: kCityKey));
183 geoAddress.setCountry(m_countries.value(akey: keys.value(akey: kCountryKey))); // mismatch code ISO2 vs ISO3
184 geoAddress.setCounty(keys.value(akey: kRegionKey));
185 geoAddress.setPostalCode(keys.value(akey: kPostalKey));
186 geoAddress.setStreet(keys.value(akey: kStAddrKey));
187 geoAddress.setState(keys.value(akey: kStateKey));
188 geoAddress.setDistrict(keys.value(akey: kDistrictKey));
189
190 // set location
191 const QJsonObject location = item.value(key: kLocationKey).toObject();
192 const QGeoCoordinate coordinate = QGeoCoordinate(location.value(key: kYKey).toDouble(),
193 location.value(key: kXKey).toDouble());
194
195 // set boundingBox
196 const QJsonObject extent = item.value(key: kExtentKey).toObject();
197 const QGeoCoordinate topLeft(extent.value(key: kYminKey).toDouble(),
198 extent.value(key: kXminKey).toDouble());
199 const QGeoCoordinate bottomRight(extent.value(key: kYmaxKey).toDouble(),
200 extent.value(key: kXmaxKey).toDouble());
201 const QGeoRectangle boundingBox(topLeft, bottomRight);
202
203 // set geolocation
204 QGeoLocation geoLocation;
205 geoLocation.setCoordinate(coordinate);
206 geoLocation.setAddress(geoAddress);
207 geoLocation.setBoundingBox(boundingBox);
208
209 // set place
210 place.setName(keys.value(akey: kLongLabelKey));
211 place.setLocation(geoLocation);
212 place.setPlaceId(attributes.value(key: kLongLabelKey).toString());
213
214 // set place result
215 QPlaceResult result;
216 result.setPlace(place);
217 result.setTitle(keys.value(akey: kAddressKey));
218 result.setDistance(keys.value(akey: kDistanceKey).toDouble());
219
220 return result;
221}
222
223QT_END_NAMESPACE
224

source code of qtlocation/src/plugins/geoservices/esri/placesearchreply_esri.cpp