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