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 | |