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