Revision control

++ // 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/qjsondocument.h>
++ #include <QtCore/qjsonobject.h>
++ #include <QtCore/qlocale.h>
++ #include <QtCore/qurlquery.h>
++ #include <QtCore/qurl.h>
++ #include <QtNetwork/qnetworkaccessmanager.h>
++ #include <QtNetwork/qnetworkreply.h>
++ #include <QtNetwork/qnetworkrequest.h>
++ #include <QtPositioning/qgeoaddress.h>
++ #include <QtPositioning/qgeocoordinate.h>
++ #include <QtPositioning/qgeorectangle.h>
++ #include <QtPositioning/qgeoshape.h>
++ #include <qgeocodereplyohosmapkit.h>
++ #include <qgeocodingmanagerengineohosmapkit.h>
++ #include <qohosmapkitcommon.h>
++
++ QT_BEGIN_NAMESPACE
++
++ namespace {
++
++ const QString geocodeApiBasePath = QLatin1String("https://siteapi.cloud.huawei.com/mapApi/v1/siteService/");
++ const QString geocodeApiPath = geocodeApiBasePath + QLatin1String("geocode");
++ const QString reverseGeocodeApiPath = geocodeApiBasePath + QLatin1String("reverseGeocode");
++
++ class QGeoCodingManagerEngineOhosMapKit : public QGeoCodingManagerEngine
++ {
++ public:
++ QGeoCodingManagerEngineOhosMapKit(
++ const QVariantMap &parameters, QGeoServiceProvider::Error *error, QString *errorString);
++
++ QGeoCodeReply *geocode(const QGeoAddress &address, const QGeoShape &bounds) override;
++ QGeoCodeReply *geocode(const QString &address, int limit, int offset, const QGeoShape &bounds) override;
++ QGeoCodeReply *reverseGeocode(const QGeoCoordinate &coordinate, const QGeoShape &bounds) override;
++
++ private:
++ QGeoCodeReply *createGeoCodeReply(const QUrl &requestUrl, const QByteArray &requestBody);
++
++ void onReplyFinished();
++ void onReplyError(QGeoCodeReply::Error errorCode, const QString &errorString);
++
++ QNetworkAccessManager m_networkManager;
++ QString m_userAgent;
++ QString m_authenticationKey;
++ };
++
++ QGeoCodingManagerEngineOhosMapKit::QGeoCodingManagerEngineOhosMapKit(
++ const QVariantMap &parameters, QGeoServiceProvider::Error *error, QString *errorString)
++ : QGeoCodingManagerEngine(parameters)
++ , m_userAgent(OhosMapKit::getUserAgentParameterOrDefault(parameters))
++ , m_authenticationKey(OhosMapKit::getAuthenticationKeyParameterOrEmpty(parameters))
++ {
++ if (error != nullptr)
++ *error = QGeoServiceProvider::NoError;
++
++ if (errorString != nullptr)
++ errorString->clear();
++ }
++
++ QGeoCodeReply *QGeoCodingManagerEngineOhosMapKit::geocode(
++ const QGeoAddress &address, const QGeoShape &bounds)
++ {
++ return geocode(address.text().simplified(), 0, 0, bounds);
++ }
++
++ QGeoCodeReply *QGeoCodingManagerEngineOhosMapKit::geocode(
++ const QString &address, int limit, int offset, const QGeoShape &bounds)
++ {
++ Q_UNUSED(limit)
++ Q_UNUSED(offset)
++
++ if (address.isEmpty()) {
++ return new QGeoCodeReply(
++ QGeoCodeReply::CombinationError,
++ tr("Cannot do geocoding query using empty address"),
++ this);
++ }
++
++ QJsonObject geocodeRequestBody;
++
++ constexpr int restApiMaxAddressLength = 512;
++ geocodeRequestBody.insert(QStringLiteral("address"), address.left(restApiMaxAddressLength));
++
++ auto coordinateBoundsObj =
++ OhosMapKit::CoordinateBoundsJson::tryConvertFromQGeoRectangle(bounds.boundingGeoRectangle());
++ if (!coordinateBoundsObj.isEmpty())
++ geocodeRequestBody.insert(QStringLiteral("bounds"), coordinateBoundsObj);
++
++ geocodeRequestBody.insert(QStringLiteral("language"), OhosMapKit::getLanguageCode());
++
++ return createGeoCodeReply(
++ QUrl(geocodeApiPath), QJsonDocument(geocodeRequestBody).toJson(QJsonDocument::Compact));
++ }
++
++ QGeoCodeReply *QGeoCodingManagerEngineOhosMapKit::reverseGeocode(
++ const QGeoCoordinate &coordinate, const QGeoShape &bounds)
++ {
++ if (!coordinate.isValid()) {
++ return new QGeoCodeReply(
++ QGeoCodeReply::CombinationError,
++ tr("Cannot do reverse geocoding query using non-valid coordinates"),
++ this);
++ }
++
++ QJsonObject reverseGeocodeRequestBody;
++ reverseGeocodeRequestBody.insert(
++ QStringLiteral("location"), OhosMapKit::CoordinateJson::tryConvertFromQGeoCoordinate(coordinate));
++ reverseGeocodeRequestBody.insert(QStringLiteral("language"), OhosMapKit::getLanguageCode());
++
++ if (bounds.isValid() && !bounds.isEmpty()) {
++ constexpr int restApiMinRadiusInMeters = 0;
++ constexpr int restApiMaxRadiusInMeters = 50;
++ const int radius = bounds.center().distanceTo(bounds.boundingGeoRectangle().topLeft());
++ reverseGeocodeRequestBody.insert(
++ QStringLiteral("radius"),
++ qBound(restApiMinRadiusInMeters, radius, restApiMaxRadiusInMeters));
++ }
++
++ return createGeoCodeReply(
++ QUrl(reverseGeocodeApiPath),
++ QJsonDocument(reverseGeocodeRequestBody).toJson(QJsonDocument::Compact));
++ }
++
++ QGeoCodeReply *QGeoCodingManagerEngineOhosMapKit::createGeoCodeReply(
++ const QUrl &requestUrl, const QByteArray &requestBody)
++ {
++ auto *reply = makeQGeoCodeReplyOhosMapKit(
++ m_networkManager.post(
++ OhosMapKit::createOhosMapKitNetworkRequestWithJsonBody(
++ requestUrl, m_userAgent, m_authenticationKey),
++ requestBody),
++ this);
++
++ connect(
++ reply, &QGeoCodeReply::finished,
++ this, &QGeoCodingManagerEngineOhosMapKit::onReplyFinished);
++ connect(
++ reply, &QGeoCodeReply::errorOccurred,
++ this, &QGeoCodingManagerEngineOhosMapKit::onReplyError);
++
++ return reply;
++ }
++
++ void QGeoCodingManagerEngineOhosMapKit::onReplyFinished()
++ {
++ auto *geocodeReply = qobject_cast<QGeoCodeReply *>(sender());
++ if (geocodeReply != nullptr)
++ Q_EMIT finished(geocodeReply);
++ }
++
++ void QGeoCodingManagerEngineOhosMapKit::onReplyError(
++ QGeoCodeReply::Error errorCode, const QString &errorString)
++ {
++ auto *geocodeReply = qobject_cast<QGeoCodeReply *>(sender());
++ if (geocodeReply != nullptr)
++ Q_EMIT errorOccurred(geocodeReply, errorCode, errorString);
++ }
++
++ }
++
++ QGeoCodingManagerEngine *makeQGeoCodingManagerEngineOhosMapKit(
++ const QVariantMap &parameters, QGeoServiceProvider::Error *error, QString *errorString)
++ {
++ return new QGeoCodingManagerEngineOhosMapKit(parameters, error, errorString);
++ }
++
++ QT_END_NAMESPACE