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
65QT_BEGIN_NAMESPACE
66
67Q_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*/
224QStringList 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*/
247QGeoServiceProvider::QGeoServiceProvider(const QString &providerName,
248 const QVariantMap &parameters,
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*/
265QGeoServiceProvider::~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. :( */
273template <class Flags>
274Flags 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*/
300QGeoServiceProvider::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*/
308QGeoServiceProvider::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*/
316QGeoServiceProvider::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*/
324QGeoServiceProvider::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*/
334QGeoServiceProvider::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. */
342template <class Engine>
343Engine *createEngine(QGeoServiceProviderPrivate *)
344{
345 return 0;
346}
347template <> 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}
351template <> 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}
355template <> 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}
359template <> 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}
363template <> 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 */
372template <class Manager, class Engine>
373Manager *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*/
449QGeoCodingManager *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*/
481QGeoMappingManager *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*/
511QGeoRoutingManager *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*/
537QPlaceManager *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*/
553QNavigationManager *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*/
567QGeoServiceProvider::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*/
576QString 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*/
587QGeoServiceProvider::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*/
598QString 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*/
609QGeoServiceProvider::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*/
620QString 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*/
631QGeoServiceProvider::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*/
642QString 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*/
653QGeoServiceProvider::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*/
664QString 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*/
675QGeoServiceProvider::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*/
686QString 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*/
699void QGeoServiceProvider::setAllowExperimental(bool allow)
700{
701 d_ptr->experimental = allow;
702 d_ptr->unload();
703 d_ptr->loadMeta();
704}
705
706void 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*/
724void QGeoServiceProvider::setParameters(const QVariantMap &parameters)
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*/
736void 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
756QGeoServiceProviderPrivate::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
773QGeoServiceProviderPrivate::~QGeoServiceProviderPrivate()
774{
775 delete geocodingManager;
776 delete routingManager;
777 delete mappingManager;
778 delete placeManager;
779 delete navigationManager;
780}
781
782void 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 */
807void 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
827void 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
863void QGeoServiceProviderPrivate::loadPlugin(const QVariantMap &parameters)
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
899QMultiHash<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
914void 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
926QT_END_NAMESPACE
927
928

source code of qtlocation/src/location/maps/qgeoserviceprovider.cpp