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.
Combined button and popup list for selecting options.
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")