| 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 "qgeoserviceprovider.h" | 
| 38 | #include "qgeoserviceprovider_p.h" | 
| 39 | #include "qgeoserviceproviderfactory.h" | 
| 40 |  | 
| 41 | #include "qgeocodingmanager.h" | 
| 42 | #include "qgeomappingmanager_p.h" | 
| 43 | #include "qgeoroutingmanager.h" | 
| 44 | #include "qplacemanager.h" | 
| 45 | #include "qnavigationmanager_p.h" | 
| 46 | #include "qgeocodingmanagerengine.h" | 
| 47 | #include "qgeomappingmanagerengine_p.h" | 
| 48 | #include "qgeoroutingmanagerengine.h" | 
| 49 | #include "qplacemanagerengine.h" | 
| 50 | #include "qplacemanagerengine_p.h" | 
| 51 | #include "qnavigationmanagerengine_p.h" | 
| 52 |  | 
| 53 | #include <QList> | 
| 54 | #include <QString> | 
| 55 | #include <QVariant> | 
| 56 |  | 
| 57 | #include <QDebug> | 
| 58 | #include <QStringList> | 
| 59 | #include <QCoreApplication> | 
| 60 | #include <QObject> | 
| 61 | #include <QMetaObject> | 
| 62 | #include <QMetaEnum> | 
| 63 | #include <QtCore/private/qfactoryloader_p.h> | 
| 64 |  | 
| 65 | QT_BEGIN_NAMESPACE | 
| 66 |  | 
| 67 | Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader, | 
| 68 |         ("org.qt-project.qt.geoservice.serviceproviderfactory/5.0" , | 
| 69 |          QLatin1String("/geoservices" ))) | 
| 70 |  | 
| 71 | /*! | 
| 72 |     \class QGeoServiceProvider | 
| 73 |     \inmodule QtLocation | 
| 74 |     \ingroup QtLocation-common | 
| 75 |     \since 5.6 | 
| 76 |  | 
| 77 |     \brief The QGeoServiceProvider class aggregates access to services which provide | 
| 78 |     geographical information. | 
| 79 |  | 
| 80 |     The Maps and Navigation API allows people to access various kinds of | 
| 81 |     geographical information, including functionality to perform geocoding, | 
| 82 |     routing and the display of maps.  The QGeoServiceProvider aggregates the | 
| 83 |     access to a set of these services that are provided by a single vendor. | 
| 84 |  | 
| 85 |     It is possible to mix and match service providers for the various domains, | 
| 86 |     so that a geocoding manager from one service provider can be used with | 
| 87 |     a geographic routing manager from another service provider. | 
| 88 |  | 
| 89 |     This is not recommended unless the client is able to verify that the | 
| 90 |     data provided by the different services are compatible, as differences | 
| 91 |     in the underlying data sets could cause serious incongruences between | 
| 92 |     the services. | 
| 93 |  | 
| 94 |     Subclasses of QGeoServiceProvider guarantee that the different services | 
| 95 |     that they provide are interoperable. | 
| 96 |  | 
| 97 |     At this point there are two GeoServices plugins packaged with Qt. They are | 
| 98 |     accessible using their provider names: | 
| 99 |  | 
| 100 |     \list | 
| 101 |         \li "mapbox" -> \l {Qt Location Mapbox Plugin}{Mapbox service} | 
| 102 |         \li "here" -> \l {Qt Location HERE Plugin}{HERE Services} | 
| 103 |         \li "osm" -> \l {Qt Location Open Street Map Plugin}{OpenStreetMap Services} | 
| 104 |         \li "esri" -> \l {Qt Location Esri Plugin}{ESRI Services} | 
| 105 |     \endlist | 
| 106 |  | 
| 107 |     Each service provider must follow a naming convention for their service specific | 
| 108 |     parameter names/keys. They use the provider name as prefix for all their | 
| 109 |     parameter names. For example, the \l {Qt Location HERE Plugin}{HERE} service provider | 
| 110 |     requires the \c here.app_id parameter. When a provider is loaded only those parameters are | 
| 111 |     passed on whose parameter names start with the provider name. This avoids the sharing | 
| 112 |     sensitive parameters such as confidential \c token or \c app_id parameters with other | 
| 113 |     plugins. | 
| 114 |  | 
| 115 |     Please check the GeoServices plugin specific documentation to | 
| 116 |     obtain a complete list of the available parameter names/keys and values. | 
| 117 | */ | 
| 118 |  | 
| 119 | /*! | 
| 120 |     \enum QGeoServiceProvider::Error | 
| 121 |  | 
| 122 |     Describes an error related to the loading and setup of a service provider plugin. | 
| 123 |  | 
| 124 |     \value NoError | 
| 125 |         No error has occurred. | 
| 126 |     \value NotSupportedError | 
| 127 |         The plugin does not support this functionality. | 
| 128 |     \value UnknownParameterError | 
| 129 |         The plugin did not recognize one of the parameters it was given. | 
| 130 |     \value MissingRequiredParameterError | 
| 131 |         The plugin did not find one of the parameters it was expecting. | 
| 132 |     \value ConnectionError | 
| 133 |         The plugin could not connect to its backend service or database. | 
| 134 |     \value LoaderError | 
| 135 |         The plugin failed to load. | 
| 136 | */ | 
| 137 |  | 
| 138 | /*! | 
| 139 |     \enum QGeoServiceProvider::RoutingFeature | 
| 140 |  | 
| 141 |     Describes the routing features supported by the geo service provider. | 
| 142 |  | 
| 143 |     \value NoRoutingFeatures            No routing features are supported. | 
| 144 |     \value OnlineRoutingFeature         Online routing is supported. | 
| 145 |     \value OfflineRoutingFeature        Offline routing is supported. | 
| 146 |     \value LocalizedRoutingFeature      Supports returning routes with localized addresses and | 
| 147 |                                         instructions. | 
| 148 |     \value RouteUpdatesFeature          Updating an existing route based on the current position is | 
| 149 |                                         supported. | 
| 150 |     \value AlternativeRoutesFeature     Supports returning alternative routes. | 
| 151 |     \value ExcludeAreasRoutingFeature   Supports specifying a areas which the returned route must | 
| 152 |                                         not cross. | 
| 153 |     \value AnyRoutingFeatures           Matches a geo service provider that provides any routing | 
| 154 |                                         features. | 
| 155 | */ | 
| 156 |  | 
| 157 | /*! | 
| 158 |     \enum QGeoServiceProvider::GeocodingFeature | 
| 159 |  | 
| 160 |     Describes the geocoding features supported by the geo service provider. | 
| 161 |  | 
| 162 |     \value NoGeocodingFeatures          No geocoding features are supported. | 
| 163 |     \value OnlineGeocodingFeature       Online geocoding is supported. | 
| 164 |     \value OfflineGeocodingFeature      Offline geocoding is supported. | 
| 165 |     \value ReverseGeocodingFeature      Reverse geocoding is supported. | 
| 166 |     \value LocalizedGeocodingFeature    Supports returning geocoding results with localized | 
| 167 |                                         addresses. | 
| 168 |     \value AnyGeocodingFeatures         Matches a geo service provider that provides any geocoding | 
| 169 |                                         features. | 
| 170 | */ | 
| 171 |  | 
| 172 | /*! | 
| 173 |     \enum QGeoServiceProvider::MappingFeature | 
| 174 |  | 
| 175 |     Describes the mapping features supported by the geo service provider. | 
| 176 |  | 
| 177 |     \value NoMappingFeatures        No mapping features are supported. | 
| 178 |     \value OnlineMappingFeature     Online mapping is supported. | 
| 179 |     \value OfflineMappingFeature    Offline mapping is supported. | 
| 180 |     \value LocalizedMappingFeature  Supports returning localized map data. | 
| 181 |     \value AnyMappingFeatures       Matches a geo service provider that provides any mapping | 
| 182 |                                     features. | 
| 183 | */ | 
| 184 |  | 
| 185 | /*! | 
| 186 |     \enum QGeoServiceProvider::PlacesFeature | 
| 187 |  | 
| 188 |     Describes the places features supported by the geo service provider. | 
| 189 |  | 
| 190 |     \value NoPlacesFeatures             No places features are supported. | 
| 191 |     \value OnlinePlacesFeature          Online places is supported. | 
| 192 |     \value OfflinePlacesFeature         Offline places is supported. | 
| 193 |     \value SavePlaceFeature             Saving places is supported. | 
| 194 |     \value RemovePlaceFeature           Removing or deleting places is supported. | 
| 195 |     \value SaveCategoryFeature          Saving categories is supported. | 
| 196 |     \value RemoveCategoryFeature        Removing or deleting categories is supported. | 
| 197 |     \value PlaceRecommendationsFeature  Searching for recommended places similar to another place | 
| 198 |                                         is supported. | 
| 199 |     \value SearchSuggestionsFeature     Search suggestions is supported. | 
| 200 |     \value LocalizedPlacesFeature       Supports returning localized place data. | 
| 201 |     \value NotificationsFeature         Notifications of place and category changes is supported. | 
| 202 |     \value PlaceMatchingFeature         Supports matching places from two different geo service | 
| 203 |                                         providers. | 
| 204 |     \value AnyPlacesFeatures            Matches a geo service provider that provides any places | 
| 205 |                                         features. | 
| 206 | */ | 
| 207 |  | 
| 208 | /*! | 
| 209 |     \enum QGeoServiceProvider::NavigationFeature | 
| 210 |  | 
| 211 |     Describes the navigation features supported by the geo service provider. | 
| 212 |  | 
| 213 |     \value NoNavigationFeatures         No navigation features are supported. | 
| 214 |     \value OnlineNavigationFeature      Online navigation is supported. | 
| 215 |     \value OfflineNavigationFeature     Offline navigation is supported. | 
| 216 |     \value AnyNavigationFeatures        Matches a geo service provider that provides any navigation | 
| 217 |                                         features. | 
| 218 | */ | 
| 219 |  | 
| 220 | /*! | 
| 221 |     Returns a list of names of the available service providers, for use with | 
| 222 |     the QGeoServiceProvider constructors. | 
| 223 | */ | 
| 224 | QStringList QGeoServiceProvider::availableServiceProviders() | 
| 225 | { | 
| 226 |     return QGeoServiceProviderPrivate::plugins().keys(); | 
| 227 | } | 
| 228 |  | 
| 229 | /*! | 
| 230 |     Constructs a QGeoServiceProvider whose backend has the name \a | 
| 231 |     providerName, using the provided \a parameters. | 
| 232 |  | 
| 233 |     If multiple plugins have the same \a providerName, the plugin with the | 
| 234 |     highest reported providerVersion() will be used. | 
| 235 |  | 
| 236 |     If \a allowExperimental is true then plugins marked as experimental may be used.  By default | 
| 237 |     experimental plugins are not considered. | 
| 238 |  | 
| 239 |     If no plugin matching \a providerName was able to be loaded then error() | 
| 240 |     and errorString() will provide details about why this is the case. | 
| 241 |  | 
| 242 |     \note Before the list of \a parameters is passed on to the to-be-loaded | 
| 243 |     provider plugin, the list is filtered to avoid the sharing of plugin specific | 
| 244 |     parameters with unrelated provider plugins. Plugin specific parameter | 
| 245 |     keys must be prefixed with the provider name (e.g. \c here.app_id). | 
| 246 | */ | 
| 247 | QGeoServiceProvider::QGeoServiceProvider(const QString &providerName, | 
| 248 |                                          const QVariantMap ¶meters, | 
| 249 |                                          bool allowExperimental) | 
| 250 |     : d_ptr(new QGeoServiceProviderPrivate()) | 
| 251 | { | 
| 252 |     d_ptr->experimental = allowExperimental; | 
| 253 |     d_ptr->parameterMap = parameters; | 
| 254 |     // TODO Qt 6 Remove silent nokia rename | 
| 255 |     if (providerName == QStringLiteral("nokia" )) | 
| 256 |         d_ptr->providerName = QStringLiteral("here" ); | 
| 257 |     else | 
| 258 |         d_ptr->providerName = providerName; | 
| 259 |     d_ptr->loadMeta(); | 
| 260 | } | 
| 261 |  | 
| 262 | /*! | 
| 263 |     Destroys the service provider object. | 
| 264 | */ | 
| 265 | QGeoServiceProvider::~QGeoServiceProvider() | 
| 266 | { | 
| 267 |     delete d_ptr; | 
| 268 | } | 
| 269 |  | 
| 270 | /* Template for the routingFeatures(), geocodingFeatures() etc methods. | 
| 271 |  * Ideally, the enumName would be a template parameter, but strings | 
| 272 |  * are not a valid const expr. :( */ | 
| 273 | template <class Flags> | 
| 274 | Flags QGeoServiceProviderPrivate::features(const char *enumName) | 
| 275 | { | 
| 276 |     const QMetaObject *mo = &QGeoServiceProvider::staticMetaObject; | 
| 277 |     const QMetaEnum en = mo->enumerator( | 
| 278 |                 index: mo->indexOfEnumerator(name: enumName)); | 
| 279 |  | 
| 280 |     /* We need the typename keyword here, or Flags::enum_type will be parsed | 
| 281 |      * as a non-type and lead to an error */ | 
| 282 |     Flags ret = typename Flags::enum_type(0); | 
| 283 |     if (this->metaData.contains(QStringLiteral("Features" )) | 
| 284 |             && this->metaData.value(QStringLiteral("Features" )).isArray()) { | 
| 285 |         QJsonArray features = this->metaData.value(QStringLiteral("Features" )).toArray(); | 
| 286 |         foreach (const QJsonValue &v, features) { | 
| 287 |             int val = en.keyToValue(key: v.toString().toLatin1().constData()); | 
| 288 |             if (v.isString() && val != -1) { | 
| 289 |                 ret |= typename Flags::enum_type(val); | 
| 290 |             } | 
| 291 |         } | 
| 292 |     } | 
| 293 |  | 
| 294 |     return ret; | 
| 295 | } | 
| 296 |  | 
| 297 | /*! | 
| 298 |     Returns the routing features supported by the geo service provider. | 
| 299 | */ | 
| 300 | QGeoServiceProvider::RoutingFeatures QGeoServiceProvider::routingFeatures() const | 
| 301 | { | 
| 302 |     return d_ptr->features<RoutingFeatures>(enumName: "RoutingFeatures" ); | 
| 303 | } | 
| 304 |  | 
| 305 | /*! | 
| 306 |     Returns the geocoding features supported by the geo service provider. | 
| 307 | */ | 
| 308 | QGeoServiceProvider::GeocodingFeatures QGeoServiceProvider::geocodingFeatures() const | 
| 309 | { | 
| 310 |     return d_ptr->features<GeocodingFeatures>(enumName: "GeocodingFeatures" ); | 
| 311 | } | 
| 312 |  | 
| 313 | /*! | 
| 314 |     Returns the mapping features supported by the geo service provider. | 
| 315 | */ | 
| 316 | QGeoServiceProvider::MappingFeatures QGeoServiceProvider::mappingFeatures() const | 
| 317 | { | 
| 318 |     return d_ptr->features<MappingFeatures>(enumName: "MappingFeatures" ); | 
| 319 | } | 
| 320 |  | 
| 321 | /*! | 
| 322 |     Returns the places features supported by the geo service provider. | 
| 323 | */ | 
| 324 | QGeoServiceProvider::PlacesFeatures QGeoServiceProvider::placesFeatures() const | 
| 325 | { | 
| 326 |     return d_ptr->features<PlacesFeatures>(enumName: "PlacesFeatures" ); | 
| 327 | } | 
| 328 |  | 
| 329 | /*! | 
| 330 |     Returns the navigation features supported by the geo service provider. | 
| 331 |  | 
| 332 |     \since QtLocation 5.11 | 
| 333 | */ | 
| 334 | QGeoServiceProvider::NavigationFeatures QGeoServiceProvider::navigationFeatures() const | 
| 335 | { | 
| 336 |     return d_ptr->features<NavigationFeatures>(enumName: "NavigationFeatures" ); | 
| 337 | } | 
| 338 |  | 
| 339 | /* Sadly, these are necessary to figure out which of the factory->createX | 
| 340 |  * methods we need to call. Ideally it would be nice to find a way to embed | 
| 341 |  * these into the manager() template. */ | 
| 342 | template <class Engine> | 
| 343 | Engine *createEngine(QGeoServiceProviderPrivate *) | 
| 344 | { | 
| 345 |     return 0; | 
| 346 | } | 
| 347 | template <> QGeoCodingManagerEngine *createEngine<QGeoCodingManagerEngine>(QGeoServiceProviderPrivate *d_ptr) | 
| 348 | { | 
| 349 |     return d_ptr->factory->createGeocodingManagerEngine(parameters: d_ptr->cleanedParameterMap, error: &(d_ptr->geocodeError), errorString: &(d_ptr->geocodeErrorString)); | 
| 350 | } | 
| 351 | template <> QGeoRoutingManagerEngine *createEngine<QGeoRoutingManagerEngine>(QGeoServiceProviderPrivate *d_ptr) | 
| 352 | { | 
| 353 |     return d_ptr->factory->createRoutingManagerEngine(parameters: d_ptr->cleanedParameterMap, error: &(d_ptr->routingError), errorString: &(d_ptr->routingErrorString)); | 
| 354 | } | 
| 355 | template <> QGeoMappingManagerEngine *createEngine<QGeoMappingManagerEngine>(QGeoServiceProviderPrivate *d_ptr) | 
| 356 | { | 
| 357 |     return d_ptr->factory->createMappingManagerEngine(parameters: d_ptr->cleanedParameterMap, error: &(d_ptr->mappingError), errorString: &(d_ptr->mappingErrorString)); | 
| 358 | } | 
| 359 | template <> QPlaceManagerEngine *createEngine<QPlaceManagerEngine>(QGeoServiceProviderPrivate *d_ptr) | 
| 360 | { | 
| 361 |     return d_ptr->factory->createPlaceManagerEngine(parameters: d_ptr->cleanedParameterMap, error: &(d_ptr->placeError), errorString: &(d_ptr->placeErrorString)); | 
| 362 | } | 
| 363 | template <> QNavigationManagerEngine *createEngine<QNavigationManagerEngine>(QGeoServiceProviderPrivate *d_ptr) | 
| 364 | { | 
| 365 |     if (!d_ptr->factoryV2) | 
| 366 |         return nullptr; | 
| 367 |     return d_ptr->factoryV2->createNavigationManagerEngine(parameters: d_ptr->cleanedParameterMap, error: &(d_ptr->navigationError), errorString: &(d_ptr->navigationErrorString)); | 
| 368 | } | 
| 369 |  | 
| 370 | /* Template for generating the code for each of the geocodingManager(), | 
| 371 |  * mappingManager() etc methods */ | 
| 372 | template <class Manager, class Engine> | 
| 373 | Manager *QGeoServiceProviderPrivate::manager(QGeoServiceProvider::Error *_error, | 
| 374 |                                              QString *_errorString, Manager **_manager) | 
| 375 | { | 
| 376 |     // make local references just so this method is easier to read | 
| 377 |     QGeoServiceProvider::Error &error = *_error; | 
| 378 |     QString &errorString = *_errorString; | 
| 379 |     Manager *&manager = *_manager; | 
| 380 |  | 
| 381 |     if (!this->factory) { | 
| 382 |         this->filterParameterMap(); | 
| 383 |         this->loadPlugin(parameters: this->parameterMap); | 
| 384 |     } | 
| 385 |  | 
| 386 |     if (!this->factory) { | 
| 387 |         error = this->error; | 
| 388 |         errorString = this->errorString; | 
| 389 |         return 0; | 
| 390 |     } | 
| 391 |  | 
| 392 |     if (!manager) { | 
| 393 |         Engine *engine = createEngine<Engine>(this); // this sets the specific error variables directly, | 
| 394 |                                                      // from now on the local error, errorString refs should be set. | 
| 395 |  | 
| 396 |         if (engine) { | 
| 397 |             engine->setManagerName( | 
| 398 |                         this->metaData.value(QStringLiteral("Provider" )).toString()); | 
| 399 |             engine->setManagerVersion( | 
| 400 |                         int(this->metaData.value(QStringLiteral("Version" )).toDouble())); | 
| 401 |             manager = new Manager(engine); | 
| 402 |         } else if (error == QGeoServiceProvider::NoError) { | 
| 403 |             error = QGeoServiceProvider::NotSupportedError; | 
| 404 |             errorString = QLatin1String("The service provider does not support the " ); | 
| 405 |             errorString.append(s: QLatin1String(Manager::staticMetaObject.className())); | 
| 406 |             errorString.append(s: QLatin1String(" type." )); | 
| 407 |         } | 
| 408 |  | 
| 409 |         if (error != QGeoServiceProvider::NoError) { | 
| 410 |             delete manager; | 
| 411 |             manager = 0; | 
| 412 |             this->error = error; | 
| 413 |             this->errorString = errorString; | 
| 414 |         } | 
| 415 |  | 
| 416 |         if (manager && this->localeSet) | 
| 417 |             manager->setLocale(this->locale); | 
| 418 |     } | 
| 419 |  | 
| 420 |     if (manager) { | 
| 421 |         this->error = QGeoServiceProvider::NoError; | 
| 422 |         this->errorString.clear(); | 
| 423 |     } | 
| 424 |  | 
| 425 |     return manager; | 
| 426 | } | 
| 427 |  | 
| 428 | /*! | 
| 429 |     Returns the QGeoCodingManager made available by the service | 
| 430 |     provider. | 
| 431 |  | 
| 432 |     This function will return 0 if the service provider does not provide | 
| 433 |     any geocoding services. | 
| 434 |  | 
| 435 |     This function will attempt to construct a QGeoCodingManager instance | 
| 436 |     when it is called for the first time.  If the attempt is successful the | 
| 437 |     QGeoCodingManager will be cached, otherwise each call of this function | 
| 438 |     will attempt to construct a QGeoCodingManager instance until the | 
| 439 |     construction is successful. | 
| 440 |  | 
| 441 |     The QGeoCodingManager is owned by this QGeoServiceProvider and should not | 
| 442 |     be deleted separately. Users should assume that deleting the | 
| 443 |     QGeoServiceProvider renders the pointer returned by this method invalid. | 
| 444 |  | 
| 445 |     After this function has been called, error() and errorString() will | 
| 446 |     report any errors which occurred during the construction of the | 
| 447 |     QGeoCodingManager. | 
| 448 | */ | 
| 449 | QGeoCodingManager *QGeoServiceProvider::geocodingManager() const | 
| 450 | { | 
| 451 |     QGeoCodingManager *mgr = d_ptr->manager<QGeoCodingManager, QGeoCodingManagerEngine>( | 
| 452 |                error: &(d_ptr->geocodeError), errorString: &(d_ptr->geocodeErrorString), | 
| 453 |                manager: &(d_ptr->geocodingManager)); | 
| 454 |     if (!mgr) | 
| 455 |         qDebug() << d_ptr->error << ", "  << d_ptr->errorString; | 
| 456 |     return mgr; | 
| 457 | } | 
| 458 |  | 
| 459 | /*! | 
| 460 |     Returns the QGeoMappingManager made available by the service provider. | 
| 461 |  | 
| 462 |     This function will return 0 if the service provider does not provide | 
| 463 |     any mapping services. | 
| 464 |  | 
| 465 |     This function will attempt to construct a QGeoMappingManager instance | 
| 466 |     when it is called for the first time.  If the attempt is successful the | 
| 467 |     QGeoMappingManager will be cached, otherwise each call of this function | 
| 468 |     will attempt to construct a QGeoMappingManager instance until the | 
| 469 |     construction is successful. | 
| 470 |  | 
| 471 |     The QGeoMappingManager is owned by this QGeoServiceProvider and should not | 
| 472 |     be deleted separately. Users should assume that deleting the | 
| 473 |     QGeoServiceProvider renders the pointer returned by this method invalid. | 
| 474 |  | 
| 475 |     After this function has been called, error() and errorString() will | 
| 476 |     report any errors which occurred during the construction of the | 
| 477 |     QGeoMappingManager. | 
| 478 |  | 
| 479 |     \internal | 
| 480 | */ | 
| 481 | QGeoMappingManager *QGeoServiceProvider::mappingManager() const | 
| 482 | { | 
| 483 |     QGeoMappingManager *mgr = d_ptr->manager<QGeoMappingManager, QGeoMappingManagerEngine>( | 
| 484 |                error: &(d_ptr->mappingError), errorString: &(d_ptr->mappingErrorString), | 
| 485 |                manager: &(d_ptr->mappingManager)); | 
| 486 |     if (!mgr) | 
| 487 |         qDebug() << d_ptr->error << ", "  << d_ptr->errorString; | 
| 488 |     return mgr; | 
| 489 | } | 
| 490 |  | 
| 491 | /*! | 
| 492 |     Returns the QGeoRoutingManager made available by the service provider. | 
| 493 |  | 
| 494 |     This function will return 0 if the service provider does not provide | 
| 495 |     any geographic routing services. | 
| 496 |  | 
| 497 |     This function will attempt to construct a QGeoRoutingManager instance | 
| 498 |     when it is called for the first time.  If the attempt is successful the | 
| 499 |     QGeoRoutingManager will be cached, otherwise each call of this function | 
| 500 |     will attempt to construct a QGeoRoutingManager instance until the | 
| 501 |     construction is successful. | 
| 502 |  | 
| 503 |     The QGeoRoutingManager is owned by this QGeoServiceProvider and should not | 
| 504 |     be deleted separately. Users should assume that deleting the | 
| 505 |     QGeoServiceProvider renders the pointer returned by this method invalid. | 
| 506 |  | 
| 507 |     After this function has been called, error() and errorString() will | 
| 508 |     report any errors which occurred during the construction of the | 
| 509 |     QGeoRoutingManager. | 
| 510 | */ | 
| 511 | QGeoRoutingManager *QGeoServiceProvider::routingManager() const | 
| 512 | { | 
| 513 |     QGeoRoutingManager *mgr = d_ptr->manager<QGeoRoutingManager, QGeoRoutingManagerEngine>( | 
| 514 |                error: &(d_ptr->routingError), errorString: &(d_ptr->routingErrorString), | 
| 515 |                manager: &(d_ptr->routingManager)); | 
| 516 |     if (!mgr) | 
| 517 |         qDebug() << d_ptr->error << ", "  << d_ptr->errorString; | 
| 518 |     return mgr; | 
| 519 | } | 
| 520 |  | 
| 521 | /*! | 
| 522 |     Returns the QPlaceManager made available by the service provider. | 
| 523 |  | 
| 524 |     This function will attempt to construct a QPlaceManager instance | 
| 525 |     when it is called for the first time.  If the attempt is successful the | 
| 526 |     QPlaceManager will be cached, otherwise each call of this function | 
| 527 |     will attempt to construct a QPlace instance until the | 
| 528 |     construction is successful. | 
| 529 |  | 
| 530 |     The QGeoPlaceManager is owned by this QGeoServiceProvider and should not | 
| 531 |     be deleted separately. Users should assume that deleting the | 
| 532 |     QGeoServiceProvider renders the pointer returned by this method invalid. | 
| 533 |  | 
| 534 |     After this function has been called, error() and errorString() will | 
| 535 |     report any errors which occurred during the construction of the QPlaceManager. | 
| 536 | */ | 
| 537 | QPlaceManager *QGeoServiceProvider::placeManager() const | 
| 538 | { | 
| 539 |     QPlaceManager *mgr = d_ptr->manager<QPlaceManager, QPlaceManagerEngine>( | 
| 540 |                error: &(d_ptr->placeError), errorString: &(d_ptr->placeErrorString), | 
| 541 |                 manager: &(d_ptr->placeManager)); | 
| 542 |     if (!mgr) | 
| 543 |         qDebug() << d_ptr->error << ", "  << d_ptr->errorString; | 
| 544 |     return mgr; | 
| 545 | } | 
| 546 |  | 
| 547 | /*! | 
| 548 |     Returns a new QNavigationManager made available by the service provider. | 
| 549 |  | 
| 550 |     After this function has been called, error() and errorString() will | 
| 551 |     report any errors which occurred during the construction of the QNavigationManagerEngine. | 
| 552 | */ | 
| 553 | QNavigationManager *QGeoServiceProvider::navigationManager() const | 
| 554 | { | 
| 555 |     QNavigationManager * mgr = d_ptr->manager<QNavigationManager, QNavigationManagerEngine>( | 
| 556 |                error: &(d_ptr->navigationError), errorString: &(d_ptr->navigationErrorString), | 
| 557 |                 manager: &(d_ptr->navigationManager)); | 
| 558 |     if (!mgr) | 
| 559 |         qDebug() << d_ptr->error << ", "  << d_ptr->errorString; | 
| 560 |     return mgr; | 
| 561 | } | 
| 562 |  | 
| 563 | /*! | 
| 564 |     Returns an error code describing the error which occurred during the | 
| 565 |     last operation that was performed by this class. | 
| 566 | */ | 
| 567 | QGeoServiceProvider::Error QGeoServiceProvider::error() const | 
| 568 | { | 
| 569 |     return d_ptr->error; | 
| 570 | } | 
| 571 |  | 
| 572 | /*! | 
| 573 |     Returns a string describing the error which occurred during the | 
| 574 |     last operation that was performed by this class. | 
| 575 | */ | 
| 576 | QString QGeoServiceProvider::errorString() const | 
| 577 | { | 
| 578 |     return d_ptr->errorString; | 
| 579 | } | 
| 580 |  | 
| 581 | /*! | 
| 582 |     Returns an error code describing the error which occurred during the | 
| 583 |     last attempt to create a mapping manager. | 
| 584 |  | 
| 585 |     \since 5.13 | 
| 586 | */ | 
| 587 | QGeoServiceProvider::Error QGeoServiceProvider::mappingError() const | 
| 588 | { | 
| 589 |     return d_ptr->mappingError; | 
| 590 | } | 
| 591 |  | 
| 592 | /*! | 
| 593 |     Returns a string describing the error which occurred during the | 
| 594 |     last attempt to create a mapping manager. | 
| 595 |  | 
| 596 |     \since 5.13 | 
| 597 | */ | 
| 598 | QString QGeoServiceProvider::mappingErrorString() const | 
| 599 | { | 
| 600 |     return d_ptr->mappingErrorString; | 
| 601 | } | 
| 602 |  | 
| 603 | /*! | 
| 604 |     Returns an error code describing the error which occurred during the | 
| 605 |     last attempt to create a geocoding manager. | 
| 606 |  | 
| 607 |     \since 5.13 | 
| 608 | */ | 
| 609 | QGeoServiceProvider::Error QGeoServiceProvider::geocodingError() const | 
| 610 | { | 
| 611 |     return d_ptr->geocodeError; | 
| 612 | } | 
| 613 |  | 
| 614 | /*! | 
| 615 |     Returns a string describing the error which occurred during the | 
| 616 |     last attempt to create a geocoding manager. | 
| 617 |  | 
| 618 |     \since 5.13 | 
| 619 | */ | 
| 620 | QString QGeoServiceProvider::geocodingErrorString() const | 
| 621 | { | 
| 622 |     return d_ptr->geocodeErrorString; | 
| 623 | } | 
| 624 |  | 
| 625 | /*! | 
| 626 |     Returns an error code describing the error which occurred during the | 
| 627 |     last attempt to create a routing manager. | 
| 628 |  | 
| 629 |     \since 5.13 | 
| 630 | */ | 
| 631 | QGeoServiceProvider::Error QGeoServiceProvider::routingError() const | 
| 632 | { | 
| 633 |     return d_ptr->routingError; | 
| 634 | } | 
| 635 |  | 
| 636 | /*! | 
| 637 |     Returns a string describing the error which occurred during the | 
| 638 |     last attempt to create a routing manager. | 
| 639 |  | 
| 640 |     \since 5.13 | 
| 641 | */ | 
| 642 | QString QGeoServiceProvider::routingErrorString() const | 
| 643 | { | 
| 644 |     return d_ptr->routingErrorString; | 
| 645 | } | 
| 646 |  | 
| 647 | /*! | 
| 648 |     Returns an error code describing the error which occurred during the | 
| 649 |     last attempt to create a places manager. | 
| 650 |  | 
| 651 |     \since 5.13 | 
| 652 | */ | 
| 653 | QGeoServiceProvider::Error QGeoServiceProvider::placesError() const | 
| 654 | { | 
| 655 |     return d_ptr->placeError; | 
| 656 | } | 
| 657 |  | 
| 658 | /*! | 
| 659 |     Returns a string describing the error which occurred during the | 
| 660 |     last attempt to create a places manager. | 
| 661 |  | 
| 662 |     \since 5.13 | 
| 663 | */ | 
| 664 | QString QGeoServiceProvider::placesErrorString() const | 
| 665 | { | 
| 666 |     return d_ptr->placeErrorString; | 
| 667 | } | 
| 668 |  | 
| 669 | /*! | 
| 670 |     Returns an error code describing the error which occurred during the | 
| 671 |     last attempt to create a navigation manager. | 
| 672 |  | 
| 673 |     \since 5.13 | 
| 674 | */ | 
| 675 | QGeoServiceProvider::Error QGeoServiceProvider::navigationError() const | 
| 676 | { | 
| 677 |     return d_ptr->navigationError; | 
| 678 | } | 
| 679 |  | 
| 680 | /*! | 
| 681 |     Returns a string describing the error which occurred during the | 
| 682 |     last attempt to create a navigation manager. | 
| 683 |  | 
| 684 |     \since 5.13 | 
| 685 | */ | 
| 686 | QString QGeoServiceProvider::navigationErrorString() const | 
| 687 | { | 
| 688 |     return d_ptr->navigationErrorString; | 
| 689 | } | 
| 690 |  | 
| 691 | /*! | 
| 692 |     Sets whether experimental plugins are considered when locating the | 
| 693 |     correct plugin library for this service provider to \a allow. | 
| 694 |  | 
| 695 |     \b {Important:} this will destroy any existing managers held by this | 
| 696 |     service provider instance. You should be sure not to attempt to use any | 
| 697 |     pointers that you have previously retrieved after calling this method. | 
| 698 | */ | 
| 699 | void QGeoServiceProvider::setAllowExperimental(bool allow) | 
| 700 | { | 
| 701 |     d_ptr->experimental = allow; | 
| 702 |     d_ptr->unload(); | 
| 703 |     d_ptr->loadMeta(); | 
| 704 | } | 
| 705 |  | 
| 706 | void QGeoServiceProvider::setQmlEngine(QQmlEngine *engine) | 
| 707 | { | 
| 708 |     d_ptr->qmlEngine = engine; | 
| 709 | } | 
| 710 |  | 
| 711 | /*! | 
| 712 |     Sets the parameters used to construct individual manager classes for | 
| 713 |     this service provider to \a parameters. | 
| 714 |  | 
| 715 |     Before the list of \a parameters is passed on to the to-be-loaded | 
| 716 |     service provider, the list is filtered to avoid the sharing of provider specific | 
| 717 |     parameters with unrelated service providers. Provider specific parameter | 
| 718 |     keys must be prefixed with the provider name (e.g. \c here.app_id). | 
| 719 |  | 
| 720 |     \b {Important:} this will destroy any existing managers held by this | 
| 721 |     service provider instance. You should be sure not to attempt to use any | 
| 722 |     pointers that you have previously retrieved after calling this method. | 
| 723 | */ | 
| 724 | void QGeoServiceProvider::setParameters(const QVariantMap ¶meters) | 
| 725 | { | 
| 726 |     d_ptr->parameterMap = parameters; | 
| 727 |     d_ptr->unload(); | 
| 728 |     d_ptr->loadMeta(); | 
| 729 | } | 
| 730 |  | 
| 731 | /*! | 
| 732 |     Sets the locale used by this service provider to \a locale. If the relevant features | 
| 733 |     (see LocalizedMappingFeature etc), this will change the languages, units | 
| 734 |     and other locale-specific attributes of the provider's data. | 
| 735 | */ | 
| 736 | void QGeoServiceProvider::setLocale(const QLocale &locale) | 
| 737 | { | 
| 738 |     d_ptr->locale = locale; | 
| 739 |     d_ptr->localeSet = true; | 
| 740 |  | 
| 741 |     if (d_ptr->geocodingManager) | 
| 742 |         d_ptr->geocodingManager->setLocale(locale); | 
| 743 |     if (d_ptr->routingManager) | 
| 744 |         d_ptr->routingManager->setLocale(locale); | 
| 745 |     if (d_ptr->mappingManager) | 
| 746 |         d_ptr->mappingManager->setLocale(locale); | 
| 747 |     if (d_ptr->placeManager) | 
| 748 |         d_ptr->placeManager->setLocale(locale); | 
| 749 |     if (d_ptr->navigationManager) | 
| 750 |         d_ptr->navigationManager->setLocale(locale); | 
| 751 | } | 
| 752 |  | 
| 753 | /******************************************************************************* | 
| 754 | *******************************************************************************/ | 
| 755 |  | 
| 756 | QGeoServiceProviderPrivate::QGeoServiceProviderPrivate() | 
| 757 |     : factory(0), | 
| 758 |       experimental(false), | 
| 759 |       geocodingManager(0), | 
| 760 |       routingManager(0), | 
| 761 |       mappingManager(0), | 
| 762 |       placeManager(0), | 
| 763 |       geocodeError(QGeoServiceProvider::NoError), | 
| 764 |       routingError(QGeoServiceProvider::NoError), | 
| 765 |       mappingError(QGeoServiceProvider::NoError), | 
| 766 |       placeError(QGeoServiceProvider::NoError), | 
| 767 |       error(QGeoServiceProvider::NoError), | 
| 768 |       localeSet(false) | 
| 769 | { | 
| 770 |     metaData.insert(QStringLiteral("index" ), value: -1); | 
| 771 | } | 
| 772 |  | 
| 773 | QGeoServiceProviderPrivate::~QGeoServiceProviderPrivate() | 
| 774 | { | 
| 775 |     delete geocodingManager; | 
| 776 |     delete routingManager; | 
| 777 |     delete mappingManager; | 
| 778 |     delete placeManager; | 
| 779 |     delete navigationManager; | 
| 780 | } | 
| 781 |  | 
| 782 | void QGeoServiceProviderPrivate::unload() | 
| 783 | { | 
| 784 |     delete geocodingManager; | 
| 785 |     geocodingManager = 0; | 
| 786 |  | 
| 787 |     delete routingManager; | 
| 788 |     routingManager = 0; | 
| 789 |  | 
| 790 |     delete mappingManager; | 
| 791 |     mappingManager = 0; | 
| 792 |  | 
| 793 |     delete placeManager; | 
| 794 |     placeManager = 0; | 
| 795 |  | 
| 796 |     delete navigationManager; | 
| 797 |     navigationManager = nullptr; | 
| 798 |  | 
| 799 |     factory = factoryV2 = factoryV3 = nullptr; | 
| 800 |     error = QGeoServiceProvider::NoError; | 
| 801 |     errorString = QLatin1String("" ); | 
| 802 |     metaData = QJsonObject(); | 
| 803 |     metaData.insert(QStringLiteral("index" ), value: -1); | 
| 804 | } | 
| 805 |  | 
| 806 | /* Filter out any parameter that doesn't match any plugin */ | 
| 807 | void QGeoServiceProviderPrivate::filterParameterMap() | 
| 808 | { | 
| 809 |     const auto availablePlugins = QGeoServiceProviderPrivate::plugins(); | 
| 810 |  | 
| 811 |     cleanedParameterMap = parameterMap; | 
| 812 |     for (auto it = availablePlugins.keyBegin(), end = availablePlugins.keyEnd(); it != end; ++it) { | 
| 813 |         if (*it == providerName) // don't remove parameters for current provider | 
| 814 |             continue; | 
| 815 |  | 
| 816 |         QVariantMap::iterator i = cleanedParameterMap.begin(); | 
| 817 |         while (i != cleanedParameterMap.end()) { | 
| 818 |             // remove every parameter meant for other plugins | 
| 819 |             if (i.key().startsWith(s: QString(*it + QLatin1Char('.')))) | 
| 820 |                 i = cleanedParameterMap.erase(it: i); | 
| 821 |             else | 
| 822 |                 ++i; | 
| 823 |         } | 
| 824 |     } | 
| 825 | } | 
| 826 |  | 
| 827 | void QGeoServiceProviderPrivate::loadMeta() | 
| 828 | { | 
| 829 |     factory = factoryV2 = factoryV3 = nullptr; | 
| 830 |     metaData = QJsonObject(); | 
| 831 |     metaData.insert(QStringLiteral("index" ), value: -1); | 
| 832 |     error = QGeoServiceProvider::NotSupportedError; | 
| 833 |     errorString = QString(QLatin1String("The geoservices provider %1 is not supported." )).arg(a: providerName); | 
| 834 |  | 
| 835 |     QList<QJsonObject> candidates = QGeoServiceProviderPrivate::plugins().values(akey: providerName); | 
| 836 |  | 
| 837 |     int versionFound = -1; | 
| 838 |     int idx = -1; | 
| 839 |  | 
| 840 |     // figure out which version of the plugin we want | 
| 841 |     // (always latest unless experimental) | 
| 842 |     for (int i = 0; i < candidates.size(); ++i) { | 
| 843 |         QJsonObject meta = candidates[i]; | 
| 844 |         if (meta.contains(QStringLiteral("Version" )) | 
| 845 |                 && meta.value(QStringLiteral("Version" )).isDouble() | 
| 846 |                 && meta.contains(QStringLiteral("Experimental" )) | 
| 847 |                 && meta.value(QStringLiteral("Experimental" )).isBool()) { | 
| 848 |             int ver = int(meta.value(QStringLiteral("Version" )).toDouble()); | 
| 849 |             if (ver > versionFound && !(!experimental && meta.value(QStringLiteral("Experimental" )).toBool())) { | 
| 850 |                 versionFound = ver; | 
| 851 |                 idx = i; | 
| 852 |             } | 
| 853 |         } | 
| 854 |     } | 
| 855 |  | 
| 856 |     if (idx != -1) { | 
| 857 |         error = QGeoServiceProvider::NoError; | 
| 858 |         errorString = QStringLiteral("" ); | 
| 859 |         metaData = candidates[idx]; | 
| 860 |     } | 
| 861 | } | 
| 862 |  | 
| 863 | void QGeoServiceProviderPrivate::loadPlugin(const QVariantMap ¶meters) | 
| 864 | { | 
| 865 |     Q_UNUSED(parameters); | 
| 866 |  | 
| 867 |     if (int(metaData.value(QStringLiteral("index" )).toDouble()) < 0) { | 
| 868 |         error = QGeoServiceProvider::NotSupportedError; | 
| 869 |         errorString = QString(QLatin1String("The geoservices provider is not supported." )); | 
| 870 |         factory = factoryV2 = factoryV3 = nullptr; | 
| 871 |         return; | 
| 872 |     } | 
| 873 |  | 
| 874 |     error = QGeoServiceProvider::NoError; | 
| 875 |     errorString = QLatin1String("" ); | 
| 876 |  | 
| 877 |     int idx = int(metaData.value(QStringLiteral("index" )).toDouble()); | 
| 878 |  | 
| 879 |     // load the actual plugin | 
| 880 |     QObject *instance = loader()->instance(index: idx); | 
| 881 |     if (!instance) { | 
| 882 |         error = QGeoServiceProvider::LoaderError; | 
| 883 |         errorString = QLatin1String("loader()->instance(idx) failed to return an instance. Set the environment variable QT_DEBUG_PLUGINS to see more details." ); | 
| 884 |         return; | 
| 885 |     } | 
| 886 |     factoryV3 = qobject_cast<QGeoServiceProviderFactoryV3 *>(object: instance); | 
| 887 |     if (!factoryV3) { | 
| 888 |         factoryV2 = qobject_cast<QGeoServiceProviderFactoryV2 *>(object: instance); | 
| 889 |         if (!factoryV2) | 
| 890 |             factory = qobject_cast<QGeoServiceProviderFactory *>(object: instance); | 
| 891 |         else | 
| 892 |             factory = factoryV2; | 
| 893 |     } else { | 
| 894 |         factory = factoryV2 = factoryV3; | 
| 895 |         factoryV3->setQmlEngine(qmlEngine); | 
| 896 |     } | 
| 897 | } | 
| 898 |  | 
| 899 | QMultiHash<QString, QJsonObject> QGeoServiceProviderPrivate::plugins(bool reload) | 
| 900 | { | 
| 901 |     static QMultiHash<QString, QJsonObject> plugins; | 
| 902 |     static bool alreadyDiscovered = false; | 
| 903 |  | 
| 904 |     if (reload == true) | 
| 905 |         alreadyDiscovered = false; | 
| 906 |  | 
| 907 |     if (!alreadyDiscovered) { | 
| 908 |         loadPluginMetadata(list&: plugins); | 
| 909 |         alreadyDiscovered = true; | 
| 910 |     } | 
| 911 |     return plugins; | 
| 912 | } | 
| 913 |  | 
| 914 | void QGeoServiceProviderPrivate::loadPluginMetadata(QMultiHash<QString, QJsonObject> &list) | 
| 915 | { | 
| 916 |     QFactoryLoader *l = loader(); | 
| 917 |     QList<QJsonObject> meta = l->metaData(); | 
| 918 |     for (int i = 0; i < meta.size(); ++i) { | 
| 919 |         QJsonObject obj = meta.at(i).value(QStringLiteral("MetaData" )).toObject(); | 
| 920 |         obj.insert(QStringLiteral("index" ), value: i); | 
| 921 |         list.insert(akey: obj.value(QStringLiteral("Provider" )).toString(), avalue: obj); | 
| 922 |     } | 
| 923 | } | 
| 924 |  | 
| 925 |  | 
| 926 | QT_END_NAMESPACE | 
| 927 |  | 
| 928 |  |