8#include <QJsonDocument>
11#include <QtCore/QUrlQuery>
13#include <QtPositioning/QGeoRectangle>
14#include <QtPositioning/QGeoShape>
16#include <QtLocation/QPlaceCategory>
17#include <QtLocation/QPlaceSearchRequest>
36 "https://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer?f=pjson");
38 "GeocodeServer/findAddressCandidates");
41 QString *errorString) :
42 QPlaceManagerEngine(parameters),
43 m_networkManager(
new QNetworkAccessManager(
this))
45 *error = QGeoServiceProvider::NoError;
67 bool unsupported =
false;
70 unsupported |= request.visibilityScope() != QLocation::UnspecifiedVisibility &&
71 request.visibilityScope() != QLocation::PublicVisibility;
72 unsupported |= request.searchTerm().isEmpty() && request.categories().isEmpty();
75 return QPlaceManagerEngine::search(request);
78 queryItems.addQueryItem(QStringLiteral(
"f"), QStringLiteral(
"json"));
80 const QGeoCoordinate center = request.searchArea().center();
83 const QString location = QString(
"%1,%2").arg(center.longitude()).arg(center.latitude());
84 queryItems.addQueryItem(kLocationKey, location);
87 const QGeoRectangle boundingBox = request.searchArea().boundingGeoRectangle();
88 if (!boundingBox.isEmpty())
90 const QString searchExtent = QString(
"%1,%2,%3,%4")
91 .arg(boundingBox.topLeft().longitude())
92 .arg(boundingBox.topLeft().latitude())
93 .arg(boundingBox.bottomRight().longitude())
94 .arg(boundingBox.bottomRight().latitude());
95 queryItems.addQueryItem(QStringLiteral(
"searchExtent"), searchExtent);
98 if (!request.searchTerm().isEmpty())
99 queryItems.addQueryItem(kSingleLineKey, request.searchTerm());
101 QStringList categories;
102 if (!request.categories().isEmpty())
104 for (
const QPlaceCategory &placeCategory : request.categories())
105 categories.append(placeCategory.categoryId());
106 queryItems.addQueryItem(
"category", categories.join(
","));
109 if (request.limit() > 0)
110 queryItems.addQueryItem(kMaxLocationsKey, QString::number(request.limit()));
112 queryItems.addQueryItem(kOutFieldsKey, QStringLiteral(
"*"));
115 requestUrl.setQuery(queryItems);
117 QNetworkRequest networkRequest(requestUrl);
118 networkRequest.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy);
119 QNetworkReply *networkReply = m_networkManager->get(networkRequest);
121 PlaceSearchReplyEsri *reply =
new PlaceSearchReplyEsri(request, networkReply, m_candidateFieldsLocale, m_countriesLocale,
this);
122 connect(reply, &PlaceSearchReplyEsri::finished,
123 this, &PlaceManagerEngineEsri::replyFinished);
124 connect(reply, &PlaceSearchReplyEsri::errorOccurred,
125 this, &PlaceManagerEngineEsri::replyError);
132 QPlaceReply *reply = qobject_cast<QPlaceReply *>(sender());
134 emit finished(reply);
139 QPlaceReply *reply = qobject_cast<QPlaceReply *>(sender());
141 emit errorOccurred(reply, errorCode, errorString);
148 initializeGeocodeServer();
150 PlaceCategoriesReplyEsri *reply =
new PlaceCategoriesReplyEsri(
this);
151 connect(reply, &PlaceCategoriesReplyEsri::finished,
152 this, &PlaceManagerEngineEsri::replyFinished);
153 connect(reply, &PlaceCategoriesReplyEsri::errorOccurred,
154 this, &PlaceManagerEngineEsri::replyError);
157 if (!m_categories.isEmpty())
158 reply->emitFinished();
160 m_pendingCategoriesReply.append(reply);
166 for (
const QJsonValueConstRef jsonValue : jsonArray)
168 if (!jsonValue.isObject())
171 const QJsonObject jsonCategory = jsonValue.toObject();
172 const QString key = jsonCategory.value(kNameKey).toString();
173 const QString localeName = localizedName(jsonCategory);
178 QPlaceCategory category;
179 category.setCategoryId(key);
180 category.setName(localeName.isEmpty() ? key : localeName);
181 m_categories.insert(key, category);
182 m_subcategories[parentCategoryId].append(key);
183 m_parentCategory.insert(key, parentCategoryId);
184 emit categoryAdded(category, parentCategoryId);
186 if (jsonCategory.contains(kCategoriesKey))
188 const QJsonArray jsonArray = jsonCategory.value(kCategoriesKey).toArray();
189 parseCategories(jsonArray, key);
196 return m_parentCategory.value(categoryId);
201 return m_subcategories.value(categoryId);
206 return m_categories.value(categoryId);
211 QList<QPlaceCategory> categories;
212 for (
const QString &id : m_subcategories.value(parentId))
213 categories.append(m_categories.value(id));
219 for (PlaceCategoriesReplyEsri *reply : m_pendingCategoriesReply)
220 reply->emitFinished();
221 m_pendingCategoriesReply.clear();
226 for (PlaceCategoriesReplyEsri *reply : m_pendingCategoriesReply)
227 reply->setError(QPlaceReply::CommunicationError, error);
235 if (m_categories.isEmpty() && !m_geocodeServerReply)
237 m_geocodeServerReply = m_networkManager->get(QNetworkRequest(kUrlGeocodeServer));
238 connect(m_geocodeServerReply, &QNetworkReply::finished,
239 this, &PlaceManagerEngineEsri::geocodeServerReplyFinished);
240 connect(m_geocodeServerReply, &QNetworkReply::errorOccurred,
241 this, &PlaceManagerEngineEsri::geocodeServerReplyError);
247 const QJsonObject localizedNames = jsonObject.value(kLocalizedNamesKey).toObject();
249 for (
const QLocale &locale : std::as_const(m_locales)) {
250 const QString localeStr = locale.name();
251 if (localizedNames.contains(localeStr))
253 return localizedNames.value(localeStr).toString();
256 const QString shortLocale = localeStr.left(2);
257 if (localizedNames.contains(shortLocale))
259 return localizedNames.value(shortLocale).toString();
267 for (
const QJsonValueConstRef jsonValue : jsonArray)
269 if (!jsonValue.isObject())
272 const QJsonObject jsonCandidateField = jsonValue.toObject();
273 if (!jsonCandidateField.contains(kLocalizedNamesKey))
276 const QString key = jsonCandidateField.value(kNameKey).toString();
277 m_candidateFieldsLocale.insert(key, localizedName(jsonCandidateField));
283 for (
const QJsonValueConstRef jsonValue : jsonArray)
285 if (!jsonValue.isObject())
288 const QJsonObject jsonCountry = jsonValue.toObject();
289 if (!jsonCountry.contains(kLocalizedNamesKey))
292 const QString key = jsonCountry.value(kNameKey).toString();
293 m_countriesLocale.insert(key, localizedName(jsonCountry));
299 if (!m_geocodeServerReply)
302 QJsonDocument document = QJsonDocument::fromJson(m_geocodeServerReply->readAll());
303 if (!document.isObject())
305 errorCaterogies(m_geocodeServerReply->errorString());
309 QJsonObject jsonObject = document.object();
312 if (jsonObject.contains(kCategoriesKey))
314 const QJsonArray jsonArray = jsonObject.value(kCategoriesKey).toArray();
315 parseCategories(jsonArray, QString());
319 if (jsonObject.contains(kCandidateFieldsKey))
321 const QJsonArray jsonArray = jsonObject.value(kCandidateFieldsKey).toArray();
322 parseCandidateFields(jsonArray);
326 if (jsonObject.contains(kCountriesKey))
328 const QJsonArray jsonArray = jsonObject.value(kCountriesKey).toArray();
329 parseCountries(jsonArray);
334 m_geocodeServerReply->deleteLater();
339 if (m_categories.isEmpty() && !m_geocodeServerReply)
342 errorCaterogies(m_geocodeServerReply->errorString());
QPlaceReply * initializeCategories() override
Initializes the categories of the manager engine.
QStringList childCategoryIds(const QString &categoryId) const override
Returns the child category identifiers of the category corresponding to categoryId.
QPlaceSearchReply * search(const QPlaceSearchRequest &request) override
Searches for places according to the parameters specified in request.
QList< QPlaceCategory > childCategories(const QString &parentId) const override
Returns a list of categories that are children of the category corresponding to parentId.
QList< QLocale > locales() const override
Returns a list of preferred locales.
~PlaceManagerEngineEsri()
void setLocales(const QList< QLocale > &locales) override
Set the list of preferred locales.
QPlaceCategory category(const QString &categoryId) const override
Returns the category corresponding to the given categoryId.
QString parentCategoryId(const QString &categoryId) const override
Returns the parent category identifier of the category corresponding to categoryId.
static const QString kSingleLineKey(QStringLiteral("singleLine"))
static const QString kCountriesKey(QStringLiteral("detailedCountries"))
static const QString kLocalizedNamesKey(QStringLiteral("localizedNames"))
static const QString kOutFieldsKey(QStringLiteral("outFields"))
static const QString kCandidateFieldsKey(QStringLiteral("candidateFields"))
static const QString kMaxLocationsKey(QStringLiteral("maxLocations"))
static QT_BEGIN_NAMESPACE const QString kCategoriesKey(QStringLiteral("categories"))
static const QString kLocationKey(QStringLiteral("location"))
static const QUrl kUrlFindAddressCandidates("https://geocode.arcgis.com/arcgis/rest/services/World/" "GeocodeServer/findAddressCandidates")
static const QString kNameKey(QStringLiteral("name"))
static const QUrl kUrlGeocodeServer("https://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer?f=pjson")