Source code
Revision control
Copy as Markdown
// Copyright (C) 2025 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtCore/qjsonarray.h>
#include <QtCore/qjsondocument.h>
#include <QtCore/qjsonobject.h>
#include <QtCore/qmetaobject.h>
#include <QtLocation/qplace.h>
#include <QtLocation/qplaceattribute.h>
#include <QtLocation/qplacecategory.h>
#include <QtLocation/qplacecontactdetail.h>
#include <QtLocation/qplaceicon.h>
#include <QtLocation/qplaceratings.h>
#include <QtLocation/qplaceresult.h>
#include <QtLocation/qplacesearchrequest.h>
#include <QtLocation/qplacesearchresult.h>
#include <QtPositioning/qgeoaddress.h>
#include <QtPositioning/qgeolocation.h>
#include <qohosmapkitcommon.h>
#include <qplacesearchreplyohosmapkit.h>
#include <qplacemanagerengineohosmapkit.h>
QT_BEGIN_NAMESPACE
namespace {
class QPlaceSearchReplyOhosMapKit : public QPlaceSearchReply
{
public:
QPlaceSearchReplyOhosMapKit(
const QPlaceSearchRequest &request, QNetworkReply *reply, QPlaceManagerEngine *parent);
private:
void onReplyFinished();
void onNetworkError(QNetworkReply::NetworkError error);
};
void populatePlaceExtendedAttributes(const QJsonObject &poiJsonObj, QPlace &place)
{
const QJsonValue openingHours = poiJsonObj.value(QStringLiteral("openingHours"));
if (!openingHours.isUndefined() && !openingHours.isNull()) {
QPlaceAttribute attr;
attr.setLabel(QPlaceSearchReplyOhosMapKit::tr("Opening hours"));
attr.setText(openingHours.toVariant().toString());
place.setExtendedAttribute(QStringLiteral("openingHours"), attr);
}
const QJsonArray photos = poiJsonObj.value(QStringLiteral("photoUrls")).toArray();
if (!photos.isEmpty()) {
QPlaceAttribute attr;
attr.setLabel(QPlaceSearchReplyOhosMapKit::tr("Photo URLs"));
attr.setText(QString::fromUtf8(QJsonDocument(photos).toJson(QJsonDocument::Compact)));
place.setExtendedAttribute(QStringLiteral("photoUrls"), attr);
}
}
void populatePlaceFromPoiJson(const QJsonObject &poiJsonObj, QPlace &place)
{
auto phoneData = poiJsonObj.value(QStringLiteral("phone")).toVariant().toString();
if (!phoneData.isEmpty()) {
QPlaceContactDetail phoneDetail;
phoneDetail.setLabel(QPlaceSearchReplyOhosMapKit::tr("Phone"));
phoneDetail.setValue(phoneData);
place.appendContactDetail(QPlaceContactDetail::Phone, phoneDetail);
}
auto internationalPhoneData =
poiJsonObj.value(QStringLiteral("internationalPhone")).toVariant().toString();
if (!internationalPhoneData.isEmpty()) {
QPlaceContactDetail intlPhoneDetail;
intlPhoneDetail.setLabel(QPlaceSearchReplyOhosMapKit::tr("International phone"));
intlPhoneDetail.setValue(internationalPhoneData);
place.appendContactDetail(QPlaceContactDetail::Phone, intlPhoneDetail);
}
auto websiteUrl = poiJsonObj.value(QStringLiteral("websiteUrl")).toVariant().toString();
if (!websiteUrl.isEmpty()) {
QPlaceContactDetail websiteDetail;
websiteDetail.setLabel(QPlaceSearchReplyOhosMapKit::tr("Website"));
websiteDetail.setValue(internationalPhoneData);
place.appendContactDetail(QPlaceContactDetail::Website, websiteDetail);
}
auto rating = poiJsonObj.value(QStringLiteral("rating")).toDouble(0.0);
if (rating > 0.0) {
QPlaceRatings ratings;
ratings.setAverage(rating);
place.setRatings(ratings);
}
auto iconUrl = poiJsonObj.value(QStringLiteral("icon")).toVariant().toUrl();
if (!iconUrl.isEmpty()) {
QPlaceIcon icon;
icon.setParameters({{QPlaceIcon::SingleUrl, iconUrl}});
place.setIcon(icon);
}
auto hwPoi = poiJsonObj.value(QStringLiteral("hwPoiTypes")).toArray();
if (!hwPoi.isEmpty()) {
auto id = hwPoi.first().toVariant().toString();
if (!id.isEmpty()) {
QPlaceCategory c;
c.setCategoryId(id);
place.setCategory(c);
}
}
populatePlaceExtendedAttributes(poiJsonObj, place);
}
QPlaceResult siteJsonObjToPlaceResult(const QJsonObject &siteJsonObj)
{
QPlace place;
place.setName(siteJsonObj.value(QStringLiteral("name")).toVariant().toString());
place.setLocation(OhosMapKit::SiteJson::tryConvertToQGeoLocation(siteJsonObj));
const QJsonObject poiObj = siteJsonObj.value(QStringLiteral("poi")).toObject();
if (!poiObj.isEmpty())
populatePlaceFromPoiJson(poiObj, place);
QPlaceResult result;
result.setPlace(place);
result.setDistance(siteJsonObj.value(QStringLiteral("distance")).toVariant().toInt());
return result;
}
QList<QPlaceSearchResult> parsePlaceSearchResponse(const QJsonDocument &responseBodyJsonDoc)
{
QList<QPlaceSearchResult> results;
const QJsonObject responseBodyJsonObj = responseBodyJsonDoc.object();
if (responseBodyJsonObj.contains(QStringLiteral("sites"))) {
const QJsonArray sites = responseBodyJsonObj.value(QStringLiteral("sites")).toArray();
for (const QJsonValue &siteValue : sites) {
if (siteValue.isObject())
results.append(siteJsonObjToPlaceResult(siteValue.toObject()));
}
}
return results;
}
QPlaceSearchReplyOhosMapKit::QPlaceSearchReplyOhosMapKit(
const QPlaceSearchRequest &request, QNetworkReply *reply, QPlaceManagerEngine *parent)
: QPlaceSearchReply(parent)
{
Q_ASSERT(parent);
if (!reply) {
setError(QPlaceReply::UnknownError, QStringLiteral("Null reply"));
return;
}
setRequest(request);
connect(reply, &QNetworkReply::finished, this, &QPlaceSearchReplyOhosMapKit::onReplyFinished);
connect(reply, &QNetworkReply::errorOccurred, this, &QPlaceSearchReplyOhosMapKit::onNetworkError);
connect(this, &QPlaceReply::aborted, reply, &QNetworkReply::abort);
connect(this, &QObject::destroyed, reply, &QObject::deleteLater);
}
void QPlaceSearchReplyOhosMapKit::onReplyFinished()
{
auto *reply = static_cast<QNetworkReply *>(sender());
reply->deleteLater();
auto setErrorEmitAndFinish = [&](QPlaceReply::Error errorCode, const QString &errorString) {
setError(errorCode, errorString);
Q_EMIT errorOccurred(errorCode, errorString);
setFinished(true);
Q_EMIT finished();
};
if (reply->error() != QNetworkReply::NoError) {
setErrorEmitAndFinish(
QPlaceReply::CommunicationError,
OhosMapKit::msgReplyError(reply->errorString()));
return;
}
const auto responseBodyJsonDoc = QJsonDocument::fromJson(reply->readAll());
if (!responseBodyJsonDoc.isObject()) {
setErrorEmitAndFinish(QPlaceReply::ParseError, tr("Response parse error"));
return;
}
auto results = parsePlaceSearchResponse(responseBodyJsonDoc);
if (request().relevanceHint() == QPlaceSearchRequest::DistanceHint) {
std::sort(
results.begin(), results.end(),
[](const auto &a, const auto &b) {
return
a.type() == QPlaceSearchResult::PlaceResult
&& b.type() == QPlaceSearchResult::PlaceResult
&& QPlaceResult(a).distance() < QPlaceResult(b).distance();
});
} else if (request().relevanceHint() == QPlaceSearchRequest::LexicalPlaceNameHint) {
std::sort(
results.begin(), results.end(),
[](const auto &a, const auto &b) {
return
a.type() == QPlaceSearchResult::PlaceResult
&& b.type() == QPlaceSearchResult::PlaceResult
&& QPlaceResult(a).place().name() < QPlaceResult(b).place().name();
});
}
setResults(results);
setFinished(true);
Q_EMIT finished();
}
void QPlaceSearchReplyOhosMapKit::onNetworkError(QNetworkReply::NetworkError error)
{
Q_UNUSED(error)
auto *reply = static_cast<QNetworkReply *>(sender());
reply->deleteLater();
setError(QPlaceReply::CommunicationError, reply->errorString());
}
}
QPlaceSearchReply *makeQPlaceSearchReplyOhosMapKit(
const QPlaceSearchRequest &request, QNetworkReply *reply, QPlaceManagerEngine *parent)
{
return new QPlaceSearchReplyOhosMapKit(request, reply, parent);
}
QT_END_NAMESPACE