1 /****************************************************************************
2 **
3 ** Copyright (C) 2013-2018 Esri <contracts@esri.com>
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtLocation module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
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 https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://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.LGPL3 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-3.0.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 (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #include "georoutingmanagerengine_esri.h"
41 #include "georoutereply_esri.h"
42 
43 #include <QUrlQuery>
44 
45 QT_BEGIN_NAMESPACE
46 
47 static const QString kPrefixEsri(QStringLiteral("esri."));
48 static const QString kParamUserAgent(kPrefixEsri + QStringLiteral("useragent"));
49 static const QString kParamToken(kPrefixEsri + QStringLiteral("token"));
50 
51 static const QString kUrlRouting(QStringLiteral("http://route.arcgis.com/arcgis/rest/services/World/Route/NAServer/Route_World/solve"));
52 
GeoRoutingManagerEngineEsri(const QVariantMap & parameters,QGeoServiceProvider::Error * error,QString * errorString)53 GeoRoutingManagerEngineEsri::GeoRoutingManagerEngineEsri(const QVariantMap &parameters,
54                                                          QGeoServiceProvider::Error *error,
55                                                          QString *errorString) :
56     QGeoRoutingManagerEngine(parameters), m_networkManager(new QNetworkAccessManager(this))
57 {
58     if (parameters.contains(kParamUserAgent))
59         m_userAgent = parameters.value(kParamUserAgent).toString().toLatin1();
60     else
61         m_userAgent = QByteArrayLiteral("Qt Location based application");
62 
63     m_token = parameters.value(kParamToken).toString();
64 
65     *error = QGeoServiceProvider::NoError;
66     errorString->clear();
67 }
68 
~GeoRoutingManagerEngineEsri()69 GeoRoutingManagerEngineEsri::~GeoRoutingManagerEngineEsri()
70 {
71 }
72 
73 // REST reference: http://resources.arcgis.com/en/help/arcgis-rest-api/index.html#//02r300000036000000
74 
calculateRoute(const QGeoRouteRequest & request)75 QGeoRouteReply *GeoRoutingManagerEngineEsri::calculateRoute(const QGeoRouteRequest &request)
76 {
77     QNetworkRequest networkRequest;
78     networkRequest.setHeader(QNetworkRequest::UserAgentHeader, m_userAgent);
79 
80     QUrl url(kUrlRouting);
81     QUrlQuery query;
82     QString stops;
83 
84     foreach (const QGeoCoordinate &coordinate, request.waypoints())
85     {
86         if (!stops.isEmpty())
87             stops += "; ";
88 
89         stops += QString::number(coordinate.longitude()) + QLatin1Char(',') +
90                  QString::number(coordinate.latitude());
91     }
92 
93     query.addQueryItem(QStringLiteral("stops"), stops);
94     query.addQueryItem(QStringLiteral("f"), QStringLiteral("json"));
95     query.addQueryItem(QStringLiteral("directionsLanguage"), preferedDirectionLangage());
96     query.addQueryItem(QStringLiteral("directionsLengthUnits"), preferedDirectionsLengthUnits());
97     query.addQueryItem(QStringLiteral("token"), m_token);
98 
99     url.setQuery(query);
100     networkRequest.setUrl(url);
101 
102     QNetworkReply *reply = m_networkManager->get(networkRequest);
103     GeoRouteReplyEsri *routeReply = new GeoRouteReplyEsri(reply, request, this);
104 
105     connect(routeReply, SIGNAL(finished()), this, SLOT(replyFinished()));
106     connect(routeReply, SIGNAL(error(QGeoRouteReply::Error,QString)), this, SLOT(replyError(QGeoRouteReply::Error,QString)));
107 
108     return routeReply;
109 }
110 
replyFinished()111 void GeoRoutingManagerEngineEsri::replyFinished()
112 {
113     QGeoRouteReply *reply = qobject_cast<QGeoRouteReply *>(sender());
114     if (reply)
115         emit finished(reply);
116 }
117 
replyError(QGeoRouteReply::Error errorCode,const QString & errorString)118 void GeoRoutingManagerEngineEsri::replyError(QGeoRouteReply::Error errorCode, const QString &errorString)
119 {
120     QGeoRouteReply *reply = qobject_cast<QGeoRouteReply *>(sender());
121     if (reply)
122         emit error(reply, errorCode, errorString);
123 }
124 
preferedDirectionLangage()125 QString GeoRoutingManagerEngineEsri::preferedDirectionLangage()
126 {
127     // list of supported langages is defined in:
128     // http://resources.arcgis.com/en/help/arcgis-rest-api/index.html#//02r300000036000000
129     const QStringList supportedLanguages = {
130         "ar", // Generate directions in Arabic
131         "cs", // Generate directions in Czech
132         "de", // Generate directions in German
133         "el", // Generate directions in Greek
134         "en", // Generate directions in English (default)
135         "es", // Generate directions in Spanish
136         "et", // Generate directions in Estonian
137         "fr", // Generate directions in French
138         "he", // Generate directions in Hebrew
139         "it", // Generate directions in Italian
140         "ja", // Generate directions in Japanese
141         "ko", // Generate directions in Korean
142         "lt", // Generate directions in Lithuanian
143         "lv", // Generate directions in Latvian
144         "nl", // Generate directions in Dutch
145         "pl", // Generate directions in Polish
146         "pt-BR", // Generate directions in Brazilian Portuguese
147         "pt-PT", // Generate directions in Portuguese (Portugal)
148         "ru", // Generate directions in Russian
149         "sv", // Generate directions in Swedish
150         "tr", // Generate directions in Turkish
151         "zh-CN" // Simplified Chinese
152     };
153 
154     for (const QString &language: locale().uiLanguages())
155     {
156         if (language.startsWith("pt_BR")) // Portuguese (Brazilian)
157             return QStringLiteral("pt-BR");
158         if (language.startsWith("pt"))    // Portuguese (Portugal)
159             return QStringLiteral("pt-PT");
160         if (language.startsWith("zh"))    // Portuguese (Portugal)
161             return QStringLiteral("zh-CN");
162 
163         const QString country = language.left(2);
164         if (supportedLanguages.contains(country))
165             return country;
166     }
167     return QStringLiteral("en");  // default value
168 }
169 
preferedDirectionsLengthUnits()170 QString GeoRoutingManagerEngineEsri::preferedDirectionsLengthUnits()
171 {
172     switch (measurementSystem())
173     {
174     case QLocale::MetricSystem:
175         return QStringLiteral("esriNAUMeters");
176         break;
177     case QLocale::ImperialUSSystem:
178         return QStringLiteral( "esriNAUFeet");
179         break;
180     case QLocale::ImperialUKSystem:
181         return QStringLiteral("esriNAUFeet");
182         break;
183     default:
184         return QStringLiteral("esriNAUMeters");
185         break;
186     }
187     return QStringLiteral("esriNAUMeters");
188 }
189 
190 QT_END_NAMESPACE
191