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 "geocodingmanagerengine_esri.h"
41#include "geocodereply_esri.h"
42
43#include <QVariantMap>
44#include <QUrl>
45#include <QUrlQuery>
46#include <QLocale>
47#include <QNetworkAccessManager>
48#include <QNetworkRequest>
49#include <QGeoCoordinate>
50#include <QGeoAddress>
51#include <QGeoShape>
52#include <QGeoRectangle>
53
54QT_BEGIN_NAMESPACE
55
56// https://developers.arcgis.com/rest/geocode/api-reference/geocoding-find-address-candidates.htm
57// https://developers.arcgis.com/rest/geocode/api-reference/geocoding-reverse-geocode.htm
58
59static const QString kPrefixEsri(QStringLiteral("esri."));
60static const QString kParamUserAgent(kPrefixEsri + QStringLiteral("useragent"));
61
62static const QString kUrlGeocode(QStringLiteral("http://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/findAddressCandidates"));
63static const QString kUrlReverseGeocode(QStringLiteral("http://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/reverseGeocode"));
64
65static QString addressToQuery(const QGeoAddress &address)
66{
67 return address.street() + QStringLiteral(", ")
68 + address.district() + QStringLiteral(", ")
69 + address.city() + QStringLiteral(", ")
70 + address.state() + QStringLiteral(", ")
71 + address.country();
72}
73
74static QString boundingBoxToLtrb(const QGeoRectangle &rect)
75{
76 return QString::number(rect.topLeft().longitude()) + QLatin1Char(',')
77 + QString::number(rect.topLeft().latitude()) + QLatin1Char(',')
78 + QString::number(rect.bottomRight().longitude()) + QLatin1Char(',')
79 + QString::number(rect.bottomRight().latitude());
80}
81
82GeoCodingManagerEngineEsri::GeoCodingManagerEngineEsri(const QVariantMap &parameters,
83 QGeoServiceProvider::Error *error,
84 QString *errorString)
85: QGeoCodingManagerEngine(parameters), m_networkManager(new QNetworkAccessManager(this))
86{
87 if (parameters.contains(akey: kParamUserAgent))
88 m_userAgent = parameters.value(akey: kParamUserAgent).toString().toLatin1();
89 else
90 m_userAgent = QByteArrayLiteral("Qt Location based application");
91
92 *error = QGeoServiceProvider::NoError;
93 errorString->clear();
94}
95
96GeoCodingManagerEngineEsri::~GeoCodingManagerEngineEsri()
97{
98}
99
100QGeoCodeReply *GeoCodingManagerEngineEsri::geocode(const QGeoAddress &address,
101 const QGeoShape &bounds)
102{
103 return geocode(address: addressToQuery(address), limit: 1, offset: -1, bounds);
104}
105
106QGeoCodeReply *GeoCodingManagerEngineEsri::geocode(const QString &address, int limit, int offset,
107 const QGeoShape &bounds)
108{
109 Q_UNUSED(offset);
110
111 QNetworkRequest request;
112 request.setHeader(header: QNetworkRequest::UserAgentHeader, value: m_userAgent);
113
114 QUrl url(kUrlGeocode);
115
116 QUrlQuery query;
117 query.addQueryItem(QStringLiteral("singleLine"), value: address);
118 query.addQueryItem(QStringLiteral("f"), QStringLiteral("json"));
119 query.addQueryItem(QStringLiteral("outFields"), value: "*");
120
121 if (bounds.type() != QGeoShape::UnknownType)
122 query.addQueryItem(QStringLiteral("searchExtent"), value: boundingBoxToLtrb(rect: bounds.boundingGeoRectangle()));
123
124 if (limit != -1)
125 query.addQueryItem(QStringLiteral("maxLocations"), value: QString::number(limit));
126
127 url.setQuery(query);
128 request.setUrl(url);
129
130 QNetworkReply *reply = m_networkManager->get(request);
131 GeoCodeReplyEsri *geocodeReply = new GeoCodeReplyEsri(reply, GeoCodeReplyEsri::Geocode, this);
132
133 connect(sender: geocodeReply, SIGNAL(finished()), receiver: this, SLOT(replyFinished()));
134 connect(sender: geocodeReply, SIGNAL(error(QGeoCodeReply::Error,QString)),
135 receiver: this, SLOT(replyError(QGeoCodeReply::Error,QString)));
136
137 return geocodeReply;
138}
139
140QGeoCodeReply *GeoCodingManagerEngineEsri::reverseGeocode(const QGeoCoordinate &coordinate,
141 const QGeoShape &bounds)
142{
143 Q_UNUSED(bounds);
144
145 QNetworkRequest request;
146 request.setHeader(header: QNetworkRequest::UserAgentHeader, value: m_userAgent);
147
148 QUrl url(kUrlReverseGeocode);
149
150 QUrlQuery query;
151
152 query.addQueryItem(QStringLiteral("f"), QStringLiteral("json"));
153 query.addQueryItem(QStringLiteral("langCode"), value: locale().name().left(n: 2));
154 query.addQueryItem(QStringLiteral("location"), value: QString::number(coordinate.longitude()) + QLatin1Char(',')
155 + QString::number(coordinate.latitude()));
156
157 url.setQuery(query);
158 request.setUrl(url);
159
160 QNetworkReply *reply = m_networkManager->get(request);
161 GeoCodeReplyEsri *geocodeReply = new GeoCodeReplyEsri(reply, GeoCodeReplyEsri::ReverseGeocode,
162 this);
163
164 connect(sender: geocodeReply, SIGNAL(finished()), receiver: this, SLOT(replyFinished()));
165 connect(sender: geocodeReply, SIGNAL(error(QGeoCodeReply::Error,QString)),
166 receiver: this, SLOT(replyError(QGeoCodeReply::Error,QString)));
167
168 return geocodeReply;
169}
170
171void GeoCodingManagerEngineEsri::replyFinished()
172{
173 QGeoCodeReply *reply = qobject_cast<QGeoCodeReply *>(object: sender());
174 if (reply)
175 emit finished(reply);
176}
177
178void GeoCodingManagerEngineEsri::replyError(QGeoCodeReply::Error errorCode,
179 const QString &errorString)
180{
181 QGeoCodeReply *reply = qobject_cast<QGeoCodeReply *>(object: sender());
182 if (reply)
183 emit error(reply, error: errorCode, errorString);
184}
185
186QT_END_NAMESPACE
187

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