/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the QtLocation module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL3$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see http://www.qt.io/terms-conditions. For further ** information use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPLv3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or later as published by the Free ** Software Foundation and appearing in the file LICENSE.GPL included in ** the packaging of this file. Please review the following information to ** ensure the GNU General Public License version 2.0 requirements will be ** met: http://www.gnu.org/licenses/gpl-2.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qgeoserviceprovider.h" #include "qgeoserviceprovider_p.h" #include "qgeoserviceproviderfactory.h" #include "qgeocodingmanager.h" #include "qgeomappingmanager_p.h" #include "qgeoroutingmanager.h" #include "qplacemanager.h" #include "qnavigationmanager_p.h" #include "qgeocodingmanagerengine.h" #include "qgeomappingmanagerengine_p.h" #include "qgeoroutingmanagerengine.h" #include "qplacemanagerengine.h" #include "qplacemanagerengine_p.h" #include "qnavigationmanagerengine_p.h" #include #include #include #include #include #include #include #include #include #include QT_BEGIN_NAMESPACE Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader, ("org.qt-project.qt.geoservice.serviceproviderfactory/5.0", QLatin1String("/geoservices"))) /*! \class QGeoServiceProvider \inmodule QtLocation \ingroup QtLocation-common \since 5.6 \brief The QGeoServiceProvider class aggregates access to services which provide geographical information. The Maps and Navigation API allows people to access various kinds of geographical information, including functionality to perform geocoding, routing and the display of maps. The QGeoServiceProvider aggregates the access to a set of these services that are provided by a single vendor. It is possible to mix and match service providers for the various domains, so that a geocoding manager from one service provider can be used with a geographic routing manager from another service provider. This is not recommended unless the client is able to verify that the data provided by the different services are compatible, as differences in the underlying data sets could cause serious incongruences between the services. Subclasses of QGeoServiceProvider guarantee that the different services that they provide are interoperable. At this point there are two GeoServices plugins packaged with Qt. They are accessible using their provider names: \list \li "mapbox" -> \l {Qt Location Mapbox Plugin}{Mapbox service} \li "here" -> \l {Qt Location HERE Plugin}{HERE Services} \li "osm" -> \l {Qt Location Open Street Map Plugin}{OpenStreetMap Services} \li "esri" -> \l {Qt Location Esri Plugin}{ESRI Services} \endlist Each service provider must follow a naming convention for their service specific parameter names/keys. They use the provider name as prefix for all their parameter names. For example, the \l {Qt Location HERE Plugin}{HERE} service provider requires the \c here.app_id parameter. When a provider is loaded only those parameters are passed on whose parameter names start with the provider name. This avoids the sharing sensitive parameters such as confidential \c token or \c app_id parameters with other plugins. Please check the GeoServices plugin specific documentation to obtain a complete list of the available parameter names/keys and values. */ /*! \enum QGeoServiceProvider::Error Describes an error related to the loading and setup of a service provider plugin. \value NoError No error has occurred. \value NotSupportedError The plugin does not support this functionality. \value UnknownParameterError The plugin did not recognize one of the parameters it was given. \value MissingRequiredParameterError The plugin did not find one of the parameters it was expecting. \value ConnectionError The plugin could not connect to its backend service or database. \value LoaderError The plugin failed to load. */ /*! \enum QGeoServiceProvider::RoutingFeature Describes the routing features supported by the geo service provider. \value NoRoutingFeatures No routing features are supported. \value OnlineRoutingFeature Online routing is supported. \value OfflineRoutingFeature Offline routing is supported. \value LocalizedRoutingFeature Supports returning routes with localized addresses and instructions. \value RouteUpdatesFeature Updating an existing route based on the current position is supported. \value AlternativeRoutesFeature Supports returning alternative routes. \value ExcludeAreasRoutingFeature Supports specifying a areas which the returned route must not cross. \value AnyRoutingFeatures Matches a geo service provider that provides any routing features. */ /*! \enum QGeoServiceProvider::GeocodingFeature Describes the geocoding features supported by the geo service provider. \value NoGeocodingFeatures No geocoding features are supported. \value OnlineGeocodingFeature Online geocoding is supported. \value OfflineGeocodingFeature Offline geocoding is supported. \value ReverseGeocodingFeature Reverse geocoding is supported. \value LocalizedGeocodingFeature Supports returning geocoding results with localized addresses. \value AnyGeocodingFeatures Matches a geo service provider that provides any geocoding features. */ /*! \enum QGeoServiceProvider::MappingFeature Describes the mapping features supported by the geo service provider. \value NoMappingFeatures No mapping features are supported. \value OnlineMappingFeature Online mapping is supported. \value OfflineMappingFeature Offline mapping is supported. \value LocalizedMappingFeature Supports returning localized map data. \value AnyMappingFeatures Matches a geo service provider that provides any mapping features. */ /*! \enum QGeoServiceProvider::PlacesFeature Describes the places features supported by the geo service provider. \value NoPlacesFeatures No places features are supported. \value OnlinePlacesFeature Online places is supported. \value OfflinePlacesFeature Offline places is supported. \value SavePlaceFeature Saving places is supported. \value RemovePlaceFeature Removing or deleting places is supported. \value SaveCategoryFeature Saving categories is supported. \value RemoveCategoryFeature Removing or deleting categories is supported. \value PlaceRecommendationsFeature Searching for recommended places similar to another place is supported. \value SearchSuggestionsFeature Search suggestions is supported. \value LocalizedPlacesFeature Supports returning localized place data. \value NotificationsFeature Notifications of place and category changes is supported. \value PlaceMatchingFeature Supports matching places from two different geo service providers. \value AnyPlacesFeatures Matches a geo service provider that provides any places features. */ /*! \enum QGeoServiceProvider::NavigationFeature Describes the navigation features supported by the geo service provider. \value NoNavigationFeatures No navigation features are supported. \value OnlineNavigationFeature Online navigation is supported. \value OfflineNavigationFeature Offline navigation is supported. \value AnyNavigationFeatures Matches a geo service provider that provides any navigation features. */ /*! Returns a list of names of the available service providers, for use with the QGeoServiceProvider constructors. */ QStringList QGeoServiceProvider::availableServiceProviders() { return QGeoServiceProviderPrivate::plugins().keys(); } /*! Constructs a QGeoServiceProvider whose backend has the name \a providerName, using the provided \a parameters. If multiple plugins have the same \a providerName, the plugin with the highest reported providerVersion() will be used. If \a allowExperimental is true then plugins marked as experimental may be used. By default experimental plugins are not considered. If no plugin matching \a providerName was able to be loaded then error() and errorString() will provide details about why this is the case. \note Before the list of \a parameters is passed on to the to-be-loaded provider plugin, the list is filtered to avoid the sharing of plugin specific parameters with unrelated provider plugins. Plugin specific parameter keys must be prefixed with the provider name (e.g. \c here.app_id). */ QGeoServiceProvider::QGeoServiceProvider(const QString &providerName, const QVariantMap ¶meters, bool allowExperimental) : d_ptr(new QGeoServiceProviderPrivate()) { d_ptr->experimental = allowExperimental; d_ptr->parameterMap = parameters; // TODO Qt 6 Remove silent nokia rename if (providerName == QStringLiteral("nokia")) d_ptr->providerName = QStringLiteral("here"); else d_ptr->providerName = providerName; d_ptr->loadMeta(); } /*! Destroys the service provider object. */ QGeoServiceProvider::~QGeoServiceProvider() { delete d_ptr; } /* Template for the routingFeatures(), geocodingFeatures() etc methods. * Ideally, the enumName would be a template parameter, but strings * are not a valid const expr. :( */ template Flags QGeoServiceProviderPrivate::features(const char *enumName) { const QMetaObject *mo = &QGeoServiceProvider::staticMetaObject; const QMetaEnum en = mo->enumerator( mo->indexOfEnumerator(enumName)); /* We need the typename keyword here, or Flags::enum_type will be parsed * as a non-type and lead to an error */ Flags ret = typename Flags::enum_type(0); if (this->metaData.contains(QStringLiteral("Features")) && this->metaData.value(QStringLiteral("Features")).isArray()) { QJsonArray features = this->metaData.value(QStringLiteral("Features")).toArray(); foreach (const QJsonValue &v, features) { int val = en.keyToValue(v.toString().toLatin1().constData()); if (v.isString() && val != -1) { ret |= typename Flags::enum_type(val); } } } return ret; } /*! Returns the routing features supported by the geo service provider. */ QGeoServiceProvider::RoutingFeatures QGeoServiceProvider::routingFeatures() const { return d_ptr->features("RoutingFeatures"); } /*! Returns the geocoding features supported by the geo service provider. */ QGeoServiceProvider::GeocodingFeatures QGeoServiceProvider::geocodingFeatures() const { return d_ptr->features("GeocodingFeatures"); } /*! Returns the mapping features supported by the geo service provider. */ QGeoServiceProvider::MappingFeatures QGeoServiceProvider::mappingFeatures() const { return d_ptr->features("MappingFeatures"); } /*! Returns the places features supported by the geo service provider. */ QGeoServiceProvider::PlacesFeatures QGeoServiceProvider::placesFeatures() const { return d_ptr->features("PlacesFeatures"); } /*! Returns the navigation features supported by the geo service provider. \since QtLocation 5.11 */ QGeoServiceProvider::NavigationFeatures QGeoServiceProvider::navigationFeatures() const { return d_ptr->features("NavigationFeatures"); } /* Sadly, these are necessary to figure out which of the factory->createX * methods we need to call. Ideally it would be nice to find a way to embed * these into the manager() template. */ template Engine *createEngine(QGeoServiceProviderPrivate *) { return 0; } template <> QGeoCodingManagerEngine *createEngine(QGeoServiceProviderPrivate *d_ptr) { return d_ptr->factory->createGeocodingManagerEngine(d_ptr->cleanedParameterMap, &(d_ptr->geocodeError), &(d_ptr->geocodeErrorString)); } template <> QGeoRoutingManagerEngine *createEngine(QGeoServiceProviderPrivate *d_ptr) { return d_ptr->factory->createRoutingManagerEngine(d_ptr->cleanedParameterMap, &(d_ptr->routingError), &(d_ptr->routingErrorString)); } template <> QGeoMappingManagerEngine *createEngine(QGeoServiceProviderPrivate *d_ptr) { return d_ptr->factory->createMappingManagerEngine(d_ptr->cleanedParameterMap, &(d_ptr->mappingError), &(d_ptr->mappingErrorString)); } template <> QPlaceManagerEngine *createEngine(QGeoServiceProviderPrivate *d_ptr) { return d_ptr->factory->createPlaceManagerEngine(d_ptr->cleanedParameterMap, &(d_ptr->placeError), &(d_ptr->placeErrorString)); } template <> QNavigationManagerEngine *createEngine(QGeoServiceProviderPrivate *d_ptr) { if (!d_ptr->factoryV2) return nullptr; return d_ptr->factoryV2->createNavigationManagerEngine(d_ptr->cleanedParameterMap, &(d_ptr->navigationError), &(d_ptr->navigationErrorString)); } /* Template for generating the code for each of the geocodingManager(), * mappingManager() etc methods */ template Manager *QGeoServiceProviderPrivate::manager(QGeoServiceProvider::Error *_error, QString *_errorString, Manager **_manager) { // make local references just so this method is easier to read QGeoServiceProvider::Error &error = *_error; QString &errorString = *_errorString; Manager *&manager = *_manager; if (!this->factory) { this->filterParameterMap(); this->loadPlugin(this->parameterMap); } if (!this->factory) { error = this->error; errorString = this->errorString; return 0; } if (!manager) { Engine *engine = createEngine(this); // this sets the specific error variables directly, // from now on the local error, errorString refs should be set. if (engine) { engine->setManagerName( this->metaData.value(QStringLiteral("Provider")).toString()); engine->setManagerVersion( int(this->metaData.value(QStringLiteral("Version")).toDouble())); manager = new Manager(engine); } else if (error == QGeoServiceProvider::NoError) { error = QGeoServiceProvider::NotSupportedError; errorString = QLatin1String("The service provider does not support the "); errorString.append(QLatin1String(Manager::staticMetaObject.className())); errorString.append(QLatin1String(" type.")); } if (error != QGeoServiceProvider::NoError) { delete manager; manager = 0; this->error = error; this->errorString = errorString; } if (manager && this->localeSet) manager->setLocale(this->locale); } if (manager) { this->error = QGeoServiceProvider::NoError; this->errorString.clear(); } return manager; } /*! Returns the QGeoCodingManager made available by the service provider. This function will return 0 if the service provider does not provide any geocoding services. This function will attempt to construct a QGeoCodingManager instance when it is called for the first time. If the attempt is successful the QGeoCodingManager will be cached, otherwise each call of this function will attempt to construct a QGeoCodingManager instance until the construction is successful. The QGeoCodingManager is owned by this QGeoServiceProvider and should not be deleted separately. Users should assume that deleting the QGeoServiceProvider renders the pointer returned by this method invalid. After this function has been called, error() and errorString() will report any errors which occurred during the construction of the QGeoCodingManager. */ QGeoCodingManager *QGeoServiceProvider::geocodingManager() const { QGeoCodingManager *mgr = d_ptr->manager( &(d_ptr->geocodeError), &(d_ptr->geocodeErrorString), &(d_ptr->geocodingManager)); if (!mgr) qDebug() << d_ptr->error << ", " << d_ptr->errorString; return mgr; } /*! Returns the QGeoMappingManager made available by the service provider. This function will return 0 if the service provider does not provide any mapping services. This function will attempt to construct a QGeoMappingManager instance when it is called for the first time. If the attempt is successful the QGeoMappingManager will be cached, otherwise each call of this function will attempt to construct a QGeoMappingManager instance until the construction is successful. The QGeoMappingManager is owned by this QGeoServiceProvider and should not be deleted separately. Users should assume that deleting the QGeoServiceProvider renders the pointer returned by this method invalid. After this function has been called, error() and errorString() will report any errors which occurred during the construction of the QGeoMappingManager. \internal */ QGeoMappingManager *QGeoServiceProvider::mappingManager() const { QGeoMappingManager *mgr = d_ptr->manager( &(d_ptr->mappingError), &(d_ptr->mappingErrorString), &(d_ptr->mappingManager)); if (!mgr) qDebug() << d_ptr->error << ", " << d_ptr->errorString; return mgr; } /*! Returns the QGeoRoutingManager made available by the service provider. This function will return 0 if the service provider does not provide any geographic routing services. This function will attempt to construct a QGeoRoutingManager instance when it is called for the first time. If the attempt is successful the QGeoRoutingManager will be cached, otherwise each call of this function will attempt to construct a QGeoRoutingManager instance until the construction is successful. The QGeoRoutingManager is owned by this QGeoServiceProvider and should not be deleted separately. Users should assume that deleting the QGeoServiceProvider renders the pointer returned by this method invalid. After this function has been called, error() and errorString() will report any errors which occurred during the construction of the QGeoRoutingManager. */ QGeoRoutingManager *QGeoServiceProvider::routingManager() const { QGeoRoutingManager *mgr = d_ptr->manager( &(d_ptr->routingError), &(d_ptr->routingErrorString), &(d_ptr->routingManager)); if (!mgr) qDebug() << d_ptr->error << ", " << d_ptr->errorString; return mgr; } /*! Returns the QPlaceManager made available by the service provider. This function will attempt to construct a QPlaceManager instance when it is called for the first time. If the attempt is successful the QPlaceManager will be cached, otherwise each call of this function will attempt to construct a QPlace instance until the construction is successful. The QGeoPlaceManager is owned by this QGeoServiceProvider and should not be deleted separately. Users should assume that deleting the QGeoServiceProvider renders the pointer returned by this method invalid. After this function has been called, error() and errorString() will report any errors which occurred during the construction of the QPlaceManager. */ QPlaceManager *QGeoServiceProvider::placeManager() const { QPlaceManager *mgr = d_ptr->manager( &(d_ptr->placeError), &(d_ptr->placeErrorString), &(d_ptr->placeManager)); if (!mgr) qDebug() << d_ptr->error << ", " << d_ptr->errorString; return mgr; } /*! Returns a new QNavigationManager made available by the service provider. After this function has been called, error() and errorString() will report any errors which occurred during the construction of the QNavigationManagerEngine. */ QNavigationManager *QGeoServiceProvider::navigationManager() const { QNavigationManager * mgr = d_ptr->manager( &(d_ptr->navigationError), &(d_ptr->navigationErrorString), &(d_ptr->navigationManager)); if (!mgr) qDebug() << d_ptr->error << ", " << d_ptr->errorString; return mgr; } /*! Returns an error code describing the error which occurred during the last operation that was performed by this class. */ QGeoServiceProvider::Error QGeoServiceProvider::error() const { return d_ptr->error; } /*! Returns a string describing the error which occurred during the last operation that was performed by this class. */ QString QGeoServiceProvider::errorString() const { return d_ptr->errorString; } /*! Returns an error code describing the error which occurred during the last attempt to create a mapping manager. \since 5.13 */ QGeoServiceProvider::Error QGeoServiceProvider::mappingError() const { return d_ptr->mappingError; } /*! Returns a string describing the error which occurred during the last attempt to create a mapping manager. \since 5.13 */ QString QGeoServiceProvider::mappingErrorString() const { return d_ptr->mappingErrorString; } /*! Returns an error code describing the error which occurred during the last attempt to create a geocoding manager. \since 5.13 */ QGeoServiceProvider::Error QGeoServiceProvider::geocodingError() const { return d_ptr->geocodeError; } /*! Returns a string describing the error which occurred during the last attempt to create a geocoding manager. \since 5.13 */ QString QGeoServiceProvider::geocodingErrorString() const { return d_ptr->geocodeErrorString; } /*! Returns an error code describing the error which occurred during the last attempt to create a routing manager. \since 5.13 */ QGeoServiceProvider::Error QGeoServiceProvider::routingError() const { return d_ptr->routingError; } /*! Returns a string describing the error which occurred during the last attempt to create a routing manager. \since 5.13 */ QString QGeoServiceProvider::routingErrorString() const { return d_ptr->routingErrorString; } /*! Returns an error code describing the error which occurred during the last attempt to create a places manager. \since 5.13 */ QGeoServiceProvider::Error QGeoServiceProvider::placesError() const { return d_ptr->placeError; } /*! Returns a string describing the error which occurred during the last attempt to create a places manager. \since 5.13 */ QString QGeoServiceProvider::placesErrorString() const { return d_ptr->placeErrorString; } /*! Returns an error code describing the error which occurred during the last attempt to create a navigation manager. \since 5.13 */ QGeoServiceProvider::Error QGeoServiceProvider::navigationError() const { return d_ptr->navigationError; } /*! Returns a string describing the error which occurred during the last attempt to create a navigation manager. \since 5.13 */ QString QGeoServiceProvider::navigationErrorString() const { return d_ptr->navigationErrorString; } /*! Sets whether experimental plugins are considered when locating the correct plugin library for this service provider to \a allow. \b {Important:} this will destroy any existing managers held by this service provider instance. You should be sure not to attempt to use any pointers that you have previously retrieved after calling this method. */ void QGeoServiceProvider::setAllowExperimental(bool allow) { d_ptr->experimental = allow; d_ptr->unload(); d_ptr->loadMeta(); } void QGeoServiceProvider::setQmlEngine(QQmlEngine *engine) { d_ptr->qmlEngine = engine; } /*! Sets the parameters used to construct individual manager classes for this service provider to \a parameters. Before the list of \a parameters is passed on to the to-be-loaded service provider, the list is filtered to avoid the sharing of provider specific parameters with unrelated service providers. Provider specific parameter keys must be prefixed with the provider name (e.g. \c here.app_id). \b {Important:} this will destroy any existing managers held by this service provider instance. You should be sure not to attempt to use any pointers that you have previously retrieved after calling this method. */ void QGeoServiceProvider::setParameters(const QVariantMap ¶meters) { d_ptr->parameterMap = parameters; d_ptr->unload(); d_ptr->loadMeta(); } /*! Sets the locale used by this service provider to \a locale. If the relevant features (see LocalizedMappingFeature etc), this will change the languages, units and other locale-specific attributes of the provider's data. */ void QGeoServiceProvider::setLocale(const QLocale &locale) { d_ptr->locale = locale; d_ptr->localeSet = true; if (d_ptr->geocodingManager) d_ptr->geocodingManager->setLocale(locale); if (d_ptr->routingManager) d_ptr->routingManager->setLocale(locale); if (d_ptr->mappingManager) d_ptr->mappingManager->setLocale(locale); if (d_ptr->placeManager) d_ptr->placeManager->setLocale(locale); if (d_ptr->navigationManager) d_ptr->navigationManager->setLocale(locale); } /******************************************************************************* *******************************************************************************/ QGeoServiceProviderPrivate::QGeoServiceProviderPrivate() : factory(0), experimental(false), geocodingManager(0), routingManager(0), mappingManager(0), placeManager(0), geocodeError(QGeoServiceProvider::NoError), routingError(QGeoServiceProvider::NoError), mappingError(QGeoServiceProvider::NoError), placeError(QGeoServiceProvider::NoError), error(QGeoServiceProvider::NoError), localeSet(false) { metaData.insert(QStringLiteral("index"), -1); } QGeoServiceProviderPrivate::~QGeoServiceProviderPrivate() { delete geocodingManager; delete routingManager; delete mappingManager; delete placeManager; delete navigationManager; } void QGeoServiceProviderPrivate::unload() { delete geocodingManager; geocodingManager = 0; delete routingManager; routingManager = 0; delete mappingManager; mappingManager = 0; delete placeManager; placeManager = 0; delete navigationManager; navigationManager = nullptr; factory = factoryV2 = factoryV3 = nullptr; error = QGeoServiceProvider::NoError; errorString = QLatin1String(""); metaData = QJsonObject(); metaData.insert(QStringLiteral("index"), -1); } /* Filter out any parameter that doesn't match any plugin */ void QGeoServiceProviderPrivate::filterParameterMap() { const auto availablePlugins = QGeoServiceProviderPrivate::plugins(); cleanedParameterMap = parameterMap; for (auto it = availablePlugins.keyBegin(), end = availablePlugins.keyEnd(); it != end; ++it) { if (*it == providerName) // don't remove parameters for current provider continue; QVariantMap::iterator i = cleanedParameterMap.begin(); while (i != cleanedParameterMap.end()) { // remove every parameter meant for other plugins if (i.key().startsWith(QString(*it + QLatin1Char('.')))) i = cleanedParameterMap.erase(i); else ++i; } } } void QGeoServiceProviderPrivate::loadMeta() { factory = factoryV2 = factoryV3 = nullptr; metaData = QJsonObject(); metaData.insert(QStringLiteral("index"), -1); error = QGeoServiceProvider::NotSupportedError; errorString = QString(QLatin1String("The geoservices provider %1 is not supported.")).arg(providerName); QList candidates = QGeoServiceProviderPrivate::plugins().values(providerName); int versionFound = -1; int idx = -1; // figure out which version of the plugin we want // (always latest unless experimental) for (int i = 0; i < candidates.size(); ++i) { QJsonObject meta = candidates[i]; if (meta.contains(QStringLiteral("Version")) && meta.value(QStringLiteral("Version")).isDouble() && meta.contains(QStringLiteral("Experimental")) && meta.value(QStringLiteral("Experimental")).isBool()) { int ver = int(meta.value(QStringLiteral("Version")).toDouble()); if (ver > versionFound && !(!experimental && meta.value(QStringLiteral("Experimental")).toBool())) { versionFound = ver; idx = i; } } } if (idx != -1) { error = QGeoServiceProvider::NoError; errorString = QStringLiteral(""); metaData = candidates[idx]; } } void QGeoServiceProviderPrivate::loadPlugin(const QVariantMap ¶meters) { Q_UNUSED(parameters); if (int(metaData.value(QStringLiteral("index")).toDouble()) < 0) { error = QGeoServiceProvider::NotSupportedError; errorString = QString(QLatin1String("The geoservices provider is not supported.")); factory = factoryV2 = factoryV3 = nullptr; return; } error = QGeoServiceProvider::NoError; errorString = QLatin1String(""); int idx = int(metaData.value(QStringLiteral("index")).toDouble()); // load the actual plugin QObject *instance = loader()->instance(idx); if (!instance) { error = QGeoServiceProvider::LoaderError; errorString = QLatin1String("loader()->instance(idx) failed to return an instance. Set the environment variable QT_DEBUG_PLUGINS to see more details."); return; } factoryV3 = qobject_cast(instance); if (!factoryV3) { factoryV2 = qobject_cast(instance); if (!factoryV2) factory = qobject_cast(instance); else factory = factoryV2; } else { factory = factoryV2 = factoryV3; factoryV3->setQmlEngine(qmlEngine); } } QHash QGeoServiceProviderPrivate::plugins(bool reload) { static QHash plugins; static bool alreadyDiscovered = false; if (reload == true) alreadyDiscovered = false; if (!alreadyDiscovered) { loadPluginMetadata(plugins); alreadyDiscovered = true; } return plugins; } void QGeoServiceProviderPrivate::loadPluginMetadata(QHash &list) { QFactoryLoader *l = loader(); QList meta = l->metaData(); for (int i = 0; i < meta.size(); ++i) { QJsonObject obj = meta.at(i).value(QStringLiteral("MetaData")).toObject(); obj.insert(QStringLiteral("index"), i); list.insertMulti(obj.value(QStringLiteral("Provider")).toString(), obj); } } QT_END_NAMESPACE