├── .github └── workflows │ └── windows.yml ├── .gitignore ├── LICENSE.txt ├── README.md ├── amap.pro ├── amap_plugin.json ├── example ├── TemperatureMap-3D高清矢量地图.gif ├── amap1.png ├── amap2.png ├── amap3.png ├── example.pro ├── example3Dbuilds.gif ├── main.cpp ├── main.qml └── qml.qrc ├── qgeocodereplyamap.cpp ├── qgeocodereplyamap.h ├── qgeocodingmanagerengineamap.cpp ├── qgeocodingmanagerengineamap.h ├── qgeoerror_messages.cpp ├── qgeoerror_messages.h ├── qgeomapreplyamap.cpp ├── qgeomapreplyamap.h ├── qgeoroutereplyamap.cpp ├── qgeoroutereplyamap.h ├── qgeoroutingmanagerengineamap.cpp ├── qgeoroutingmanagerengineamap.h ├── qgeoserviceproviderpluginamap.cpp ├── qgeoserviceproviderpluginamap.h ├── qgeotiledmapamap.cpp ├── qgeotiledmapamap.h ├── qgeotiledmappingmanagerengineamap.cpp ├── qgeotiledmappingmanagerengineamap.h ├── qgeotilefetcheramap.cpp ├── qgeotilefetcheramap.h ├── qplacecategoriesreplyamap.cpp ├── qplacecategoriesreplyamap.h ├── qplacemanagerengineamap.h ├── qplacemanagerengineamp.cpp ├── qplacesearchreplyamap.cpp ├── qplacesearchreplyamap.h ├── qplacesearchsuggestionreplyimpl.cpp ├── qplacesearchsuggestionreplyimpl.h └── scripts └── windows-publish.ps1 /.github/workflows/windows.yml: -------------------------------------------------------------------------------- 1 | name: Windows 2 | on: 3 | # push代码时触发workflow 4 | push: 5 | paths: 6 | - '**' 7 | # pull_request时触发workflow 8 | pull_request: 9 | paths: 10 | - '**' 11 | jobs: 12 | build: 13 | name: Build 14 | # 运行平台, windows-latest目前是windows server 2019 15 | # 参考文档 https://github.com/actions/virtual-environments/blob/main/images/win/Windows2019-Readme.md 16 | runs-on: windows-2019 17 | strategy: 18 | # 矩阵配置 19 | matrix: 20 | include: 21 | - qt_ver: 6.7.2 22 | qt_arch: win64_msvc2019_64 23 | msvc_arch: x64 24 | qt_arch_install: msvc2019_64 25 | env: 26 | targetName: amap 27 | # 步骤 28 | steps: 29 | # 安装Qt 30 | - name: Install Qt 31 | # 使用外部action。这个action专门用来安装Qt 32 | uses: jurplel/install-qt-action@v4 33 | with: 34 | # Version of Qt to install 35 | version: ${{ matrix.qt_ver }} 36 | aqtversion: ==3.1.* 37 | host: windows 38 | target: desktop 39 | arch: ${{ matrix.qt_arch }} 40 | modules: qtlocation qtpositioning qt5compat 41 | setup-python: true 42 | cached: 'false' 43 | # 拉取代码 44 | - uses: actions/checkout@v2 45 | with: 46 | fetch-depth: 1 47 | submodules: 'true' 48 | # msvc编译 49 | - name: msvc-build 50 | id: build 51 | shell: cmd 52 | run: | 53 | call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ${{ matrix.msvc_arch }} 54 | qmake 55 | nmake 56 | echo winSdkDir=%WindowsSdkDir% >> %GITHUB_ENV% 57 | echo winSdkVer=%WindowsSdkVersion% >> %GITHUB_ENV% 58 | echo vcToolsInstallDir=%VCToolsInstallDir% >> %GITHUB_ENV% 59 | echo vcToolsRedistDir=%VCToolsRedistDir% >> %GITHUB_ENV% 60 | mkdir -p plugins\geoservices 61 | cp -p release\qtgeoservices_amap.dll plugins\geoservices\qtgeoservices_amap.dll 62 | # tag 打包 63 | - name: package 64 | id: package 65 | # if: startsWith(github.event.ref, 'refs/tags/') 66 | env: 67 | archiveName: ${{ matrix.qt_ver }}-${{ matrix.qt_arch }} 68 | msvcArch: ${{ matrix.msvc_arch }} 69 | shell: pwsh 70 | run: | 71 | & scripts\windows-publish.ps1 ${env:archiveName} ${env:targetName} 72 | # 记录packageName给后续step 73 | $name = ${env:archiveName} 74 | echo "::set-output name=packageName::$name" 75 | # 上传artifacts 76 | - uses: actions/upload-artifact@v2 77 | with: 78 | name: ${{ steps.package.outputs.packageName }} 79 | path: ${{ steps.package.outputs.packageName }}.zip 80 | # tag 上传Release 81 | - name: uploadRelease 82 | if: startsWith(github.event.ref, 'refs/tags/') 83 | uses: svenstaro/upload-release-action@v2 84 | with: 85 | repo_token: ${{ secrets.GITHUB_TOKEN }} 86 | file: ${{ steps.package.outputs.packageName }}.zip 87 | asset_name: ${{ steps.package.outputs.packageName }}.zip 88 | tag: ${{ github.ref }} 89 | overwrite: true -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | *.user 3 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Sinden https://github.com/SindenDev/amap 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Amap Maps plugin for QtLocation [Support Qt5、Qt6] 2 | 3 | ## 高德地图Qt插件 plugin for QtLocation module 4 | * Qt地图插件,使用简单方便,不用浏览器内核,运行高效迅猛; 5 | * 跨平台支持,(Qt Windows(MinGW, MSVC)\Linux(桌面、嵌入式)\Android\IOS\QNX都可以的亲测试过),鸿蒙(还没试过); 6 | * 在线更新下载,支持离线地图; 7 | * 支持地图倾斜、旋转、方位调整等; 8 | 9 | ## 编译工程 10 | 1.将在生成目录编译出插件(以使用MinGW为例子) 11 | ``` 12 | plugins\geoservices\qtgeoservices_amap.dll 13 | plugins\geoservices\qtgeoservices_amapd.dll 14 | ``` 15 | 16 | 2.将(qtgeoservices_amap.dll 、qtgeoservices_amapd.dll)拷贝插件到Qt的 plugins\geoservices 定位插件目录 17 | 注意:以下路径是以使用MinGW为例子 18 | ``` 19 | C:\Qt\Qt5.13.2\5.13.2\mingw53_32\plugins\geoservices 20 | ``` 21 | ## 接下来就可以非常容易的使用,QML建立地图高德地图(example目录的测试工程) 22 | ``` 23 | import QtQuick 2.12 24 | import QtQuick.Window 2.12 25 | import QtPositioning 5.12 26 | import QtLocation 5.12 27 | 28 | Window { 29 | visible: true 30 | width: 640 31 | height: 480 32 | title: qsTr("Hello AMap") 33 | 34 | Map{ 35 | anchors.fill:parent 36 | plugin: Plugin{ 37 | name: "amap" 38 | } 39 | } 40 | } 41 | ``` 42 | MapType:街景 43 | ![](example/amap1.png) 44 | MapType:室内 45 | ![](example/amap2.png) 46 | MapType:卫星 47 | ![](example/amap3.png) 48 | 49 | 3D矢量地图以及overlay模型展示 50 | ![效果图](example/example3Dbuilds.gif) 51 | ![效果图](example/TemperatureMap-3D高清矢量地图.gif) 52 | -------------------------------------------------------------------------------- /amap.pro: -------------------------------------------------------------------------------- 1 | TARGET = qtgeoservices_amap 2 | QT += location-private positioning-private network 3 | 4 | PLUGIN_TYPE = geoservices 5 | PLUGIN_CLASS_NAME = QGeoServiceProviderFactoryAmap 6 | greaterThan(QT_MAJOR_VERSION, 5){ 7 | TEMPLATE = lib 8 | CONFIG += plugin c++17 9 | }else{ 10 | load(qt_plugin) 11 | } 12 | !isEmpty(target.path): INSTALLS += target 13 | 14 | HEADERS += \ 15 | qgeotilefetcheramap.h \ 16 | qplacesearchsuggestionreplyimpl.h \ 17 | qgeoerror_messages.h \ 18 | qgeocodereplyamap.h \ 19 | qgeocodingmanagerengineamap.h \ 20 | qgeomapreplyamap.h \ 21 | qgeoroutereplyamap.h \ 22 | qgeoroutingmanagerengineamap.h \ 23 | qgeoserviceproviderpluginamap.h \ 24 | qgeotiledmapamap.h \ 25 | qgeotiledmappingmanagerengineamap.h \ 26 | qgeotilefetcheramap.h \ 27 | qplacecategoriesreplyamap.h \ 28 | qplacemanagerengineamap.h \ 29 | qplacesearchreplyamap.h 30 | 31 | SOURCES += \ 32 | qplacesearchsuggestionreplyimpl.cpp \ 33 | qgeoerror_messages.cpp \ 34 | qgeocodereplyamap.cpp \ 35 | qgeocodingmanagerengineamap.cpp \ 36 | qgeomapreplyamap.cpp \ 37 | qgeoroutereplyamap.cpp \ 38 | qgeoroutingmanagerengineamap.cpp \ 39 | qgeoserviceproviderpluginamap.cpp \ 40 | qgeotiledmapamap.cpp \ 41 | qgeotiledmappingmanagerengineamap.cpp \ 42 | qgeotilefetcheramap.cpp \ 43 | qplacecategoriesreplyamap.cpp \ 44 | qplacemanagerengineamp.cpp \ 45 | qplacesearchreplyamap.cpp 46 | 47 | 48 | OTHER_FILES += \ 49 | amap_plugin.json 50 | 51 | DISTFILES += \ 52 | README.md 53 | 54 | -------------------------------------------------------------------------------- /amap_plugin.json: -------------------------------------------------------------------------------- 1 | { 2 | "Keys": ["amap"], 3 | "Provider": "amap", 4 | "Version": 300, 5 | "Experimental": false, 6 | "Features": [ 7 | "OnlineGeocodingFeature", 8 | "ReverseGeocodingFeature", 9 | "OnlineRoutingFeature", 10 | "AlternativeRoutesFeature", 11 | "OnlineMappingFeature", 12 | "SearchSuggestionsFeature" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /example/TemperatureMap-3D高清矢量地图.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SindenDev/amap/2dfdbf54af623e13c04767e8a612d883a8aa6faf/example/TemperatureMap-3D高清矢量地图.gif -------------------------------------------------------------------------------- /example/amap1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SindenDev/amap/2dfdbf54af623e13c04767e8a612d883a8aa6faf/example/amap1.png -------------------------------------------------------------------------------- /example/amap2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SindenDev/amap/2dfdbf54af623e13c04767e8a612d883a8aa6faf/example/amap2.png -------------------------------------------------------------------------------- /example/amap3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SindenDev/amap/2dfdbf54af623e13c04767e8a612d883a8aa6faf/example/amap3.png -------------------------------------------------------------------------------- /example/example.pro: -------------------------------------------------------------------------------- 1 | QT += quick 2 | 3 | CONFIG += c++11 4 | 5 | # The following define makes your compiler emit warnings if you use 6 | # any Qt feature that has been marked deprecated (the exact warnings 7 | # depend on your compiler). Refer to the documentation for the 8 | # deprecated API to know how to port your code away from it. 9 | DEFINES += QT_DEPRECATED_WARNINGS 10 | 11 | # You can also make your code fail to compile if it uses deprecated APIs. 12 | # In order to do so, uncomment the following line. 13 | # You can also select to disable deprecated APIs only up to a certain version of Qt. 14 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 15 | 16 | SOURCES += \ 17 | main.cpp 18 | 19 | RESOURCES += qml.qrc 20 | 21 | # Additional import path used to resolve QML modules in Qt Creator's code model 22 | QML_IMPORT_PATH = 23 | 24 | # Additional import path used to resolve QML modules just for Qt Quick Designer 25 | QML_DESIGNER_IMPORT_PATH = 26 | 27 | # Default rules for deployment. 28 | qnx: target.path = /tmp/$${TARGET}/bin 29 | else: unix:!android: target.path = /opt/$${TARGET}/bin 30 | !isEmpty(target.path): INSTALLS += target 31 | -------------------------------------------------------------------------------- /example/example3Dbuilds.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SindenDev/amap/2dfdbf54af623e13c04767e8a612d883a8aa6faf/example/example3Dbuilds.gif -------------------------------------------------------------------------------- /example/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); 7 | 8 | QGuiApplication app(argc, argv); 9 | 10 | QQmlApplicationEngine engine; 11 | const QUrl url(QStringLiteral("qrc:/main.qml")); 12 | QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, 13 | &app, [url](QObject *obj, const QUrl &objUrl) { 14 | if (!obj && url == objUrl) 15 | QCoreApplication::exit(-1); 16 | }, Qt::QueuedConnection); 17 | engine.load(url); 18 | 19 | return app.exec(); 20 | } 21 | -------------------------------------------------------------------------------- /example/main.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | import QtQuick.Window 2.12 3 | import QtPositioning 5.12 4 | import QtLocation 5.12 5 | 6 | Window { 7 | visible: true 8 | width: 640 9 | height: 480 10 | title: qsTr("Hello World") 11 | Component.onCompleted: { 12 | for(var i in m_MapPlugin.availableServiceProviders){ 13 | var it = m_MapPlugin.availableServiceProviders[i] 14 | console.log("Available Service Provider:", it) 15 | } 16 | } 17 | 18 | Map{ 19 | anchors.fill:parent 20 | plugin: Plugin{ 21 | id:m_MapPlugin; 22 | name: "amap"; 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /example/qml.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | main.qml 4 | 5 | 6 | -------------------------------------------------------------------------------- /qgeocodereplyamap.cpp: -------------------------------------------------------------------------------- 1 | #include "qgeocodereplyamap.h" 2 | 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | static QGeoCoordinate constructCoordiante(const QJsonObject &jsonCoord) { 14 | QGeoCoordinate coord(0,0); 15 | coord.setLatitude(jsonCoord.value(QStringLiteral("lat")).toDouble()); 16 | coord.setLongitude(jsonCoord.value(QStringLiteral("lng")).toDouble()); 17 | return coord; 18 | } 19 | 20 | static bool checkAddressType(const QJsonObject &jsonAddress, const QString &type) { 21 | QJsonArray a = jsonAddress.value("types").toArray(); 22 | for (int i = 0; i < a.size(); i++) { 23 | if (a.at(i).toString() == type) 24 | return true; 25 | } 26 | return false; 27 | } 28 | 29 | QGeoCodeReplyAmap::QGeoCodeReplyAmap(QNetworkReply *reply, QObject *parent) 30 | : QGeoCodeReply(parent), m_reply(reply) 31 | { 32 | connect(m_reply, SIGNAL(finished()), this, SLOT(networkReplyFinished())); 33 | connect(m_reply, SIGNAL(error(QNetworkReply::NetworkError)), 34 | this, SLOT(networkReplyError(QNetworkReply::NetworkError))); 35 | 36 | setLimit(1); 37 | setOffset(0); 38 | } 39 | 40 | QGeoCodeReplyAmap::~QGeoCodeReplyAmap() 41 | { 42 | if (m_reply) 43 | m_reply->deleteLater(); 44 | } 45 | 46 | void QGeoCodeReplyAmap::abort() 47 | { 48 | if (!m_reply) 49 | return; 50 | 51 | m_reply->abort(); 52 | 53 | m_reply->deleteLater(); 54 | m_reply = 0; 55 | } 56 | 57 | 58 | void QGeoCodeReplyAmap::networkReplyFinished() 59 | { 60 | if (!m_reply) 61 | return; 62 | 63 | if (m_reply->error() != QNetworkReply::NoError) 64 | return; 65 | 66 | QString status; 67 | 68 | QList locations; 69 | // setError(QGeoCodeReply::ParseError, QStringLiteral("Error parsing OpenRouteService xml response:") + xml.errorString() + " at line: " + xml.lineNumber()); 70 | QJsonDocument document = QJsonDocument::fromJson(m_reply->read(m_reply->bytesAvailable())); 71 | if (document.isObject()) { 72 | QJsonObject object = document.object(); 73 | 74 | status = object.value(QStringLiteral("status")).toString(); 75 | if (status == "OK") { 76 | QJsonArray jsonlocations = object.value(QStringLiteral("results")).toArray(); 77 | qDebug() << "locations:" << jsonlocations.size(); 78 | for(int i = 0; i < jsonlocations.size(); i++) { 79 | QGeoLocation location; 80 | QGeoAddress address; 81 | 82 | QJsonObject o = jsonlocations.at(i).toObject(); 83 | address.setText(o.value("formatted_address").toString()); 84 | QJsonObject ogeometry = o.value("geometry").toObject(); 85 | 86 | location.setCoordinate(constructCoordiante(ogeometry.value("location").toObject())); 87 | 88 | QJsonObject jaddressRanges = ogeometry.value("viewport").toObject(); 89 | if (!jaddressRanges.isEmpty()) { 90 | QGeoRectangle r; 91 | r.setTopRight(constructCoordiante(jaddressRanges.value("northeast").toObject())); 92 | r.setBottomLeft(constructCoordiante(jaddressRanges.value("southwest").toObject())); 93 | #if (QT_VERSION >= QT_VERSION_CHECK(6,0,0)) 94 | location.setBoundingShape(r); 95 | #else 96 | location.setBoundingBox(r); 97 | #endif 98 | 99 | } 100 | 101 | QJsonArray jaddress = o.value("address_components").toArray(); 102 | 103 | QString street_name; 104 | QString street_num; 105 | for(int j = 0; j < jaddress.size(); j++) { 106 | QJsonObject addobj = jaddress.at(j).toObject(); 107 | if (checkAddressType(addobj, "street_number")) 108 | street_num = addobj.value("long_name").toString(); 109 | if (checkAddressType(addobj, "route")) 110 | street_name = addobj.value("long_name").toString(); 111 | if (checkAddressType(addobj, "country")) 112 | address.setCountryCode(addobj.value("short_name").toString()); 113 | if (checkAddressType(addobj, "administrative_area_level_3")) 114 | address.setCity(addobj.value("long_name").toString()); 115 | if (checkAddressType(addobj, "administrative_area_level_2")) 116 | address.setCounty(addobj.value("long_name").toString()); 117 | if (checkAddressType(addobj, "administrative_area_level_1")) 118 | address.setState(addobj.value("long_name").toString()); 119 | if (checkAddressType(addobj, "sublocality")) 120 | address.setDistrict(addobj.value("long_name").toString()); 121 | if (checkAddressType(addobj, "postal_code")) 122 | address.setPostalCode(addobj.value("long_name").toString()); 123 | } 124 | address.setStreet(street_name + (street_num.size() > 0 ? ( ", " + street_num) : "")); 125 | 126 | location.setAddress(address); 127 | 128 | locations.append(location); 129 | } 130 | } 131 | } else { 132 | if (status == "ZERO_RESULTS") 133 | setError(CombinationError, "Geocode was successful but returned no results. This may occur if the geocoder was passed a non-existent address"); 134 | else if (status == "OVER_QUERY_LIMIT") 135 | setError(CommunicationError, "Request quota is over"); 136 | else if (status == "REQUEST_DENIED") 137 | setError(CommunicationError, "Request denied"); 138 | else if (status == "INVALID_REQUEST") 139 | setError(UnsupportedOptionError, "Address, components or latlng is missing"); 140 | else if (status == "UNKNOWN_ERROR") 141 | setError(UnknownError, "Request could not be processed due to a server error. Try again later"); 142 | } 143 | 144 | setLocations(locations); 145 | setFinished(true); 146 | 147 | m_reply->deleteLater(); 148 | m_reply = 0; 149 | } 150 | 151 | void QGeoCodeReplyAmap::networkReplyError(QNetworkReply::NetworkError error) 152 | { 153 | Q_UNUSED(error) 154 | 155 | if (!m_reply) 156 | return; 157 | 158 | setError(QGeoCodeReply::CommunicationError, m_reply->errorString()); 159 | 160 | m_reply->deleteLater(); 161 | m_reply = 0; 162 | } 163 | -------------------------------------------------------------------------------- /qgeocodereplyamap.h: -------------------------------------------------------------------------------- 1 | #ifndef QGEOCODEREPLYAMAP_H 2 | #define QGEOCODEREPLYAMAP_H 3 | 4 | #include 5 | #include 6 | 7 | class QGeoCodeReplyAmap : public QGeoCodeReply 8 | { 9 | Q_OBJECT 10 | 11 | public: 12 | explicit QGeoCodeReplyAmap(QNetworkReply *reply, QObject *parent = 0); 13 | ~QGeoCodeReplyAmap(); 14 | 15 | void abort(); 16 | 17 | private Q_SLOTS: 18 | void networkReplyFinished(); 19 | void networkReplyError(QNetworkReply::NetworkError error); 20 | 21 | private: 22 | QNetworkReply *m_reply; 23 | }; 24 | 25 | #endif // QGEOCODEREPLYORS_H 26 | -------------------------------------------------------------------------------- /qgeocodingmanagerengineamap.cpp: -------------------------------------------------------------------------------- 1 | #include "qgeocodingmanagerengineamap.h" 2 | #include "qgeocodereplyamap.h" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | static QString addressToQuery(const QGeoAddress &address) 16 | { 17 | return address.street() + QStringLiteral(",+") + 18 | address.district() + QStringLiteral(",+") + 19 | address.city() + QStringLiteral(",+") + 20 | address.state() + QStringLiteral(",+") + 21 | address.country(); 22 | } 23 | 24 | static QString coordinateToQuery(const QGeoCoordinate &coordinate) 25 | { 26 | return QString::number(coordinate.latitude()) + QStringLiteral(",") + 27 | QString::number(coordinate.longitude()); 28 | } 29 | 30 | QGeoCodingManagerEngineAmap::QGeoCodingManagerEngineAmap(const QVariantMap ¶meters, 31 | QGeoServiceProvider::Error *error, 32 | QString *errorString) 33 | : QGeoCodingManagerEngine(parameters), m_networkManager(new QNetworkAccessManager(this)) 34 | { 35 | if (parameters.contains(QStringLiteral("amap.useragent"))) 36 | m_userAgent = parameters.value(QStringLiteral("amap.useragent")).toString().toLatin1(); 37 | else 38 | m_userAgent = "Qt Location based application"; 39 | 40 | if(parameters.contains((QStringLiteral("amap.geocode.apikey")))) 41 | m_apiKey = parameters.value(QStringLiteral("amap.geocode.apikey")).toString(); 42 | else 43 | m_apiKey = parameters.value(QStringLiteral("amap.apikey")).toString(); 44 | 45 | m_urlPrefix = QStringLiteral("https://maps.amap.com/maps/api/geocode/json"); 46 | 47 | *error = QGeoServiceProvider::NoError; 48 | errorString->clear(); 49 | } 50 | 51 | QGeoCodingManagerEngineAmap::~QGeoCodingManagerEngineAmap() 52 | { 53 | } 54 | 55 | QGeoCodeReply *QGeoCodingManagerEngineAmap::geocode(const QGeoAddress &address, const QGeoShape &bounds) 56 | { 57 | return geocode(addressToQuery(address), -1, -1, bounds); 58 | } 59 | 60 | QGeoCodeReply *QGeoCodingManagerEngineAmap::geocode(const QString &address, int limit, int offset, const QGeoShape &bounds) 61 | { 62 | Q_UNUSED(offset) 63 | Q_UNUSED(limit) 64 | 65 | QNetworkRequest request; 66 | request.setRawHeader("User-Agent", m_userAgent); 67 | 68 | QUrl url(m_urlPrefix); 69 | QUrlQuery query; 70 | query.addQueryItem(QStringLiteral("address"), address); 71 | query.addQueryItem(QStringLiteral("key"), m_apiKey); 72 | if (bounds.isValid() && !bounds.isEmpty() && bounds.type() != QGeoShape::UnknownType) { 73 | if (bounds.type() == QGeoShape::RectangleType) { 74 | const QGeoRectangle &r = static_cast(bounds); 75 | query.addQueryItem(QStringLiteral("bounds"), 76 | (coordinateToQuery(r.topRight()) + "|" + coordinateToQuery(r.bottomLeft()))); 77 | } 78 | } 79 | url.setQuery(query); 80 | request.setUrl(url); 81 | 82 | QNetworkReply *reply = m_networkManager->get(request); 83 | 84 | QGeoCodeReplyAmap *geocodeReply = new QGeoCodeReplyAmap(reply, this); 85 | 86 | connect(geocodeReply, SIGNAL(finished()), this, SLOT(replyFinished())); 87 | connect(geocodeReply, SIGNAL(error(QGeoCodeReply::Error,QString)), 88 | this, SLOT(replyError(QGeoCodeReply::Error,QString))); 89 | 90 | return geocodeReply; 91 | } 92 | 93 | QGeoCodeReply *QGeoCodingManagerEngineAmap::reverseGeocode(const QGeoCoordinate &coordinate, 94 | const QGeoShape &bounds) 95 | { 96 | Q_UNUSED(bounds) 97 | 98 | QNetworkRequest request; 99 | request.setRawHeader("User-Agent", m_userAgent); 100 | 101 | QUrl url(m_urlPrefix); 102 | QUrlQuery query; 103 | query.addQueryItem(QStringLiteral("latlng"), coordinateToQuery(coordinate)); 104 | query.addQueryItem(QStringLiteral("key"), m_apiKey); 105 | 106 | url.setQuery(query); 107 | request.setUrl(url); 108 | 109 | QNetworkReply *reply = m_networkManager->get(request); 110 | 111 | QGeoCodeReplyAmap *geocodeReply = new QGeoCodeReplyAmap(reply, this); 112 | 113 | connect(geocodeReply, SIGNAL(finished()), this, SLOT(replyFinished())); 114 | connect(geocodeReply, SIGNAL(error(QGeoCodeReply::Error,QString)), 115 | this, SLOT(replyError(QGeoCodeReply::Error,QString))); 116 | 117 | return geocodeReply; 118 | } 119 | 120 | void QGeoCodingManagerEngineAmap::replyFinished() 121 | { 122 | QGeoCodeReply *reply = qobject_cast(sender()); 123 | if (reply) 124 | emit finished(reply); 125 | } 126 | 127 | void QGeoCodingManagerEngineAmap::replyError(QGeoCodeReply::Error errorCode, const QString &errorString) 128 | { 129 | QGeoCodeReply *reply = qobject_cast(sender()); 130 | if (reply){ 131 | #if (QT_VERSION >= QT_VERSION_CHECK(6,0,0)) 132 | Q_EMIT errorOccurred(reply, errorCode, errorString); 133 | #else 134 | Q_EMIT error(reply, errorCode, errorString); 135 | #endif 136 | 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /qgeocodingmanagerengineamap.h: -------------------------------------------------------------------------------- 1 | #ifndef QGEOCODINGMANAGERENGINEAMAP_H 2 | #define QGEOCODINGMANAGERENGINEAMAP_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class QNetworkAccessManager; 9 | 10 | class QGeoCodingManagerEngineAmap : public QGeoCodingManagerEngine 11 | { 12 | Q_OBJECT 13 | 14 | public: 15 | QGeoCodingManagerEngineAmap(const QVariantMap ¶meters, QGeoServiceProvider::Error *error, 16 | QString *errorString); 17 | ~QGeoCodingManagerEngineAmap(); 18 | 19 | QGeoCodeReply *geocode(const QGeoAddress &address, const QGeoShape &bounds) Q_DECL_OVERRIDE; 20 | QGeoCodeReply *geocode(const QString &address, int limit, int offset, 21 | const QGeoShape &bounds) Q_DECL_OVERRIDE; 22 | QGeoCodeReply *reverseGeocode(const QGeoCoordinate &coordinate, 23 | const QGeoShape &bounds) Q_DECL_OVERRIDE; 24 | 25 | private Q_SLOTS: 26 | void replyFinished(); 27 | void replyError(QGeoCodeReply::Error errorCode, const QString &errorString); 28 | 29 | private: 30 | QNetworkAccessManager *m_networkManager; 31 | QByteArray m_userAgent; 32 | QString m_urlPrefix; 33 | QString m_apiKey; 34 | }; 35 | 36 | #endif // QGEOCODINGMANAGERENGINEOrs_H 37 | -------------------------------------------------------------------------------- /qgeoerror_messages.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2015 The Qt Company Ltd. 4 | ** Contact: http://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of the QtLocation module of the Qt Toolkit. 7 | ** 8 | ** $QT_BEGIN_LICENSE:LGPL3$ 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 http://www.qt.io/terms-conditions. For further 15 | ** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free 28 | ** Software Foundation and appearing in the file LICENSE.GPL included in 29 | ** the packaging of this file. Please review the following information to 30 | ** ensure the GNU General Public License version 2.0 requirements will be 31 | ** met: http://www.gnu.org/licenses/gpl-2.0.html. 32 | ** 33 | ** $QT_END_LICENSE$ 34 | ** 35 | ****************************************************************************/ 36 | 37 | #include "qgeoerror_messages.h" 38 | 39 | QT_BEGIN_NAMESPACE 40 | 41 | const char NOKIA_PLUGIN_CONTEXT_NAME[] = "QtLocationQML"; 42 | const char MISSED_CREDENTIALS[] = QT_TRANSLATE_NOOP("QtLocationQML", "Qt Location requires app_id and token parameters.\nPlease register at https://developer.here.com/ to get your personal application credentials."); 43 | const char SAVING_PLACE_NOT_SUPPORTED[] = QT_TRANSLATE_NOOP("QtLocationQML", "Saving places is not supported."); 44 | const char REMOVING_PLACE_NOT_SUPPORTED[] = QT_TRANSLATE_NOOP("QtLocationQML", "Removing places is not supported."); 45 | const char SAVING_CATEGORY_NOT_SUPPORTED[] = QT_TRANSLATE_NOOP("QtLocationQML", "Saving categories is not supported."); 46 | const char REMOVING_CATEGORY_NOT_SUPPORTED[] = QT_TRANSLATE_NOOP("QtLocationQML", "Removing categories is not supported."); 47 | const char PARSE_ERROR[] = QT_TRANSLATE_NOOP("QtLocationQML", "Error parsing response."); 48 | const char NETWORK_ERROR[] = QT_TRANSLATE_NOOP("QtLocationQML", "Network error."); 49 | const char CANCEL_ERROR[] = QT_TRANSLATE_NOOP("QtLocationQML", "Request was canceled."); 50 | const char RESPONSE_NOT_RECOGNIZABLE[] = QT_TRANSLATE_NOOP("QtLocationQML", "The response from the service was not in a recognizable format."); 51 | 52 | QT_END_NAMESPACE 53 | -------------------------------------------------------------------------------- /qgeoerror_messages.h: -------------------------------------------------------------------------------- 1 | 2 | /**************************************************************************** 3 | ** 4 | ** Copyright (C) 2015 The Qt Company Ltd. 5 | ** Contact: http://www.qt.io/licensing/ 6 | ** 7 | ** This file is part of the QtLocation module of the Qt Toolkit. 8 | ** 9 | ** $QT_BEGIN_LICENSE:LGPL3$ 10 | ** Commercial License Usage 11 | ** Licensees holding valid commercial Qt licenses may use this file in 12 | ** accordance with the commercial license agreement provided with the 13 | ** Software or, alternatively, in accordance with the terms contained in 14 | ** a written agreement between you and The Qt Company. For licensing terms 15 | ** and conditions see http://www.qt.io/terms-conditions. For further 16 | ** information use the contact form at http://www.qt.io/contact-us. 17 | ** 18 | ** GNU Lesser General Public License Usage 19 | ** Alternatively, this file may be used under the terms of the GNU Lesser 20 | ** General Public License version 3 as published by the Free Software 21 | ** Foundation and appearing in the file LICENSE.LGPLv3 included in the 22 | ** packaging of this file. Please review the following information to 23 | ** ensure the GNU Lesser General Public License version 3 requirements 24 | ** will be met: https://www.gnu.org/licenses/lgpl.html. 25 | ** 26 | ** GNU General Public License Usage 27 | ** Alternatively, this file may be used under the terms of the GNU 28 | ** General Public License version 2.0 or later as published by the Free 29 | ** Software Foundation and appearing in the file LICENSE.GPL included in 30 | ** the packaging of this file. Please review the following information to 31 | ** ensure the GNU General Public License version 2.0 requirements will be 32 | ** met: http://www.gnu.org/licenses/gpl-2.0.html. 33 | ** 34 | ** $QT_END_LICENSE$ 35 | ** 36 | ****************************************************************************/ 37 | 38 | #ifndef QGEOERROR_MESSAGES_H 39 | #define QGEOERROR_MESSAGES_H 40 | 41 | #include 42 | 43 | QT_BEGIN_NAMESPACE 44 | 45 | extern const char NOKIA_PLUGIN_CONTEXT_NAME[]; 46 | extern const char MISSED_CREDENTIALS[]; 47 | extern const char SAVING_PLACE_NOT_SUPPORTED[]; 48 | extern const char REMOVING_PLACE_NOT_SUPPORTED[]; 49 | extern const char SAVING_CATEGORY_NOT_SUPPORTED[]; 50 | extern const char REMOVING_CATEGORY_NOT_SUPPORTED[]; 51 | extern const char PARSE_ERROR[]; 52 | extern const char NETWORK_ERROR[]; 53 | extern const char CANCEL_ERROR[]; 54 | extern const char RESPONSE_NOT_RECOGNIZABLE[]; 55 | 56 | QT_END_NAMESPACE 57 | 58 | #endif // QGEOERROR_MESSAGES_H 59 | -------------------------------------------------------------------------------- /qgeomapreplyamap.cpp: -------------------------------------------------------------------------------- 1 | #include "qgeomapreplyamap.h" 2 | #include 3 | #include 4 | #include 5 | 6 | QT_BEGIN_NAMESPACE 7 | 8 | QGeoMapReplyAmap::QGeoMapReplyAmap(QNetworkReply *reply, const QGeoTileSpec &spec, QObject *parent) 9 | : QGeoTiledMapReply(spec, parent), 10 | m_reply(reply) 11 | { 12 | connect(m_reply, 13 | SIGNAL(finished()), 14 | this, 15 | SLOT(networkFinished())); 16 | 17 | connect(m_reply, 18 | SIGNAL(error(QNetworkReply::NetworkError)), 19 | this, 20 | SLOT(networkError(QNetworkReply::NetworkError))); 21 | } 22 | 23 | QGeoMapReplyAmap::~QGeoMapReplyAmap() 24 | { 25 | } 26 | 27 | QNetworkReply *QGeoMapReplyAmap::networkReply() const 28 | { 29 | return m_reply; 30 | } 31 | 32 | void QGeoMapReplyAmap::abort() 33 | { 34 | if (!m_reply) 35 | return; 36 | 37 | m_reply->abort(); 38 | } 39 | 40 | void QGeoMapReplyAmap::networkFinished() 41 | { 42 | if (!m_reply) 43 | return; 44 | 45 | if (m_reply->error() != QNetworkReply::NoError) 46 | return; 47 | 48 | setMapImageData(m_reply->readAll()); 49 | const int _mid = tileSpec().mapId(); 50 | if (_mid == 2) 51 | setMapImageFormat("jpeg"); 52 | else 53 | setMapImageFormat("png"); 54 | setFinished(true); 55 | 56 | m_reply->deleteLater(); 57 | m_reply = 0; 58 | } 59 | 60 | void QGeoMapReplyAmap::networkError(QNetworkReply::NetworkError error) 61 | { 62 | Q_UNUSED(error); 63 | if (!m_reply) 64 | return; 65 | 66 | setFinished(true); 67 | setCached(false); 68 | m_reply->deleteLater(); 69 | m_reply = 0; 70 | } 71 | 72 | QT_END_NAMESPACE 73 | -------------------------------------------------------------------------------- /qgeomapreplyamap.h: -------------------------------------------------------------------------------- 1 | #ifndef QGEOMAPREPLYAMAP_H 2 | #define QGEOMAPREPLYAMAP_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | QT_BEGIN_NAMESPACE 10 | 11 | class QGeoMapReplyAmap : public QGeoTiledMapReply 12 | { 13 | Q_OBJECT 14 | 15 | public: 16 | QGeoMapReplyAmap(QNetworkReply *reply, const QGeoTileSpec &spec, QObject *parent = 0); 17 | ~QGeoMapReplyAmap(); 18 | 19 | void abort(); 20 | 21 | QNetworkReply *networkReply() const; 22 | 23 | private Q_SLOTS: 24 | void networkFinished(); 25 | void networkError(QNetworkReply::NetworkError error); 26 | 27 | private: 28 | QPointer m_reply; 29 | }; 30 | 31 | QT_END_NAMESPACE 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /qgeoroutereplyamap.cpp: -------------------------------------------------------------------------------- 1 | #include "qgeoroutereplyamap.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | static QList parsePolyline(const QByteArray &data) 11 | { 12 | QList path; 13 | 14 | bool parsingLatitude = true; 15 | 16 | int shift = 0; 17 | int value = 0; 18 | 19 | QGeoCoordinate coord(0, 0); 20 | 21 | for (int i = 0; i < data.length(); ++i) { 22 | unsigned char c = data.at(i) - 63; 23 | 24 | value |= (c & 0x1f) << shift; 25 | shift += 5; 26 | 27 | // another chunk 28 | if (c & 0x20) 29 | continue; 30 | 31 | int diff = (value & 1) ? ~(value >> 1) : (value >> 1); 32 | 33 | if (parsingLatitude) { 34 | coord.setLatitude(coord.latitude() + (double)diff/1e5); 35 | } else { 36 | coord.setLongitude(coord.longitude() + (double)diff/1e5); 37 | path.append(coord); 38 | } 39 | 40 | parsingLatitude = !parsingLatitude; 41 | 42 | value = 0; 43 | shift = 0; 44 | } 45 | 46 | return path; 47 | } 48 | 49 | static QGeoCoordinate constructCoordiante(const QJsonObject &jsonCoord) { 50 | QGeoCoordinate coord(0,0); 51 | coord.setLatitude(jsonCoord.value(QStringLiteral("lat")).toDouble()); 52 | coord.setLongitude(jsonCoord.value(QStringLiteral("lng")).toDouble()); 53 | return coord; 54 | } 55 | 56 | /* 57 | ferry-train 58 | ferry 59 | */ 60 | 61 | static QGeoManeuver::InstructionDirection gmapsInstructionDirection(const QString &instructionCode) 62 | { 63 | if (instructionCode == "merge" 64 | || instructionCode == "straight") 65 | return QGeoManeuver::DirectionForward; 66 | else if (instructionCode == "turn-slight-right") 67 | return QGeoManeuver::DirectionLightRight; 68 | else if (instructionCode == "turn-right" || 69 | instructionCode == "roundabout-right") 70 | return QGeoManeuver::DirectionRight; 71 | else if (instructionCode == "turn-sharp-right") 72 | return QGeoManeuver::DirectionHardRight; 73 | else if (instructionCode == "turn-sharp-left") 74 | return QGeoManeuver::DirectionHardLeft; 75 | else if (instructionCode == "turn-left" || 76 | instructionCode == "roundabout-left") 77 | return QGeoManeuver::DirectionLeft; 78 | else if (instructionCode == "turn-slight-left") 79 | return QGeoManeuver::DirectionLightLeft; 80 | else if (instructionCode == "uturn-right") 81 | return QGeoManeuver::DirectionUTurnRight; 82 | else if (instructionCode == "uturn-left") 83 | return QGeoManeuver::DirectionUTurnLeft; 84 | else if (instructionCode == "keep-right" || 85 | instructionCode == "ramp-right" || 86 | instructionCode == "fork-right") 87 | return QGeoManeuver::DirectionBearRight; 88 | else if (instructionCode == "keep-left" || 89 | instructionCode == "ramp-left" || 90 | instructionCode == "fork-left") 91 | return QGeoManeuver::DirectionBearLeft; 92 | else 93 | return QGeoManeuver::DirectionForward; 94 | } 95 | 96 | 97 | 98 | 99 | QGeoRouteReplyAmap::QGeoRouteReplyAmap(QNetworkReply *reply, const QGeoRouteRequest &request, 100 | QObject *parent) 101 | : QGeoRouteReply(request, parent), m_reply(reply) 102 | { 103 | connect(m_reply, SIGNAL(finished()), this, SLOT(networkReplyFinished())); 104 | connect(m_reply, SIGNAL(error(QNetworkReply::NetworkError)), 105 | this, SLOT(networkReplyError(QNetworkReply::NetworkError))); 106 | } 107 | 108 | QGeoRouteReplyAmap::~QGeoRouteReplyAmap() 109 | { 110 | if (m_reply) 111 | m_reply->deleteLater(); 112 | } 113 | 114 | void QGeoRouteReplyAmap::abort() 115 | { 116 | if (!m_reply) 117 | return; 118 | 119 | m_reply->abort(); 120 | 121 | m_reply->deleteLater(); 122 | m_reply = 0; 123 | } 124 | 125 | void QGeoRouteReplyAmap::networkReplyFinished() 126 | { 127 | if (!m_reply) 128 | return; 129 | 130 | if (m_reply->error() != QNetworkReply::NoError) { 131 | setError(QGeoRouteReply::CommunicationError, m_reply->errorString()); 132 | m_reply->deleteLater(); 133 | m_reply = 0; 134 | return; 135 | } 136 | QList routes; 137 | 138 | QJsonDocument document = QJsonDocument::fromJson(m_reply->readAll()); 139 | if (document.isObject()) { 140 | QJsonObject object = document.object(); 141 | 142 | QString status = object.value(QStringLiteral("status")).toString(); 143 | QString statusMessage = object.value(QStringLiteral("error_message")).toString(); 144 | 145 | // status code is OK in case of success 146 | // an error occurred when trying to find a route 147 | if (status != "OK") { 148 | setError(QGeoRouteReply::UnknownError, statusMessage); 149 | m_reply->deleteLater(); 150 | m_reply = 0; 151 | return; 152 | } 153 | QJsonArray jsonroutes = object.value(QStringLiteral("routes")).toArray(); 154 | qDebug() << "routes:" << jsonroutes.size(); 155 | for(int i = 0; i < jsonroutes.size(); i++) { 156 | QGeoRoute route; 157 | 158 | QJsonObject o = jsonroutes.at(i).toObject(); 159 | 160 | QList path; 161 | 162 | QJsonObject bo = o.value(QStringLiteral("bounds")).toObject(); 163 | QJsonObject ne_loc_o = bo.value(QStringLiteral("northeast")).toObject(); 164 | QJsonObject sw_loc_o = bo.value(QStringLiteral("southwest")).toObject(); 165 | QGeoRectangle r(constructCoordiante(ne_loc_o), 166 | constructCoordiante(sw_loc_o)); 167 | route.setBounds(r); 168 | 169 | QJsonArray legs = o.value(QStringLiteral("legs")).toArray(); 170 | QGeoRouteSegment firstSegment; 171 | QGeoRouteSegment prevSegment; 172 | for(int l = 0; l < legs.size(); l++) { 173 | QJsonObject lego = legs.at(l).toObject(); 174 | route.setDistance(lego.value("distance").toObject().value("value").toDouble()); 175 | route.setTravelTime(lego.value("duration").toObject().value("value").toInt()); 176 | 177 | QJsonArray steps = lego.value(QStringLiteral("steps")).toArray(); 178 | 179 | for(int s = 0; s < steps.size(); s++) { 180 | QJsonObject stepo = steps.at(s).toObject(); 181 | 182 | QGeoRouteSegment segment; 183 | QGeoManeuver maneuver; 184 | 185 | QString instructionText = stepo.value("html_instructions").toString(); 186 | qreal distance = stepo.value("distance").toObject().value("value").toDouble(); 187 | int segmentTime = stepo.value("duration").toObject().value("value").toInt(); 188 | QByteArray stepGeometry = stepo.value(QStringLiteral("polyline")). 189 | toObject().value(QStringLiteral("points")).toString().toLatin1(); 190 | QList steppath = parsePolyline(stepGeometry); 191 | QString directionCode = stepo.value("maneuver").toString(); 192 | 193 | path += steppath; 194 | 195 | maneuver.setDirection(gmapsInstructionDirection(directionCode)); 196 | maneuver.setDistanceToNextInstruction(distance); 197 | maneuver.setInstructionText(instructionText); 198 | if (steppath.size() > 0) { 199 | maneuver.setPosition(steppath.at(0)); 200 | maneuver.setWaypoint(steppath.at(0)); 201 | } 202 | maneuver.setTimeToNextInstruction(segmentTime); 203 | 204 | segment.setDistance(distance); 205 | segment.setManeuver(maneuver); 206 | segment.setPath(steppath); 207 | segment.setTravelTime(segmentTime); 208 | 209 | if (s == 0 && l == 0) { 210 | firstSegment = segment; 211 | } 212 | if (prevSegment.isValid()) 213 | prevSegment.setNextRouteSegment(segment); 214 | prevSegment = segment; 215 | } 216 | } 217 | route.setFirstRouteSegment(firstSegment); 218 | route.setPath(path); 219 | routes.append(route); 220 | } 221 | 222 | setRoutes(routes); 223 | setFinished(true); 224 | } 225 | else { 226 | setError(QGeoRouteReply::ParseError, QStringLiteral("Error parsing Amap Maps JSON response:")); 227 | } 228 | 229 | m_reply->deleteLater(); 230 | m_reply = 0; 231 | } 232 | 233 | void QGeoRouteReplyAmap::networkReplyError(QNetworkReply::NetworkError error) 234 | { 235 | Q_UNUSED(error) 236 | 237 | if (!m_reply) 238 | return; 239 | 240 | setError(QGeoRouteReply::CommunicationError, m_reply->errorString()); 241 | 242 | m_reply->deleteLater(); 243 | m_reply = 0; 244 | } 245 | -------------------------------------------------------------------------------- /qgeoroutereplyamap.h: -------------------------------------------------------------------------------- 1 | #ifndef QGEOROUTEREPLYORS_H 2 | #define QGEOROUTEREPLYORS_H 3 | 4 | #include 5 | #include 6 | 7 | QT_BEGIN_NAMESPACE 8 | 9 | class QGeoRouteReplyAmap : public QGeoRouteReply 10 | { 11 | Q_OBJECT 12 | 13 | public: 14 | explicit QGeoRouteReplyAmap(QNetworkReply *reply, const QGeoRouteRequest &request, QObject *parent = 0); 15 | ~QGeoRouteReplyAmap(); 16 | 17 | void abort() Q_DECL_OVERRIDE; 18 | 19 | private Q_SLOTS: 20 | void networkReplyFinished(); 21 | void networkReplyError(QNetworkReply::NetworkError error); 22 | 23 | private: 24 | QNetworkReply *m_reply; 25 | }; 26 | 27 | Q_DECLARE_METATYPE(QGeoRouteReplyAmap) 28 | QT_END_NAMESPACE 29 | 30 | #endif // QGEOROUTEREPLYOrs_H 31 | 32 | -------------------------------------------------------------------------------- /qgeoroutingmanagerengineamap.cpp: -------------------------------------------------------------------------------- 1 | #include "qgeoroutingmanagerengineamap.h" 2 | #include "qgeoroutereplyamap.h" 3 | 4 | #include 5 | 6 | #include 7 | 8 | QGeoRoutingManagerEngineAmap::QGeoRoutingManagerEngineAmap(const QVariantMap ¶meters, 9 | QGeoServiceProvider::Error *error, 10 | QString *errorString) 11 | : QGeoRoutingManagerEngine(parameters), m_networkManager(new QNetworkAccessManager(this)) 12 | { 13 | if (parameters.contains(QStringLiteral("amap.useragent"))) 14 | m_userAgent = parameters.value(QStringLiteral("amap.useragent")).toString().toLatin1(); 15 | else 16 | m_userAgent = "Qt Location based application"; 17 | 18 | m_urlPrefix = QStringLiteral("https://maps.amap.com/maps/api/directions/json"); 19 | if(parameters.contains(QStringLiteral("amap.route.apikey"))) 20 | m_apiKey = parameters.value(QStringLiteral("amap.route.apikey")).toString(); 21 | else 22 | m_apiKey = parameters.value(QStringLiteral("amap.apikey")).toString(); 23 | 24 | *error = QGeoServiceProvider::NoError; 25 | errorString->clear(); 26 | } 27 | 28 | QGeoRoutingManagerEngineAmap::~QGeoRoutingManagerEngineAmap() 29 | { 30 | } 31 | 32 | QGeoRouteReply* QGeoRoutingManagerEngineAmap::calculateRoute(const QGeoRouteRequest &request) 33 | { 34 | QNetworkRequest networkRequest; 35 | networkRequest.setRawHeader("User-Agent", m_userAgent); 36 | 37 | if (m_apiKey.isEmpty()) { 38 | QGeoRouteReply *reply = new QGeoRouteReply(QGeoRouteReply::UnsupportedOptionError, "Set amap.route.apikey with amap maps application key, supporting directions", this); 39 | 40 | #if (QT_VERSION >= QT_VERSION_CHECK(6,0,0)) 41 | Q_EMIT errorOccurred(reply, reply->error(), reply->errorString()); 42 | #else 43 | Q_EMIT error(reply, reply->error(), reply->errorString()); 44 | #endif 45 | return reply; 46 | } 47 | 48 | QUrl url(m_urlPrefix); 49 | QUrlQuery query; 50 | QStringList waypoints; 51 | 52 | foreach (const QGeoCoordinate &c, request.waypoints()) { 53 | QString scoord = QString::number(c.latitude()) + QLatin1Char(',') + QString::number(c.longitude()); 54 | if (c == request.waypoints().first()) 55 | query.addQueryItem(QStringLiteral("origin"), scoord); 56 | else if (c == request.waypoints().last()) 57 | query.addQueryItem(QStringLiteral("destination"), scoord); 58 | else 59 | waypoints.append(scoord); 60 | } 61 | if (waypoints.size() > 0) 62 | query.addQueryItem(QStringLiteral("waypoints"), waypoints.join("|")); 63 | 64 | 65 | if (request.travelModes() & QGeoRouteRequest::CarTravel) 66 | query.addQueryItem(QStringLiteral("mode"), QStringLiteral("driving")); 67 | if (request.travelModes() & QGeoRouteRequest::PedestrianTravel) 68 | query.addQueryItem(QStringLiteral("mode"), QStringLiteral("walking")); 69 | if (request.travelModes() & QGeoRouteRequest::BicycleTravel) 70 | query.addQueryItem(QStringLiteral("mode"), QStringLiteral("bicycling")); 71 | if (request.travelModes() & QGeoRouteRequest::PublicTransitTravel) 72 | query.addQueryItem(QStringLiteral("mode"), QStringLiteral("transit")); 73 | 74 | if (request.numberAlternativeRoutes() > 1) 75 | query.addQueryItem(QStringLiteral("alternatives"), QStringLiteral("true")); 76 | 77 | QStringList avoidList; 78 | foreach (QGeoRouteRequest::FeatureType routeFeature, request.featureTypes()) { 79 | QGeoRouteRequest::FeatureWeight weigth = request.featureWeight(routeFeature); 80 | if (weigth == QGeoRouteRequest::AvoidFeatureWeight 81 | || weigth == QGeoRouteRequest::DisallowFeatureWeight) { 82 | if (routeFeature == QGeoRouteRequest::TollFeature) 83 | avoidList.append(QStringLiteral("tolls")); 84 | if (routeFeature == QGeoRouteRequest::HighwayFeature) 85 | avoidList.append(QStringLiteral("highways")); 86 | if (routeFeature == QGeoRouteRequest::FerryFeature) 87 | avoidList.append(QStringLiteral("ferries")); 88 | } 89 | } 90 | if (avoidList.size() > 0) 91 | query.addQueryItem(QStringLiteral("avoid"), avoidList.join("|")); 92 | 93 | 94 | if (QLocale::MetricSystem == measurementSystem()) 95 | query.addQueryItem(QStringLiteral("units"), QStringLiteral("metric")); 96 | else 97 | query.addQueryItem(QStringLiteral("units"), QStringLiteral("imperial")); 98 | 99 | const QLocale loc(locale()); 100 | 101 | if (QLocale::C != loc.language() && QLocale::AnyLanguage != loc.language()) { 102 | query.addQueryItem(QStringLiteral("language"), loc.name()); 103 | } 104 | 105 | query.addQueryItem(QStringLiteral("key"), m_apiKey); 106 | 107 | 108 | url.setQuery(query); 109 | qDebug() << url; 110 | networkRequest.setUrl(url); 111 | 112 | QNetworkReply *reply = m_networkManager->get(networkRequest); 113 | 114 | QGeoRouteReplyAmap *routeReply = new QGeoRouteReplyAmap(reply, request, this); 115 | 116 | connect(routeReply, SIGNAL(finished()), this, SLOT(replyFinished())); 117 | connect(routeReply, SIGNAL(error(QGeoRouteReply::Error,QString)), 118 | this, SLOT(replyError(QGeoRouteReply::Error,QString))); 119 | 120 | return routeReply; 121 | } 122 | 123 | void QGeoRoutingManagerEngineAmap::replyFinished() 124 | { 125 | QGeoRouteReply *reply = qobject_cast(sender()); 126 | if (reply) 127 | emit finished(reply); 128 | } 129 | 130 | void QGeoRoutingManagerEngineAmap::replyError(QGeoRouteReply::Error errorCode, 131 | const QString &errorString) 132 | { 133 | QGeoRouteReply *reply = qobject_cast(sender()); 134 | if (reply){ 135 | #if (QT_VERSION >= QT_VERSION_CHECK(6,0,0)) 136 | Q_EMIT errorOccurred(reply, errorCode, errorString); 137 | #else 138 | Q_EMIT error(reply, errorCode, errorString); 139 | #endif 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /qgeoroutingmanagerengineamap.h: -------------------------------------------------------------------------------- 1 | #ifndef QGEOROUTINGMANAGERENGINEAMAP_H 2 | #define QGEOROUTINGMANAGERENGINEAMAP_H 3 | 4 | #include 5 | #include 6 | 7 | class QNetworkAccessManager; 8 | 9 | class QGeoRoutingManagerEngineAmap : public QGeoRoutingManagerEngine 10 | { 11 | Q_OBJECT 12 | 13 | public: 14 | QGeoRoutingManagerEngineAmap(const QVariantMap ¶meters, 15 | QGeoServiceProvider::Error *error, 16 | QString *errorString); 17 | ~QGeoRoutingManagerEngineAmap(); 18 | 19 | QGeoRouteReply *calculateRoute(const QGeoRouteRequest &request); 20 | 21 | private Q_SLOTS: 22 | void replyFinished(); 23 | void replyError(QGeoRouteReply::Error errorCode, const QString &errorString); 24 | 25 | private: 26 | QNetworkAccessManager *m_networkManager; 27 | QByteArray m_userAgent; 28 | QString m_urlPrefix; 29 | QString m_apiKey; 30 | }; 31 | 32 | #endif // QGEOROUTINGMANAGERENGINEAMAP_H 33 | 34 | -------------------------------------------------------------------------------- /qgeoserviceproviderpluginamap.cpp: -------------------------------------------------------------------------------- 1 | #include "qgeoserviceproviderpluginamap.h" 2 | #include "qgeocodingmanagerengineamap.h" 3 | #include "qgeoroutingmanagerengineamap.h" 4 | #include "qplacemanagerengineamap.h" 5 | #include "qgeotiledmappingmanagerengineamap.h" 6 | 7 | 8 | QGeoCodingManagerEngine *QGeoServiceProviderFactoryAmap::createGeocodingManagerEngine( 9 | const QVariantMap ¶meters, QGeoServiceProvider::Error *error, QString *errorString) const 10 | { 11 | return new QGeoCodingManagerEngineAmap(parameters, error, errorString); 12 | } 13 | 14 | QGeoRoutingManagerEngine *QGeoServiceProviderFactoryAmap::createRoutingManagerEngine( 15 | const QVariantMap ¶meters, QGeoServiceProvider::Error *error, QString *errorString) const 16 | { 17 | return new QGeoRoutingManagerEngineAmap(parameters, error, errorString); 18 | } 19 | 20 | QPlaceManagerEngine *QGeoServiceProviderFactoryAmap::createPlaceManagerEngine( 21 | const QVariantMap ¶meters, QGeoServiceProvider::Error *error, QString *errorString) const 22 | { 23 | return new QPlaceManagerEngineAmap(parameters, error, errorString); 24 | } 25 | 26 | QGeoMappingManagerEngine *QGeoServiceProviderFactoryAmap::createMappingManagerEngine( 27 | const QVariantMap ¶meters, 28 | QGeoServiceProvider::Error *error, 29 | QString *errorString) const 30 | { 31 | return new QGeoTiledMappingManagerEngineAmap(parameters, error, errorString); 32 | } 33 | -------------------------------------------------------------------------------- /qgeoserviceproviderpluginamap.h: -------------------------------------------------------------------------------- 1 | #ifndef QGEOSERVICEPROVIDERAMAP_H 2 | #define QGEOSERVICEPROVIDERAMAP_H 3 | 4 | #include 5 | #include 6 | 7 | class QGeoServiceProviderFactoryAmap: public QObject, public QGeoServiceProviderFactory 8 | { 9 | Q_OBJECT 10 | Q_INTERFACES(QGeoServiceProviderFactory) 11 | #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) 12 | Q_PLUGIN_METADATA(IID "org.qt-project.qt.geoservice.serviceproviderfactory/6.0" 13 | FILE "amap_plugin.json") 14 | #elif 15 | Q_PLUGIN_METADATA(IID "org.qt-project.qt.geoservice.serviceproviderfactory/5.0" 16 | FILE "amap_plugin.json") 17 | #endif 18 | 19 | public: 20 | QGeoCodingManagerEngine *createGeocodingManagerEngine(const QVariantMap ¶meters, 21 | QGeoServiceProvider::Error *error, 22 | QString *errorString) const; 23 | QGeoRoutingManagerEngine *createRoutingManagerEngine(const QVariantMap ¶meters, 24 | QGeoServiceProvider::Error *error, 25 | QString *errorString) const; 26 | QPlaceManagerEngine *createPlaceManagerEngine(const QVariantMap ¶meters, 27 | QGeoServiceProvider::Error *error, 28 | QString *errorString) const; 29 | QGeoMappingManagerEngine *createMappingManagerEngine(const QVariantMap ¶meters, 30 | QGeoServiceProvider::Error *error, 31 | QString *errorString) const; 32 | 33 | }; 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /qgeotiledmapamap.cpp: -------------------------------------------------------------------------------- 1 | #include "qgeotiledmapamap.h" 2 | #include "qgeotiledmappingmanagerengineamap.h" 3 | #if QT_VERSION <= QT_VERSION_CHECK(5,6,0) 4 | #include "QtLocation/private/qgeomapcontroller_p.h" 5 | #endif 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | QT_BEGIN_NAMESPACE 18 | 19 | /*! 20 | Constructs a new tiled map data object, which stores the map data required by 21 | \a geoMap and makes use of the functionality provided by \a engine. 22 | */ 23 | QGeoTiledMapAmap::QGeoTiledMapAmap(QGeoTiledMappingManagerEngineAmap *engine, QObject *parent /*= 0*/) : 24 | QGeoTiledMap(engine, parent), 25 | m_engine(engine) 26 | {} 27 | 28 | QGeoTiledMapAmap::~QGeoTiledMapAmap() {} 29 | 30 | void QGeoTiledMapAmap::evaluateCopyrights(const QSet &visibleTiles) 31 | { 32 | Q_UNUSED(visibleTiles); 33 | } 34 | 35 | QT_END_NAMESPACE 36 | -------------------------------------------------------------------------------- /qgeotiledmapamap.h: -------------------------------------------------------------------------------- 1 | #ifndef QGEOMAPAMAP_H 2 | #define QGEOMAPAMAP_H 3 | 4 | #include "QtLocation/private/qgeotiledmap_p.h" 5 | #include 6 | #include 7 | 8 | QT_BEGIN_NAMESPACE 9 | 10 | class QGeoTiledMappingManagerEngineAmap; 11 | 12 | class QGeoTiledMapAmap: public QGeoTiledMap 13 | { 14 | Q_OBJECT 15 | public: 16 | QGeoTiledMapAmap(QGeoTiledMappingManagerEngineAmap *engine, QObject *parent = 0); 17 | ~QGeoTiledMapAmap(); 18 | 19 | QString getViewCopyright(); 20 | void evaluateCopyrights(const QSet &visibleTiles); 21 | 22 | private: 23 | //QImage m_logo; 24 | QImage m_copyrightsSlab; 25 | QString m_lastCopyrightsString; 26 | QPointer m_engine; 27 | 28 | Q_DISABLE_COPY(QGeoTiledMapAmap) 29 | }; 30 | 31 | QT_END_NAMESPACE 32 | 33 | #endif // QGEOMAPAMAP_H 34 | -------------------------------------------------------------------------------- /qgeotiledmappingmanagerengineamap.cpp: -------------------------------------------------------------------------------- 1 | #include "QtLocation/private/qgeocameracapabilities_p.h" 2 | #include "qgeotiledmappingmanagerengineamap.h" 3 | #include "qgeotiledmapamap.h" 4 | #include "qgeotilefetcheramap.h" 5 | #include "QtLocation/private/qgeotilespec_p.h" 6 | #include "QtLocation/private/qgeofiletilecache_p.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | QT_BEGIN_NAMESPACE 18 | 19 | QGeoTiledMappingManagerEngineAmap::QGeoTiledMappingManagerEngineAmap(const QVariantMap ¶meters, 20 | QGeoServiceProvider::Error *error, 21 | QString *errorString) 22 | : QGeoTiledMappingManagerEngine() 23 | { 24 | Q_UNUSED(error); 25 | Q_UNUSED(errorString); 26 | 27 | QGeoCameraCapabilities capabilities; 28 | capabilities.setMinimumZoomLevel(1.96); 29 | capabilities.setMaximumZoomLevel(20.88); 30 | capabilities.setSupportsBearing(true); 31 | capabilities.setSupportsTilting(true); 32 | capabilities.setMinimumTilt(0); 33 | capabilities.setMaximumTilt(80); 34 | capabilities.setMinimumFieldOfView(20.0); 35 | capabilities.setMaximumFieldOfView(120.0); 36 | capabilities.setOverzoomEnabled(true); 37 | 38 | setCameraCapabilities(capabilities); 39 | 40 | int tile = parameters.value(QStringLiteral("amap.maps.tilesize"), 256).toInt(); 41 | 42 | setTileSize(QSize(tile, tile)); 43 | 44 | QList types; 45 | #if QT_VERSION < QT_VERSION_CHECK(5,9,0) 46 | types << QGeoMapType(QGeoMapType::StreetMap, tr("Road Map"), tr("Normal map view in daylight mode"), false, false, 1); 47 | types << QGeoMapType(QGeoMapType::SatelliteMapDay, tr("Satellite"), tr("Satellite map view in daylight mode"), false, false, 2); 48 | types << QGeoMapType(QGeoMapType::TerrainMap, tr("Terrain"), tr("Terrain map view in daylight mode"), false, false, 3); 49 | types << QGeoMapType(QGeoMapType::HybridMap, tr("Hybrid"), tr("Satellite map view with streets in daylight mode"), false, false, 4); 50 | #elif QT_VERSION < QT_VERSION_CHECK(5,10,0) 51 | types << QGeoMapType(QGeoMapType::StreetMap, tr("Road Map"), tr("Normal map view in daylight mode"), false, false, 1, "amap"); 52 | types << QGeoMapType(QGeoMapType::SatelliteMapDay, tr("Satellite"), tr("Satellite map view in daylight mode"), false, false, 2, "amap"); 53 | types << QGeoMapType(QGeoMapType::TerrainMap, tr("Terrain"), tr("Terrain map view in daylight mode"), false, false, 3, "amap"); 54 | types << QGeoMapType(QGeoMapType::HybridMap, tr("Hybrid"), tr("Satellite map view with streets in daylight mode"), false, false, 4, "amap"); 55 | #else 56 | //QGeoCameraCapabilities cameraCapabilities; 57 | types << QGeoMapType(QGeoMapType::StreetMap, tr("Road Map"), tr("Normal map view in daylight mode"), false,false, 1, "amap", capabilities); 58 | types << QGeoMapType(QGeoMapType::TerrainMap, tr("Terrain"), tr("Terrain map view in daylight mode"), false, false, 2, "amap", capabilities); 59 | types << QGeoMapType(QGeoMapType::SatelliteMapDay, tr("Satellite"), tr("Satellite map view in daylight mode"), false, false, 3, "amap", capabilities); 60 | types << QGeoMapType(QGeoMapType::HybridMap, tr("Hybrid"), tr("Satellite map view with streets in daylight mode"), false, false, 4, "amap", capabilities); 61 | #endif 62 | 63 | setSupportedMapTypes(types); 64 | 65 | QGeoTileFetcherAmap *fetcher = new QGeoTileFetcherAmap(parameters, this, tileSize()); 66 | setTileFetcher(fetcher); 67 | 68 | if (parameters.contains(QStringLiteral("amap.cachefolder"))) 69 | m_cacheDirectory = parameters.value(QStringLiteral("amap.cachefolder")).toString().toLatin1(); 70 | else 71 | m_cacheDirectory = QAbstractGeoTileCache::baseCacheDirectory() + QLatin1String("amap"); 72 | 73 | QAbstractGeoTileCache *tileCache = new QGeoFileTileCache(m_cacheDirectory); 74 | tileCache->setMaxDiskUsage(100 * 1024 * 1024); 75 | setTileCache(tileCache); 76 | 77 | // populateMapSchemes(); 78 | // *error = QGeoServiceProvider::NoError; 79 | // errorString->clear(); 80 | *error = QGeoServiceProvider::NoError; 81 | errorString->clear(); 82 | } 83 | 84 | QGeoTiledMappingManagerEngineAmap::~QGeoTiledMappingManagerEngineAmap() 85 | { 86 | } 87 | 88 | //void QGeoTiledMappingManagerEngineAmap::populateMapSchemes() 89 | //{ 90 | // m_mapSchemes[0] = QStringLiteral("roadmap"); 91 | // m_mapSchemes[1] = QStringLiteral("roadmap"); 92 | // m_mapSchemes[2] = QStringLiteral("satellite"); 93 | // m_mapSchemes[3] = QStringLiteral("terrain"); 94 | // m_mapSchemes[4] = QStringLiteral("hybrid"); 95 | //} 96 | 97 | //QString QGeoTiledMappingManagerEngineAmap::getScheme(int mapId) 98 | //{ 99 | // return m_mapSchemes[mapId]; 100 | //} 101 | 102 | QGeoMap *QGeoTiledMappingManagerEngineAmap::createMap() 103 | { 104 | return new QGeoTiledMapAmap(this); 105 | } 106 | 107 | QT_END_NAMESPACE 108 | 109 | -------------------------------------------------------------------------------- /qgeotiledmappingmanagerengineamap.h: -------------------------------------------------------------------------------- 1 | #ifndef QGEOTILEDMAPPINGMANAGERENGINEAMAP_H 2 | #define QGEOTILEDMAPPINGMANAGERENGINEAMAP_H 3 | 4 | #include "QtLocation/private/qgeotiledmappingmanagerengine_p.h" 5 | #include 6 | #include "QtLocation/private/qgeomaptype_p.h" 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | QT_BEGIN_NAMESPACE 15 | 16 | class QByteArray; 17 | class QGeoTileSpec; 18 | class QGeoNetworkAccessManager; 19 | 20 | class QGeoTiledMappingManagerEngineAmap : public QGeoTiledMappingManagerEngine 21 | { 22 | Q_OBJECT 23 | 24 | public: 25 | QGeoTiledMappingManagerEngineAmap(const QVariantMap ¶meters, 26 | QGeoServiceProvider::Error *error, 27 | QString *errorString); 28 | ~QGeoTiledMappingManagerEngineAmap(); 29 | 30 | virtual QGeoMap *createMap(); 31 | QString getScheme(int mapId); 32 | 33 | private: 34 | void initialize(); 35 | // void populateMapSchemes(); 36 | 37 | // QHash m_mapSchemes; 38 | QString m_cacheDirectory; 39 | }; 40 | 41 | QT_END_NAMESPACE 42 | 43 | #endif // QGEOTILEDMAPPINGMANAGERENGINEAMAP_H 44 | -------------------------------------------------------------------------------- /qgeotilefetcheramap.cpp: -------------------------------------------------------------------------------- 1 | #include "qgeotilefetcheramap.h" 2 | #include "qgeomapreplyamap.h" 3 | #include "qgeotiledmapamap.h" 4 | #include "qgeotiledmappingmanagerengineamap.h" 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #if (QT_VERSION >= QT_VERSION_CHECK(6,0,0)) 18 | #include 19 | #endif 20 | 21 | #include 22 | 23 | #include 24 | 25 | QT_BEGIN_NAMESPACE 26 | 27 | namespace 28 | { 29 | 30 | int _getServerNum(int x, int y, int max) 31 | { 32 | return (x + 2 * y) % max; 33 | } 34 | 35 | } 36 | 37 | QGeoTileFetcherAmap::QGeoTileFetcherAmap(const QVariantMap ¶meters, 38 | QGeoTiledMappingManagerEngineAmap *engine, 39 | const QSize &tileSize) 40 | : QGeoTileFetcher(engine), 41 | m_networkManager(new QNetworkAccessManager(this)), 42 | m_engineAmap(engine), 43 | m_tileSize(tileSize), 44 | _amapVersionRetrieved(false) 45 | { 46 | if(parameters.contains(QStringLiteral("amap.maps.apikey"))) 47 | m_apiKey = parameters.value(QStringLiteral("amap.maps.apikey")).toString(); 48 | else 49 | m_apiKey = parameters.value(QStringLiteral("amap.apikey")).toString(); 50 | m_signature = parameters.value(QStringLiteral("amap.maps.signature")).toString(); 51 | m_client = parameters.value(QStringLiteral("amap.maps.client")).toString(); 52 | m_baseUri = QStringLiteral("http://maps.amap.com/maps/api/staticmap"); 53 | if (parameters.contains(QStringLiteral("amap.useragent"))) 54 | _userAgent = parameters.value(QStringLiteral("amap.useragent")).toString().toLatin1(); 55 | else 56 | _userAgent = ""; 57 | // _userAgent = "Mozilla/5.0 (X11; Linux i586; rv:31.0) Gecko/20100101 Firefox/31.0"; 58 | 59 | QStringList langs = QLocale::system().uiLanguages(); 60 | if (langs.length() > 0) { 61 | _language = langs[0]; 62 | } 63 | 64 | // Amap version strings 65 | _versionAmapMap = "m@338000000"; 66 | _versionAmapSatellite = "198"; 67 | _versionAmapLabels = "h@336"; 68 | _versionAmapTerrain = "t@132,r@338000000"; 69 | _secAmapWord = "Galileo"; 70 | 71 | // _tryCorrectAmapVersions(m_networkManager); 72 | 73 | // netRequest.setRawHeader("Referrer", "https://www.amap.com/maps/preview"); 74 | // netRequest.setRawHeader("Accept", "*/*"); 75 | // netRequest.setRawHeader("User-Agent", _userAgent); 76 | 77 | /* 2017: support new Amap Maps Tile API (yet under development) 78 | You have to be whitelisted to use the Tile API. I can't tell how to get whitelisted. 79 | see https://developers.amap.com/maps/documentation/tile/ 80 | To use the new feature getUrl() and parsing the response has to be adapted. Maybe more than that... 81 | */ 82 | // _getSessionToken(); 83 | } 84 | 85 | QGeoTileFetcherAmap::~QGeoTileFetcherAmap() 86 | { 87 | } 88 | 89 | void QGeoTileFetcherAmap::_getSessionToken() 90 | { 91 | QUrl sessionUrl("https://www.amap.com/tile/v1/createSession"); 92 | 93 | QUrlQuery queryItems; 94 | queryItems.addQueryItem("key", m_apiKey); 95 | queryItems.addQueryItem("mapType", "roadmap"); 96 | queryItems.addQueryItem("language", _language); 97 | queryItems.addQueryItem("region", "de"); 98 | 99 | sessionUrl.setQuery(queryItems); 100 | netRequest.setUrl(sessionUrl); 101 | QNetworkReply *sessionReply = m_networkManager->get(netRequest); 102 | 103 | 104 | if (sessionReply->error() != QNetworkReply::NoError) 105 | return; 106 | 107 | QJsonDocument document = QJsonDocument::fromJson(sessionReply->readAll()); 108 | if (!document.isObject()) 109 | return; 110 | 111 | QJsonObject object = document.object(); 112 | QJsonValue status = object.value(QStringLiteral("session")); 113 | printf(status.toString().toLatin1().data()); 114 | } 115 | 116 | QGeoTiledMapReply *QGeoTileFetcherAmap::getTileImage(const QGeoTileSpec &spec) 117 | { 118 | QString surl = _getURL(spec.mapId(), spec.x(), spec.y(), spec.zoom()); 119 | // qDebug()<<"_getURL:" << surl; 120 | QUrl url(surl); 121 | 122 | netRequest.setUrl(url); 123 | 124 | QNetworkReply *netReply = m_networkManager->get(netRequest); 125 | 126 | QGeoTiledMapReply *mapReply = new QGeoMapReplyAmap(netReply, spec); 127 | 128 | return mapReply; 129 | } 130 | 131 | void QGeoTileFetcherAmap::_getSecAmapWords(int x, int y, QString &sec1, QString &sec2) 132 | { 133 | sec1 = ""; // after &x=... 134 | sec2 = ""; // after &zoom=... 135 | int seclen = ((x * 3) + y) % 8; 136 | sec2 = _secAmapWord.left(seclen); 137 | if (y >= 10000 && y < 100000) { 138 | sec1 = "&s="; 139 | } 140 | } 141 | 142 | QString QGeoTileFetcherAmap::_getURL(int type, int x, int y, int zoom) 143 | { 144 | // qDebug() << "Type:" << type; 145 | switch (type) { 146 | case 0: 147 | case 1: //Road Map 148 | { 149 | QString sec1 = ""; // after &x=... 150 | QString sec2 = ""; // after &zoom=... 151 | _getSecAmapWords(x, y, sec1, sec2); 152 | 153 | return QString("http://wprd03.is.autonavi.com/appmaptile?style=7&x=%1&y=%2&z=%3").arg(x).arg(y).arg(zoom); 154 | } 155 | break; 156 | case 2: //Satallite Map 157 | { 158 | QString sec1 = ""; // after &x=... 159 | QString sec2 = ""; // after &zoom=... 160 | _getSecAmapWords(x, y, sec1, sec2); 161 | return QString("http://wprd03.is.autonavi.com/appmaptile?lang=zh_cn&size=1&style=7&x=%1&y=%2&z=%3").arg(x).arg(y).arg(zoom); 162 | } 163 | break; 164 | case 3: //Terrain Map 165 | { 166 | QString sec1 = ""; // after &x=... 167 | QString sec2 = ""; // after &zoom=... 168 | _getSecAmapWords(x, y, sec1, sec2); 169 | return QString("http://wprd03.is.autonavi.com/appmaptile?lang=zh_cn&size=1&style=6&x=%1&y=%2&z=%3").arg(x).arg(y).arg(zoom); 170 | } 171 | break; 172 | case 4: //Hybrid Map 173 | { 174 | QString sec1 = ""; // after &x=... 175 | QString sec2 = ""; // after &zoom=... 176 | _getSecAmapWords(x, y, sec1, sec2); 177 | return QString("http://wprd03.is.autonavi.com/appmaptile?lang=zh_cn&size=1&style=8&x=%1&y=%2&z=%3").arg(x).arg(y).arg(zoom); 178 | } 179 | break; 180 | } 181 | return ""; 182 | } 183 | 184 | void QGeoTileFetcherAmap::_networkReplyError(QNetworkReply::NetworkError error) 185 | { 186 | qWarning() << "Could not connect to amap maps. Error:" << error; 187 | if(_amapReply) 188 | { 189 | _amapReply->deleteLater(); 190 | _amapReply = NULL; 191 | } 192 | } 193 | 194 | void QGeoTileFetcherAmap::_replyDestroyed() 195 | { 196 | _amapReply = NULL; 197 | } 198 | 199 | void QGeoTileFetcherAmap::_amapVersionCompleted() 200 | { 201 | if (!_amapReply || (_amapReply->error() != QNetworkReply::NoError)) { 202 | qDebug() << "Error collecting Amap maps version info"; 203 | return; 204 | } 205 | QString html = QString(_amapReply->readAll()); 206 | #if (QT_VERSION >= QT_VERSION_CHECK(6,0,0)) 207 | QRegularExpression reg("\"*https?://mt\\D?\\d..*/vt\\?lyrs=m@(\\d*)", QRegularExpression::CaseInsensitiveOption); 208 | QRegularExpressionMatch match = reg.match(html); 209 | if (match.hasMatch()) { 210 | QStringList gc = match.capturedTexts(); 211 | _versionAmapMap = QString("m@%1").arg(gc[1]); 212 | } 213 | reg = QRegularExpression("\"*https?://khm\\D?\\d.amap.com/kh\\?v=(\\d*)", QRegularExpression::CaseInsensitiveOption); 214 | match = reg.match(html); 215 | if (match.hasMatch()) { 216 | QStringList gc = match.capturedTexts(); 217 | _versionAmapSatellite = gc[1]; 218 | } 219 | 220 | reg = QRegularExpression("\"*https?://mt\\D?\\d..*/vt\\?lyrs=t@(\\d*),r@(\\d*)", QRegularExpression::CaseInsensitiveOption); 221 | match = reg.match(html); 222 | if (match.hasMatch()) { 223 | QStringList gc = match.capturedTexts(); 224 | _versionAmapTerrain = QString("t@%1,r@%2").arg(gc[1]).arg(gc[2]); 225 | } 226 | 227 | #else 228 | QRegExp reg("\"*https?://mt\\D?\\d..*/vt\\?lyrs=m@(\\d*)", Qt::CaseInsensitive); 229 | if (reg.indexIn(html) != -1) { 230 | QStringList gc = reg.capturedTexts(); 231 | _versionAmapMap = QString("m@%1").arg(gc[1]); 232 | } 233 | reg = QRegExp("\"*https?://khm\\D?\\d.amap.com/kh\\?v=(\\d*)", Qt::CaseInsensitive); 234 | if (reg.indexIn(html) != -1) { 235 | QStringList gc = reg.capturedTexts(); 236 | _versionAmapSatellite = gc[1]; 237 | } 238 | reg = QRegExp("\"*https?://mt\\D?\\d..*/vt\\?lyrs=t@(\\d*),r@(\\d*)", Qt::CaseInsensitive); 239 | if (reg.indexIn(html) != -1) { 240 | QStringList gc = reg.capturedTexts(); 241 | _versionAmapTerrain = QString("t@%1,r@%2").arg(gc[1]).arg(gc[2]); 242 | } 243 | #endif 244 | _amapReply->deleteLater(); 245 | _amapReply = NULL; 246 | } 247 | 248 | 249 | void QGeoTileFetcherAmap::_tryCorrectAmapVersions(QNetworkAccessManager* networkManager) 250 | { 251 | QMutexLocker locker(&_amapVersionMutex); 252 | if (_amapVersionRetrieved) { 253 | return; 254 | } 255 | _amapVersionRetrieved = true; 256 | if(networkManager) 257 | { 258 | QNetworkRequest qheader; 259 | QNetworkProxy proxy = networkManager->proxy(); 260 | QNetworkProxy tProxy; 261 | tProxy.setType(QNetworkProxy::DefaultProxy); 262 | networkManager->setProxy(tProxy); 263 | QSslConfiguration conf = qheader.sslConfiguration(); conf.setPeerVerifyMode(QSslSocket::VerifyNone); 264 | qheader.setSslConfiguration(conf); 265 | 266 | QString url = "http://maps.amap.com/maps/api/js?v=3.2&sensor=false"; 267 | qheader.setUrl(QUrl(url)); 268 | qheader.setRawHeader("User-Agent", _userAgent); 269 | _amapReply = networkManager->get(qheader); 270 | connect(_amapReply, &QNetworkReply::finished, this, &QGeoTileFetcherAmap::_amapVersionCompleted); 271 | connect(_amapReply, &QNetworkReply::destroyed, this, &QGeoTileFetcherAmap::_replyDestroyed); 272 | #if (QT_VERSION >= QT_VERSION_CHECK(6,0,0)) 273 | connect(_amapReply, &QNetworkReply::errorOccurred, 274 | this, &QGeoTileFetcherAmap::_networkReplyError); 275 | #else 276 | connect(_amapReply, static_cast(&QNetworkReply::error), 277 | this, &QGeoTileFetcherAmap::_networkReplyError); 278 | #endif 279 | networkManager->setProxy(proxy); 280 | } 281 | } 282 | 283 | QT_END_NAMESPACE 284 | -------------------------------------------------------------------------------- /qgeotilefetcheramap.h: -------------------------------------------------------------------------------- 1 | #ifndef QGEOTILEFETCHERAMAP_H 2 | #define QGEOTILEFETCHERAMAP_H 3 | 4 | #include "qgeoserviceproviderpluginamap.h" 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | QT_BEGIN_NAMESPACE 11 | 12 | class QGeoTiledMapReply; 13 | class QGeoTileSpec; 14 | class QGeoTiledMappingManagerEngine; 15 | class QGeoTiledMappingManagerEngineAmap; 16 | class QNetworkAccessManager; 17 | 18 | class QGeoTileFetcherAmap : public QGeoTileFetcher 19 | { 20 | Q_OBJECT 21 | 22 | public: 23 | QGeoTileFetcherAmap(const QVariantMap ¶meters, 24 | QGeoTiledMappingManagerEngineAmap *engine, const QSize &tileSize); 25 | ~QGeoTileFetcherAmap(); 26 | 27 | QGeoTiledMapReply *getTileImage(const QGeoTileSpec &spec); 28 | 29 | private: 30 | QString _getURL(int type, int x, int y, int zoom); 31 | void _tryCorrectAmapVersions(QNetworkAccessManager *networkManager); 32 | void _getSecAmapWords(int x, int y, QString &sec1, QString &sec2); 33 | void _getSessionToken(); 34 | 35 | private slots: 36 | void _networkReplyError(QNetworkReply::NetworkError error); 37 | void _replyDestroyed(); 38 | void _amapVersionCompleted(); 39 | 40 | private: 41 | Q_DISABLE_COPY(QGeoTileFetcherAmap) 42 | 43 | QNetworkAccessManager *m_networkManager; 44 | 45 | QPointer m_engineAmap; 46 | QSize m_tileSize; 47 | QString m_apiKey; 48 | QString m_signature; 49 | QString m_client; 50 | QString m_baseUri; 51 | 52 | int _timeout; 53 | bool _amapVersionRetrieved; 54 | QNetworkReply* _amapReply; 55 | QMutex _amapVersionMutex; 56 | QByteArray _userAgent; 57 | QString _language; 58 | QJsonValue _sessionToken; 59 | 60 | // Amap version strings 61 | QString _versionAmapMap; 62 | QString _versionAmapSatellite; 63 | QString _versionAmapLabels; 64 | QString _versionAmapTerrain; 65 | QString _secAmapWord; 66 | 67 | QNetworkRequest netRequest; 68 | }; 69 | 70 | QT_END_NAMESPACE 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /qplacecategoriesreplyamap.cpp: -------------------------------------------------------------------------------- 1 | #include "qplacecategoriesreplyamap.h" 2 | 3 | QPlaceCategoriesReplyAmap::QPlaceCategoriesReplyAmap(QObject *parent) 4 | : QPlaceReply(parent) 5 | { 6 | } 7 | 8 | QPlaceCategoriesReplyAmap::~QPlaceCategoriesReplyAmap() 9 | { 10 | } 11 | 12 | void QPlaceCategoriesReplyAmap::emitFinished() 13 | { 14 | setFinished(true); 15 | emit finished(); 16 | } 17 | 18 | void QPlaceCategoriesReplyAmap::setError(QPlaceReply::Error errorCode, const QString &errorString) 19 | { 20 | QPlaceReply::setError(errorCode, errorString); 21 | #if (QT_VERSION >= QT_VERSION_CHECK(6,0,0)) 22 | Q_EMIT errorOccurred(errorCode, errorString); 23 | #else 24 | Q_EMIT error(errorCode, errorString); 25 | #endif 26 | } 27 | -------------------------------------------------------------------------------- /qplacecategoriesreplyamap.h: -------------------------------------------------------------------------------- 1 | #ifndef QPLACECATEGORIESREPLYAMAP_H 2 | #define QPLACECATEGORIESREPLYAMAP_H 3 | 4 | #include 5 | 6 | class QPlaceCategoriesReplyAmap : public QPlaceReply 7 | { 8 | Q_OBJECT 9 | 10 | public: 11 | explicit QPlaceCategoriesReplyAmap(QObject *parent = 0); 12 | ~QPlaceCategoriesReplyAmap(); 13 | 14 | void emitFinished(); 15 | void setError(QPlaceReply::Error errorCode, const QString &errorString); 16 | }; 17 | 18 | #endif // QPLACECATEGORIESREPLYAMAP_H 19 | -------------------------------------------------------------------------------- /qplacemanagerengineamap.h: -------------------------------------------------------------------------------- 1 | #ifndef QPLACEMANAGERENGINEAMAP_H 2 | #define QPLACEMANAGERENGINEAMAP_H 3 | 4 | #include 5 | #include 6 | 7 | class QNetworkAccessManager; 8 | class QNetworkReply; 9 | class QPlaceCategoriesReplyAmap; 10 | 11 | class QPlaceManagerEngineAmap : public QPlaceManagerEngine 12 | { 13 | Q_OBJECT 14 | 15 | public: 16 | QPlaceManagerEngineAmap(const QVariantMap ¶meters, QGeoServiceProvider::Error *error, 17 | QString *errorString); 18 | ~QPlaceManagerEngineAmap(); 19 | 20 | QPlaceSearchReply *search(const QPlaceSearchRequest &request) Q_DECL_OVERRIDE; 21 | QPlaceSearchSuggestionReply *searchSuggestions(const QPlaceSearchRequest &request) Q_DECL_OVERRIDE; 22 | 23 | QPlaceReply *initializeCategories() Q_DECL_OVERRIDE; 24 | QString parentCategoryId(const QString &categoryId) const Q_DECL_OVERRIDE; 25 | QStringList childCategoryIds(const QString &categoryId) const Q_DECL_OVERRIDE; 26 | QPlaceCategory category(const QString &categoryId) const Q_DECL_OVERRIDE; 27 | 28 | QList childCategories(const QString &parentId) const Q_DECL_OVERRIDE; 29 | 30 | QList locales() const Q_DECL_OVERRIDE; 31 | void setLocales(const QList &locales) Q_DECL_OVERRIDE; 32 | 33 | private: 34 | QNetworkReply *sendRequest(const QUrl &url); 35 | 36 | private slots: 37 | void categoryReplyFinished(); 38 | void categoryReplyError(); 39 | void replyFinished(); 40 | void replyError(QPlaceReply::Error errorCode, const QString &errorString); 41 | 42 | private: 43 | void fetchNextCategoryLocale(); 44 | 45 | QNetworkAccessManager *m_networkManager; 46 | QByteArray m_userAgent; 47 | QString m_urlPrefix; 48 | QList m_locales; 49 | QString m_apiKey; 50 | 51 | QNetworkReply *m_categoriesReply; 52 | QList m_pendingCategoriesReply; 53 | QHash m_categories; 54 | QHash m_subcategories; 55 | 56 | QList m_categoryLocales; 57 | }; 58 | 59 | #endif // QPLACEMANAGERENGINEAMAP_H 60 | -------------------------------------------------------------------------------- /qplacemanagerengineamp.cpp: -------------------------------------------------------------------------------- 1 | #include "qplacemanagerengineamap.h" 2 | #include "qplacesearchreplyamap.h" 3 | #include "qplacecategoriesreplyamap.h" 4 | #include "qplacesearchrequest.h" 5 | #include "qplacesearchsuggestionreplyimpl.h" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include 19 | 20 | namespace 21 | { 22 | QString SpecialPhrasesBaseUrl = QStringLiteral("http://wiki.openstreetmap.org/wiki/Special:Export/Nominatim/Special_Phrases/"); 23 | 24 | QString nameForTagKey(const QString &tagKey) 25 | { 26 | if (tagKey == QLatin1String("aeroway")) 27 | return QPlaceManagerEngineAmap::tr("Aeroway"); 28 | else if (tagKey == QLatin1String("amenity")) 29 | return QPlaceManagerEngineAmap::tr("Amenity"); 30 | else if (tagKey == QLatin1String("building")) 31 | return QPlaceManagerEngineAmap::tr("Building"); 32 | else if (tagKey == QLatin1String("highway")) 33 | return QPlaceManagerEngineAmap::tr("Highway"); 34 | else if (tagKey == QLatin1String("historic")) 35 | return QPlaceManagerEngineAmap::tr("Historic"); 36 | else if (tagKey == QLatin1String("landuse")) 37 | return QPlaceManagerEngineAmap::tr("Land use"); 38 | else if (tagKey == QLatin1String("leisure")) 39 | return QPlaceManagerEngineAmap::tr("Leisure"); 40 | else if (tagKey == QLatin1String("man_made")) 41 | return QPlaceManagerEngineAmap::tr("Man made"); 42 | else if (tagKey == QLatin1String("natural")) 43 | return QPlaceManagerEngineAmap::tr("Natural"); 44 | else if (tagKey == QLatin1String("place")) 45 | return QPlaceManagerEngineAmap::tr("Place"); 46 | else if (tagKey == QLatin1String("railway")) 47 | return QPlaceManagerEngineAmap::tr("Railway"); 48 | else if (tagKey == QLatin1String("shop")) 49 | return QPlaceManagerEngineAmap::tr("Shop"); 50 | else if (tagKey == QLatin1String("tourism")) 51 | return QPlaceManagerEngineAmap::tr("Tourism"); 52 | else if (tagKey == QLatin1String("waterway")) 53 | return QPlaceManagerEngineAmap::tr("Waterway"); 54 | else 55 | return tagKey; 56 | } 57 | 58 | } 59 | 60 | 61 | static bool addAtForBoundingArea(const QGeoShape &area, 62 | QUrlQuery *queryItems) 63 | { 64 | QGeoCoordinate center = area.center(); 65 | if (!center.isValid()) 66 | return false; 67 | 68 | queryItems->addQueryItem(QStringLiteral("location"), 69 | QString::number(center.latitude()) + 70 | QLatin1Char(',') + 71 | QString::number(center.longitude())); 72 | // for amap maps the shape has to be a circle 73 | QGeoCircle* cirle = new QGeoCircle(area); 74 | if(cirle != NULL) 75 | { 76 | qreal radiusCorrected = cirle->radius(); 77 | if(radiusCorrected < 1) 78 | radiusCorrected = 1; 79 | queryItems->addQueryItem(QStringLiteral("radius"), 80 | QString::number(radiusCorrected)); 81 | } 82 | return true; 83 | } 84 | 85 | QPlaceManagerEngineAmap::QPlaceManagerEngineAmap(const QVariantMap ¶meters, 86 | QGeoServiceProvider::Error *error, 87 | QString *errorString) 88 | : QPlaceManagerEngine(parameters), m_networkManager(new QNetworkAccessManager(this)), 89 | m_categoriesReply(0) 90 | { 91 | // if (parameters.contains(QStringLiteral("ors.useragent"))) 92 | // m_userAgent = parameters.value(QStringLiteral("ors.useragent")).toString().toLatin1(); 93 | // else 94 | // m_userAgent = "Qt Location based application"; 95 | 96 | if (parameters.contains(QStringLiteral("amap.places.apikey"))) 97 | m_apiKey = parameters.value(QStringLiteral("amap.places.apikey")).toString().toLatin1(); 98 | else 99 | m_apiKey = parameters.value(QStringLiteral("amap.apikey")).toString().toLatin1(); 100 | 101 | // if (parameters.contains(QStringLiteral("Ors.places.host"))) 102 | // m_urlPrefix = parameters.value(QStringLiteral("Ors.places.host")).toString(); 103 | // else 104 | m_urlPrefix = QStringLiteral("https://maps.amap.com/maps/api/place"); 105 | 106 | *error = QGeoServiceProvider::NoError; 107 | errorString->clear(); 108 | } 109 | 110 | QPlaceManagerEngineAmap::~QPlaceManagerEngineAmap() 111 | { 112 | } 113 | 114 | QPlaceSearchReply *QPlaceManagerEngineAmap::search(const QPlaceSearchRequest &request) 115 | { 116 | bool unsupported = false; 117 | 118 | // Only public visibility supported 119 | 120 | unsupported |= request.visibilityScope() != QLocation::UnspecifiedVisibility && 121 | request.visibilityScope() != QLocation::PublicVisibility; 122 | unsupported |= request.searchTerm().isEmpty() && request.categories().isEmpty(); 123 | 124 | if (unsupported) 125 | return QPlaceManagerEngine::search(request); 126 | 127 | QUrlQuery queryItems; 128 | 129 | queryItems.addQueryItem(QStringLiteral("format"), QStringLiteral("jsonv2")); 130 | 131 | //queryItems.addQueryItem(QStringLiteral("accept-language"), QStringLiteral("en")); 132 | 133 | QGeoRectangle boundingBox; 134 | QGeoShape searchArea = request.searchArea(); 135 | switch (searchArea.type()) { 136 | case QGeoShape::CircleType: { 137 | QGeoCircle c(searchArea); 138 | qreal radius = c.radius(); 139 | if (radius < 0) 140 | radius = 50000; 141 | 142 | boundingBox = QGeoRectangle(c.center().atDistanceAndAzimuth(radius, -45), 143 | c.center().atDistanceAndAzimuth(radius, 135)); 144 | break; 145 | } 146 | case QGeoShape::RectangleType: 147 | boundingBox = searchArea; 148 | break; 149 | default: 150 | ; 151 | } 152 | 153 | if (!boundingBox.isEmpty()) { 154 | queryItems.addQueryItem(QStringLiteral("bounded"), QStringLiteral("1")); 155 | QString coordinates; 156 | coordinates = QString::number(boundingBox.topLeft().longitude()) + QLatin1Char(',') + 157 | QString::number(boundingBox.topLeft().latitude()) + QLatin1Char(',') + 158 | QString::number(boundingBox.bottomRight().longitude()) + QLatin1Char(',') + 159 | QString::number(boundingBox.bottomRight().latitude()); 160 | queryItems.addQueryItem(QStringLiteral("viewbox"), coordinates); 161 | } 162 | 163 | QStringList queryParts; 164 | if (!request.searchTerm().isEmpty()) 165 | queryParts.append(request.searchTerm()); 166 | 167 | foreach (const QPlaceCategory &category, request.categories()) { 168 | QString id = category.categoryId(); 169 | int index = id.indexOf(QLatin1Char('=')); 170 | if (index != -1) 171 | id = id.mid(index+1); 172 | queryParts.append(QLatin1Char('[') + id + QLatin1Char(']')); 173 | } 174 | 175 | queryItems.addQueryItem(QStringLiteral("q"), queryParts.join(QLatin1Char('+'))); 176 | 177 | QVariantMap parameters = request.searchContext().toMap(); 178 | 179 | QStringList placeIds = parameters.value(QStringLiteral("ExcludePlaceIds")).toStringList(); 180 | if (!placeIds.isEmpty()) 181 | queryItems.addQueryItem(QStringLiteral("exclude_place_ids"), placeIds.join(QLatin1Char(','))); 182 | 183 | queryItems.addQueryItem(QStringLiteral("addressdetails"), QStringLiteral("1")); 184 | 185 | QUrl requestUrl(m_urlPrefix); 186 | requestUrl.setQuery(queryItems); 187 | 188 | QNetworkReply *networkReply = m_networkManager->get(QNetworkRequest(requestUrl)); 189 | 190 | QPlaceSearchReplyAmap *reply = new QPlaceSearchReplyAmap(request, networkReply, this); 191 | connect(reply, SIGNAL(finished()), this, SLOT(replyFinished())); 192 | connect(reply, SIGNAL(error(QPlaceReply::Error,QString)), 193 | this, SLOT(replyError(QPlaceReply::Error,QString))); 194 | 195 | return reply; 196 | } 197 | 198 | QPlaceSearchSuggestionReply *QPlaceManagerEngineAmap::searchSuggestions(const QPlaceSearchRequest &query) 199 | { 200 | bool unsupported = false; 201 | 202 | unsupported |= query.visibilityScope() != QLocation::UnspecifiedVisibility && 203 | query.visibilityScope() != QLocation::PublicVisibility; 204 | 205 | unsupported |= !query.categories().isEmpty(); 206 | unsupported |= !query.recommendationId().isEmpty(); 207 | 208 | if (unsupported) { 209 | QPlaceSearchSuggestionReplyImpl *reply = new QPlaceSearchSuggestionReplyImpl(0, this); 210 | connect(reply, SIGNAL(finished()), this, SLOT(replyFinished())); 211 | connect(reply, SIGNAL(error(QPlaceReply::Error,QString)), 212 | this, SLOT(replyError(QPlaceReply::Error,QString))); 213 | QMetaObject::invokeMethod(reply, "setError", Qt::QueuedConnection, 214 | Q_ARG(QPlaceReply::Error, QPlaceReply::BadArgumentError), 215 | Q_ARG(QString, "Unsupported search request options specified.")); 216 | return reply; 217 | } 218 | 219 | QUrl requestUrl(m_urlPrefix + QStringLiteral("/autocomplete/json")); 220 | 221 | QUrlQuery queryItems; 222 | 223 | queryItems.addQueryItem(QStringLiteral("input"), query.searchTerm()); 224 | 225 | if (!addAtForBoundingArea(query.searchArea(), &queryItems)) { 226 | QPlaceSearchSuggestionReplyImpl *reply = new QPlaceSearchSuggestionReplyImpl(0, this); 227 | connect(reply, SIGNAL(finished()), this, SLOT(replyFinished())); 228 | connect(reply, SIGNAL(error(QPlaceReply::Error,QString)), 229 | this, SLOT(replyError(QPlaceReply::Error,QString))); 230 | QMetaObject::invokeMethod(reply, "setError", Qt::QueuedConnection, 231 | Q_ARG(QPlaceReply::Error, QPlaceReply::BadArgumentError), 232 | Q_ARG(QString, "Invalid search area provided")); 233 | return reply; 234 | } 235 | 236 | requestUrl.setQuery(queryItems); 237 | 238 | QNetworkReply *networkReply = sendRequest(requestUrl); 239 | 240 | QPlaceSearchSuggestionReplyImpl *reply = new QPlaceSearchSuggestionReplyImpl(networkReply, this); 241 | connect(reply, SIGNAL(finished()), this, SLOT(replyFinished())); 242 | connect(reply, SIGNAL(error(QPlaceReply::Error,QString)), 243 | this, SLOT(replyError(QPlaceReply::Error,QString))); 244 | 245 | return reply; 246 | } 247 | 248 | QPlaceReply *QPlaceManagerEngineAmap::initializeCategories() 249 | { 250 | // Only fetch categories once 251 | if (m_categories.isEmpty() && !m_categoriesReply) { 252 | m_categoryLocales = m_locales; 253 | m_categoryLocales.append(QLocale(QLocale::English)); 254 | fetchNextCategoryLocale(); 255 | } 256 | 257 | QPlaceCategoriesReplyAmap *reply = new QPlaceCategoriesReplyAmap(this); 258 | connect(reply, SIGNAL(finished()), this, SLOT(replyFinished())); 259 | connect(reply, SIGNAL(error(QPlaceReply::Error,QString)), 260 | this, SLOT(replyError(QPlaceReply::Error,QString))); 261 | 262 | // TODO delayed finished() emission 263 | if (!m_categories.isEmpty()) 264 | reply->emitFinished(); 265 | 266 | m_pendingCategoriesReply.append(reply); 267 | return reply; 268 | } 269 | 270 | QString QPlaceManagerEngineAmap::parentCategoryId(const QString &categoryId) const 271 | { 272 | Q_UNUSED(categoryId) 273 | 274 | // Only a two category levels 275 | return QString(); 276 | } 277 | 278 | QStringList QPlaceManagerEngineAmap::childCategoryIds(const QString &categoryId) const 279 | { 280 | return m_subcategories.value(categoryId); 281 | } 282 | 283 | QPlaceCategory QPlaceManagerEngineAmap::category(const QString &categoryId) const 284 | { 285 | return m_categories.value(categoryId); 286 | } 287 | 288 | QList QPlaceManagerEngineAmap::childCategories(const QString &parentId) const 289 | { 290 | QList categories; 291 | foreach (const QString &id, m_subcategories.value(parentId)) 292 | categories.append(m_categories.value(id)); 293 | return categories; 294 | } 295 | 296 | QList QPlaceManagerEngineAmap::locales() const 297 | { 298 | return m_locales; 299 | } 300 | 301 | void QPlaceManagerEngineAmap::setLocales(const QList &locales) 302 | { 303 | m_locales = locales; 304 | } 305 | 306 | void QPlaceManagerEngineAmap::categoryReplyFinished() 307 | { 308 | QNetworkReply *reply = qobject_cast(sender()); 309 | if (!reply) 310 | return; 311 | 312 | reply->deleteLater(); 313 | 314 | QXmlStreamReader parser(reply); 315 | while (!parser.atEnd() && parser.readNextStartElement()) { 316 | if (parser.name() == QLatin1String("mediawiki")) 317 | continue; 318 | if (parser.name() == QLatin1String("page")) 319 | continue; 320 | if (parser.name() == QLatin1String("revision")) 321 | continue; 322 | if (parser.name() == QLatin1String("text")) { 323 | // parse 324 | QString page = parser.readElementText(); 325 | QRegularExpression regex(QStringLiteral("\\| ([^|]+) \\|\\| ([^|]+) \\|\\| ([^|]+) \\|\\| ([^|]+) \\|\\| ([\\-YN])")); 326 | QRegularExpressionMatchIterator i = regex.globalMatch(page); 327 | while (i.hasNext()) { 328 | QRegularExpressionMatch match = i.next(); 329 | #if (QT_VERSION >= QT_VERSION_CHECK(6,0,0)) 330 | QString name = match.captured(1); 331 | QString tagKey = match.captured(2); 332 | QString tagValue = match.captured(3); 333 | QString op = match.captured(4); 334 | QString plural = match.captured(5); 335 | #else 336 | QString name = match.capturedRef(1).toString(); 337 | QString tagKey = match.capturedRef(2).toString(); 338 | QString tagValue = match.capturedRef(3).toString(); 339 | QString op = match.capturedRef(4).toString(); 340 | QString plural = match.capturedRef(5).toString(); 341 | #endif 342 | 343 | // Only interested in any operator plural forms 344 | if (op != QLatin1String("-") || plural != QLatin1String("Y")) 345 | continue; 346 | 347 | if (!m_categories.contains(tagKey)) { 348 | QPlaceCategory category; 349 | category.setCategoryId(tagKey); 350 | category.setName(nameForTagKey(tagKey)); 351 | m_categories.insert(category.categoryId(), category); 352 | m_subcategories[QString()].append(tagKey); 353 | emit categoryAdded(category, QString()); 354 | } 355 | 356 | QPlaceCategory category; 357 | category.setCategoryId(tagKey + QLatin1Char('=') + tagValue); 358 | category.setName(name); 359 | 360 | if (!m_categories.contains(category.categoryId())) { 361 | m_categories.insert(category.categoryId(), category); 362 | m_subcategories[tagKey].append(category.categoryId()); 363 | emit categoryAdded(category, tagKey); 364 | } 365 | } 366 | } 367 | 368 | parser.skipCurrentElement(); 369 | } 370 | 371 | if (m_categories.isEmpty() && !m_categoryLocales.isEmpty()) { 372 | fetchNextCategoryLocale(); 373 | return; 374 | } else { 375 | m_categoryLocales.clear(); 376 | } 377 | 378 | foreach (QPlaceCategoriesReplyAmap *reply, m_pendingCategoriesReply) 379 | reply->emitFinished(); 380 | m_pendingCategoriesReply.clear(); 381 | } 382 | 383 | void QPlaceManagerEngineAmap::categoryReplyError() 384 | { 385 | foreach (QPlaceCategoriesReplyAmap *reply, m_pendingCategoriesReply) 386 | reply->setError(QPlaceReply::CommunicationError, tr("Network request error")); 387 | } 388 | 389 | void QPlaceManagerEngineAmap::replyFinished() 390 | { 391 | QPlaceReply *reply = qobject_cast(sender()); 392 | if (reply) 393 | emit finished(reply); 394 | } 395 | 396 | void QPlaceManagerEngineAmap::replyError(QPlaceReply::Error errorCode, const QString &errorString) 397 | { 398 | QPlaceReply *reply = qobject_cast(sender()); 399 | if (reply){ 400 | #if (QT_VERSION >= QT_VERSION_CHECK(6,0,0)) 401 | Q_EMIT errorOccurred(reply, errorCode, errorString); 402 | #else 403 | Q_EMIT error(reply, errorCode, errorString); 404 | #endif 405 | } 406 | } 407 | 408 | void QPlaceManagerEngineAmap::fetchNextCategoryLocale() 409 | { 410 | if (m_categoryLocales.isEmpty()) { 411 | qWarning("No locales specified to fetch categories for"); 412 | return; 413 | } 414 | 415 | QLocale locale = m_categoryLocales.takeFirst(); 416 | 417 | // FIXME: Categories should be cached. 418 | QUrl requestUrl = QUrl(SpecialPhrasesBaseUrl + locale.name().left(2).toUpper()); 419 | 420 | m_categoriesReply = m_networkManager->get(QNetworkRequest(requestUrl)); 421 | connect(m_categoriesReply, SIGNAL(finished()), this, SLOT(categoryReplyFinished())); 422 | connect(m_categoriesReply, SIGNAL(error(QNetworkReply::NetworkError)), 423 | this, SLOT(categoryReplyError())); 424 | } 425 | 426 | 427 | QNetworkReply *QPlaceManagerEngineAmap::sendRequest(const QUrl &url) 428 | { 429 | QUrlQuery queryItems(url); 430 | queryItems.addQueryItem(QStringLiteral("key"), m_apiKey); 431 | 432 | QUrl requestUrl = url; 433 | requestUrl.setQuery(queryItems); 434 | 435 | QNetworkRequest request; 436 | request.setUrl(requestUrl); 437 | 438 | request.setRawHeader("Accept", "application/json"); 439 | // request.setRawHeader("Accept-Language", createLanguageString()); 440 | 441 | return m_networkManager->get(request); 442 | } 443 | -------------------------------------------------------------------------------- /qplacesearchreplyamap.cpp: -------------------------------------------------------------------------------- 1 | #include "qplacesearchreplyamap.h" 2 | #include "qplacemanagerengineamap.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | QPlaceSearchReplyAmap::QPlaceSearchReplyAmap(const QPlaceSearchRequest &request, 17 | QNetworkReply *reply, QPlaceManagerEngineAmap *parent) 18 | : QPlaceSearchReply(parent), m_reply(reply) 19 | { 20 | Q_ASSERT(parent); 21 | 22 | setRequest(request); 23 | 24 | if (!m_reply) 25 | return; 26 | 27 | m_reply->setParent(this); 28 | connect(m_reply, SIGNAL(finished()), this, SLOT(replyFinished())); 29 | } 30 | 31 | QPlaceSearchReplyAmap::~QPlaceSearchReplyAmap() 32 | { 33 | } 34 | 35 | void QPlaceSearchReplyAmap::abort() 36 | { 37 | if (m_reply) 38 | m_reply->abort(); 39 | } 40 | 41 | void QPlaceSearchReplyAmap::setError(QPlaceReply::Error errorCode, const QString &errorString) 42 | { 43 | QPlaceReply::setError(errorCode, errorString); 44 | 45 | #if (QT_VERSION >= QT_VERSION_CHECK(6,0,0)) 46 | Q_EMIT errorOccurred(errorCode, errorString); 47 | #else 48 | Q_EMIT error(errorCode, errorString); 49 | #endif 50 | setFinished(true); 51 | emit finished(); 52 | } 53 | 54 | static QGeoRectangle parseBoundingBox(const QJsonArray &coordinates) 55 | { 56 | if (coordinates.count() != 4) 57 | return QGeoRectangle(); 58 | 59 | double bottom = coordinates.at(0).toString().toDouble(); 60 | double top = coordinates.at(1).toString().toDouble(); 61 | double left = coordinates.at(2).toString().toDouble(); 62 | double right = coordinates.at(3).toString().toDouble(); 63 | 64 | return QGeoRectangle(QGeoCoordinate(top, left), QGeoCoordinate(bottom, right)); 65 | } 66 | 67 | void QPlaceSearchReplyAmap::replyFinished() 68 | { 69 | QNetworkReply *reply = m_reply; 70 | m_reply->deleteLater(); 71 | m_reply = 0; 72 | 73 | if (reply->error() != QNetworkReply::NoError) { 74 | setError(CommunicationError, tr("Communication error")); 75 | return; 76 | } 77 | 78 | QJsonDocument document = QJsonDocument::fromJson(reply->readAll()); 79 | if (!document.isArray()) { 80 | setError(ParseError, tr("Response parse error")); 81 | return; 82 | } 83 | 84 | QJsonArray resultsArray = document.array(); 85 | 86 | QGeoCoordinate searchCenter = request().searchArea().center(); 87 | 88 | QStringList placeIds; 89 | 90 | QList results; 91 | for (int i = 0; i < resultsArray.count(); ++i) { 92 | QJsonObject item = resultsArray.at(i).toObject(); 93 | QPlaceResult pr = parsePlaceResult(item); 94 | pr.setDistance(searchCenter.distanceTo(pr.place().location().coordinate())); 95 | placeIds.append(pr.place().placeId()); 96 | results.append(pr); 97 | } 98 | 99 | QVariantMap searchContext = request().searchContext().toMap(); 100 | QStringList excludePlaceIds = 101 | searchContext.value(QStringLiteral("ExcludePlaceIds")).toStringList(); 102 | 103 | if (!excludePlaceIds.isEmpty()) { 104 | QPlaceSearchRequest r = request(); 105 | QVariantMap parameters = searchContext; 106 | 107 | QStringList epi = excludePlaceIds; 108 | epi.removeLast(); 109 | 110 | parameters.insert(QStringLiteral("ExcludePlaceIds"), epi); 111 | r.setSearchContext(parameters); 112 | setPreviousPageRequest(r); 113 | } 114 | 115 | if (!placeIds.isEmpty()) { 116 | QPlaceSearchRequest r = request(); 117 | QVariantMap parameters = searchContext; 118 | 119 | QStringList epi = excludePlaceIds; 120 | epi.append(placeIds.join(QLatin1Char(','))); 121 | 122 | parameters.insert(QStringLiteral("ExcludePlaceIds"), epi); 123 | r.setSearchContext(parameters); 124 | setNextPageRequest(r); 125 | } 126 | 127 | setResults(results); 128 | 129 | setFinished(true); 130 | emit finished(); 131 | } 132 | 133 | QPlaceResult QPlaceSearchReplyAmap::parsePlaceResult(const QJsonObject &item) const 134 | { 135 | QPlace place; 136 | 137 | QGeoCoordinate coordinate = QGeoCoordinate(item.value(QStringLiteral("lat")).toString().toDouble(), 138 | item.value(QStringLiteral("lon")).toString().toDouble()); 139 | 140 | //const QString placeRank = item.value(QStringLiteral("place_rank")).toString(); 141 | //const QString category = item.value(QStringLiteral("category")).toString(); 142 | const QString type = item.value(QStringLiteral("type")).toString(); 143 | //double importance = item.value(QStringLiteral("importance")).toDouble(); 144 | 145 | place.setAttribution(item.value(QStringLiteral("licence")).toString()); 146 | place.setPlaceId(item.value(QStringLiteral("place_id")).toString()); 147 | 148 | QVariantMap iconParameters; 149 | iconParameters.insert(QPlaceIcon::SingleUrl, 150 | QUrl(item.value(QStringLiteral("icon")).toString())); 151 | QPlaceIcon icon; 152 | icon.setParameters(iconParameters); 153 | place.setIcon(icon); 154 | 155 | QJsonObject addressDetails = item.value(QStringLiteral("address")).toObject(); 156 | 157 | const QString title = addressDetails.value(type).toString(); 158 | 159 | place.setName(title); 160 | 161 | QGeoAddress address; 162 | address.setCity(addressDetails.value(QStringLiteral("city")).toString()); 163 | address.setCountry(addressDetails.value(QStringLiteral("country")).toString()); 164 | // FIXME: country_code is alpha-2 setCountryCode takes alpha-3 165 | //address.setCountryCode(addressDetails.value(QStringLiteral("country_code")).toString()); 166 | address.setPostalCode(addressDetails.value(QStringLiteral("postcode")).toString()); 167 | address.setStreet(addressDetails.value(QStringLiteral("road")).toString()); 168 | address.setState(addressDetails.value(QStringLiteral("state")).toString()); 169 | address.setDistrict(addressDetails.value(QStringLiteral("suburb")).toString()); 170 | 171 | QGeoLocation location; 172 | location.setCoordinate(coordinate); 173 | location.setAddress(address); 174 | #if (QT_VERSION >= QT_VERSION_CHECK(6,0,0)) 175 | location.setBoundingShape(parseBoundingBox(item.value(QStringLiteral("boundingbox")).toArray())); 176 | #else 177 | location.setBoundingBox(parseBoundingBox(item.value(QStringLiteral("boundingbox")).toArray())); 178 | #endif 179 | place.setLocation(location); 180 | 181 | QPlaceResult result; 182 | result.setIcon(icon); 183 | result.setPlace(place); 184 | result.setTitle(title); 185 | 186 | return result; 187 | } 188 | -------------------------------------------------------------------------------- /qplacesearchreplyamap.h: -------------------------------------------------------------------------------- 1 | #ifndef QPLACESEARCHREPLYAMAP_H 2 | #define QPLACESEARCHREPLYAMAP_H 3 | 4 | #include 5 | 6 | QT_BEGIN_NAMESPACE 7 | 8 | class QNetworkReply; 9 | class QPlaceManagerEngineAmap; 10 | class QPlaceResult; 11 | 12 | class QPlaceSearchReplyAmap : public QPlaceSearchReply 13 | { 14 | Q_OBJECT 15 | 16 | public: 17 | QPlaceSearchReplyAmap(const QPlaceSearchRequest &request, QNetworkReply *reply, 18 | QPlaceManagerEngineAmap *parent); 19 | ~QPlaceSearchReplyAmap(); 20 | 21 | void abort(); 22 | 23 | private slots: 24 | void setError(QPlaceReply::Error errorCode, const QString &errorString); 25 | void replyFinished(); 26 | 27 | private: 28 | QPlaceResult parsePlaceResult(const QJsonObject &item) const; 29 | 30 | QNetworkReply *m_reply; 31 | }; 32 | 33 | QT_END_NAMESPACE 34 | 35 | #endif // QPLACESEARCHREPLYORS_H 36 | -------------------------------------------------------------------------------- /qplacesearchsuggestionreplyimpl.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2015 The Qt Company Ltd. 4 | ** Contact: http://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of the QtLocation module of the Qt Toolkit. 7 | ** 8 | ** $QT_BEGIN_LICENSE:LGPL3$ 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 http://www.qt.io/terms-conditions. For further 15 | ** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free 28 | ** Software Foundation and appearing in the file LICENSE.GPL included in 29 | ** the packaging of this file. Please review the following information to 30 | ** ensure the GNU General Public License version 2.0 requirements will be 31 | ** met: http://www.gnu.org/licenses/gpl-2.0.html. 32 | ** 33 | ** $QT_END_LICENSE$ 34 | ** 35 | ****************************************************************************/ 36 | 37 | #include "qplacesearchsuggestionreplyimpl.h" 38 | #include "qgeoerror_messages.h" 39 | 40 | #include 41 | #include 42 | #include 43 | #include 44 | 45 | QT_BEGIN_NAMESPACE 46 | 47 | QPlaceSearchSuggestionReplyImpl::QPlaceSearchSuggestionReplyImpl(QNetworkReply *reply, 48 | QObject *parent) 49 | : QPlaceSearchSuggestionReply(parent), m_reply(reply) 50 | { 51 | if (!m_reply) 52 | return; 53 | 54 | m_reply->setParent(this); 55 | connect(m_reply, SIGNAL(finished()), this, SLOT(replyFinished())); 56 | } 57 | 58 | QPlaceSearchSuggestionReplyImpl::~QPlaceSearchSuggestionReplyImpl() 59 | { 60 | } 61 | 62 | void QPlaceSearchSuggestionReplyImpl::abort() 63 | { 64 | if (m_reply) 65 | m_reply->abort(); 66 | } 67 | 68 | void QPlaceSearchSuggestionReplyImpl::setError(QPlaceReply::Error error_, 69 | const QString &errorString) 70 | { 71 | QPlaceReply::setError(error_, errorString); 72 | 73 | #if (QT_VERSION >= QT_VERSION_CHECK(6,0,0)) 74 | Q_EMIT errorOccurred(error_, errorString); 75 | #else 76 | Q_EMIT error(error_, errorString); 77 | #endif 78 | setFinished(true); 79 | emit finished(); 80 | } 81 | 82 | void QPlaceSearchSuggestionReplyImpl::replyFinished() 83 | { 84 | if (m_reply->error() != QNetworkReply::NoError) { 85 | switch (m_reply->error()) { 86 | case QNetworkReply::OperationCanceledError: 87 | setError(CancelError, "Request canceled."); 88 | break; 89 | default: 90 | setError(CommunicationError, "Network error."); 91 | } 92 | return; 93 | } 94 | 95 | QJsonDocument document = QJsonDocument::fromJson(m_reply->readAll()); 96 | if (!document.isObject()) { 97 | setError(ParseError, QCoreApplication::translate(NOKIA_PLUGIN_CONTEXT_NAME, PARSE_ERROR)); 98 | 99 | #if (QT_VERSION >= QT_VERSION_CHECK(6,0,0)) 100 | Q_EMIT errorOccurred(error(), errorString()); 101 | #else 102 | Q_EMIT error(error(), errorString()); 103 | #endif 104 | return; 105 | } 106 | 107 | QJsonObject object = document.object(); 108 | 109 | QJsonValue status = object.value(QStringLiteral("status")); 110 | if(status.toString().toLatin1() != "OK") 111 | { 112 | QJsonValue errorMessage = object.value(QStringLiteral("error_message")); 113 | setError(UnknownError, QString("%1: %2").arg(status.toString()).arg(errorMessage.toString()).toLatin1()); 114 | return; 115 | } 116 | QJsonArray suggestions = object.value(QStringLiteral("predictions")).toArray(); 117 | 118 | QStringList s; 119 | for (int i = 0; i < suggestions.count(); ++i) { 120 | if(suggestions.at(i).isObject()) { 121 | QJsonObject suggestion = suggestions.at(i).toObject(); 122 | QJsonValue description = suggestion.value("description"); 123 | if (description.isString()) { 124 | s.append(description.toString()); 125 | } 126 | } 127 | } 128 | 129 | setSuggestions(s); 130 | 131 | m_reply->deleteLater(); 132 | m_reply = 0; 133 | 134 | setFinished(true); 135 | emit finished(); 136 | } 137 | 138 | QT_END_NAMESPACE 139 | -------------------------------------------------------------------------------- /qplacesearchsuggestionreplyimpl.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2015 The Qt Company Ltd. 4 | ** Contact: http://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of the QtLocation module of the Qt Toolkit. 7 | ** 8 | ** $QT_BEGIN_LICENSE:LGPL3$ 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 http://www.qt.io/terms-conditions. For further 15 | ** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free 28 | ** Software Foundation and appearing in the file LICENSE.GPL included in 29 | ** the packaging of this file. Please review the following information to 30 | ** ensure the GNU General Public License version 2.0 requirements will be 31 | ** met: http://www.gnu.org/licenses/gpl-2.0.html. 32 | ** 33 | ** $QT_END_LICENSE$ 34 | ** 35 | ****************************************************************************/ 36 | 37 | #ifndef QPLACESEARCHSUGGESTIONREPLYIMPL_H 38 | #define QPLACESEARCHSUGGESTIONREPLYIMPL_H 39 | 40 | #include 41 | #include 42 | 43 | QT_BEGIN_NAMESPACE 44 | 45 | class QPlaceSearchSuggestionReplyImpl : public QPlaceSearchSuggestionReply 46 | { 47 | Q_OBJECT 48 | 49 | public: 50 | explicit QPlaceSearchSuggestionReplyImpl(QNetworkReply *reply, QObject *parent = 0); 51 | ~QPlaceSearchSuggestionReplyImpl(); 52 | 53 | public slots: 54 | void abort(); 55 | 56 | private slots: 57 | void setError(QPlaceReply::Error error_, const QString &errorString); 58 | void replyFinished(); 59 | private: 60 | 61 | QNetworkReply *m_reply; 62 | }; 63 | 64 | QT_END_NAMESPACE 65 | 66 | #endif // QPLACESEARCHSUGGESTIONREPLYIMPL_H 67 | -------------------------------------------------------------------------------- /scripts/windows-publish.ps1: -------------------------------------------------------------------------------- 1 | [CmdletBinding()] 2 | param ( 3 | [string] $archiveName, [string] $targetName 4 | ) 5 | # 外部环境变量包括: 6 | # VCINSTALLDIR: 'C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC' 7 | # archiveName: ${{ matrix.qt_ver }}-${{ matrix.qt_arch }} 8 | # winSdkDir: ${{ steps.build.outputs.winSdkDir }} 9 | # winSdkVer: ${{ steps.build.outputs.winSdkVer }} 10 | # vcToolsInstallDir: ${{ steps.build.outputs.vcToolsInstallDir }} 11 | # vcToolsRedistDir: ${{ steps.build.outputs.vcToolsRedistDir }} 12 | # msvcArch: ${{ matrix.msvc_arch }} 13 | 14 | 15 | # winSdkDir: C:\Program Files (x86)\Windows Kits\10\ 16 | # winSdkVer: 10.0.19041.0\ 17 | # vcToolsInstallDir: C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.28.29333\ 18 | # vcToolsRedistDir: C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Redist\MSVC\14.28.29325\ 19 | # VCINSTALLDIR: C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC 20 | # archiveName: 5.9.9-win32_msvc2015 21 | # msvcArch: x86 22 | 23 | $scriptDir = $PSScriptRoot 24 | $currentDir = Get-Location 25 | Write-Host "currentDir" $currentDir 26 | Write-Host "scriptDir" $scriptDir 27 | 28 | function Main() { 29 | # 打包zip 30 | Compress-Archive -Path "plugins" $archiveName'.zip' 31 | } 32 | 33 | if ($null -eq $archiveName || $null -eq $targetName) { 34 | Write-Host "args missing, archiveName is" $archiveName ", targetName is" $targetName 35 | return 36 | } 37 | Main --------------------------------------------------------------------------------