From 1451c427431b63c5a452228b0efde762a9e9d28a Mon Sep 17 00:00:00 2001 From: Tadej Novak Date: Mon, 30 Oct 2023 17:32:12 +0100 Subject: [PATCH] Rework style settings and make QMapLibre::Settings more future-proof --- examples/quick/main.qml | 2 +- src/core/CMakeLists.txt | 2 +- src/core/map.cpp | 22 +-- src/core/map.hpp | 2 - src/core/map_p.hpp | 1 - src/core/settings.cpp | 229 ++++++++++++++++------ src/core/settings.hpp | 51 ++--- src/core/settings_p.hpp | 53 +++++ src/core/types.hpp | 29 +++ src/location/qgeomap.cpp | 4 +- src/location/qt_mapping_engine.cpp | 127 +++++++++--- src/widgets/gl_widget.cpp | 11 +- test/core/map_tester.cpp | 1 + test/core/test_core.cpp | 2 +- test/qml/qt5/tst_map.qml | 10 +- test/qml/qt5/tst_plugin_style.qml | 77 ++++++++ test/qml/qt6/tst_map.qml | 10 +- test/qml/qt6/tst_plugin_no_parameters.qml | 37 ++++ test/qml/qt6/tst_plugin_provider.qml | 42 ++++ test/qml/qt6/tst_plugin_style.qml | 77 ++++++++ test/widgets/test_widgets.cpp | 40 +++- 21 files changed, 691 insertions(+), 138 deletions(-) create mode 100644 src/core/settings_p.hpp create mode 100644 test/qml/qt5/tst_plugin_style.qml create mode 100644 test/qml/qt6/tst_plugin_no_parameters.qml create mode 100644 test/qml/qt6/tst_plugin_provider.qml create mode 100644 test/qml/qt6/tst_plugin_style.qml diff --git a/examples/quick/main.qml b/examples/quick/main.qml index 4990944..3307c0b 100644 --- a/examples/quick/main.qml +++ b/examples/quick/main.qml @@ -40,7 +40,7 @@ Window { name: "maplibre" // specify plugin parameters if necessary PluginParameter { - name: "maplibre.map.style_urls" + name: "maplibre.map.styles" value: "https://demotiles.maplibre.org/style.json" } } diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 7d5e45d..538accb 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -49,7 +49,7 @@ target_sources( renderer_backend.cpp renderer_backend_p.hpp renderer_observer_p.hpp scheduler.cpp scheduler_p.hpp - settings.cpp + settings.cpp settings_p.hpp types.cpp utils.cpp ) diff --git a/src/core/map.cpp b/src/core/map.cpp index d17a8b5..7f6539e 100644 --- a/src/core/map.cpp +++ b/src/core/map.cpp @@ -128,10 +128,17 @@ mbgl::MapOptions mapOptionsFromSettings(const QMapLibre::Settings &settings, con } mbgl::ResourceOptions resourceOptionsFromSettings(const QMapLibre::Settings &settings) { + if (settings.tileServerOptions() == nullptr) { + return std::move(mbgl::ResourceOptions() + .withAssetPath(settings.assetPath().toStdString()) + .withCachePath(settings.cacheDatabasePath().toStdString()) + .withMaximumCacheSize(settings.cacheDatabaseMaximumSize())); + } + return std::move(mbgl::ResourceOptions() .withApiKey(settings.apiKey().toStdString()) .withAssetPath(settings.assetPath().toStdString()) - .withTileServerOptions(*settings.tileServerOptionsInternal()) + .withTileServerOptions(*settings.tileServerOptions()) .withCachePath(settings.cacheDatabasePath().toStdString()) .withMaximumCacheSize(settings.cacheDatabaseMaximumSize())); } @@ -1236,14 +1243,6 @@ void Map::connectionEstablished() { mbgl::NetworkStatus::Reachable(); } -/*! - Returns a list containing a pair of string objects, representing the style - URL and name, respectively. -*/ -const QVector> &Map::defaultStyles() const { - return d_ptr->defaultStyles; -} - /*! \fn void QMapLibre::Map::needsRendering() @@ -1303,11 +1302,6 @@ MapPrivate::MapPrivate(Map *q, const Settings &settings, const QSize &size, qrea connect(m_mapObserver.get(), &MapObserver::copyrightsChanged, q, &Map::copyrightsChanged); auto resourceOptions = resourceOptionsFromSettings(settings); - for (auto style : resourceOptions.tileServerOptions().defaultStyles()) { - defaultStyles.append( - QPair(QString::fromStdString(style.getUrl()), QString::fromStdString(style.getName()))); - } - auto clientOptions = clientOptionsFromSettings(settings); // Setup the Map object. diff --git a/src/core/map.hpp b/src/core/map.hpp index 25ee7dc..9602d92 100644 --- a/src/core/map.hpp +++ b/src/core/map.hpp @@ -169,8 +169,6 @@ class Q_MAPLIBRE_CORE_EXPORT Map : public QObject { void destroyRenderer(); void setFramebufferObject(quint32 fbo, const QSize &size); - const QVector> &defaultStyles() const; - public slots: void render(); void connectionEstablished(); diff --git a/src/core/map_p.hpp b/src/core/map_p.hpp index 83bfdbe..7aaf346 100644 --- a/src/core/map_p.hpp +++ b/src/core/map_p.hpp @@ -47,7 +47,6 @@ class MapPrivate : public QObject, public mbgl::RendererFrontend { mbgl::EdgeInsets margins; std::unique_ptr mapObj{}; - QVector> defaultStyles; public slots: void requestRendering(); diff --git a/src/core/settings.cpp b/src/core/settings.cpp index c240a01..e73d9c9 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -4,6 +4,7 @@ // SPDX-License-Identifier: BSD-2-Clause #include "settings.hpp" +#include "settings_p.hpp" #include #include @@ -12,6 +13,7 @@ #include #include +#include #ifdef _MSC_VER #pragma warning(push) @@ -143,18 +145,41 @@ namespace QMapLibre { /*! Constructs a Settings object with the default values. The default - configuration is valid for initializing a QMapLibre::Map. + configuration is not valid for initializing a \a QMapLibre::Map, + but a provider template can be provided. */ -Settings::Settings() - : m_contextMode(Settings::SharedGLContext), - m_mapMode(Settings::Continuous), - m_constrainMode(Settings::ConstrainHeightOnly), - m_viewportMode(Settings::DefaultViewport), - m_cacheMaximumSize(mbgl::util::DEFAULT_MAX_CACHE_SIZE), - m_cacheDatabasePath(":memory:"), - m_assetPath(QCoreApplication::applicationDirPath()), - m_apiKey(qgetenv("MLN_API_KEY")), - m_tileServerOptionsInternal(new mbgl::TileServerOptions(mbgl::TileServerOptions::DefaultConfiguration())) {} +Settings::Settings(ProviderTemplate provider) + : d_ptr(new SettingsPrivate) { + d_ptr->setProviderTemplate(provider); +} + +Settings::~Settings() { + delete d_ptr; +} + +Settings::Settings(const Settings &s) + : d_ptr(new SettingsPrivate) { + *d_ptr = *s.d_ptr; +} + +Settings::Settings(Settings &&s) noexcept + : d_ptr(s.d_ptr) { + s.d_ptr = nullptr; +} + +Settings &Settings::operator=(const Settings &s) { + if (d_ptr != nullptr) delete d_ptr; + d_ptr = new SettingsPrivate; + *d_ptr = *s.d_ptr; + return *this; +} + +Settings &Settings::operator=(Settings &&s) noexcept { + if (d_ptr != nullptr) delete d_ptr; + d_ptr = s.d_ptr; + s.d_ptr = nullptr; + return *this; +} /*! Returns the OpenGL context mode. This is specially important when mixing @@ -163,14 +188,14 @@ Settings::Settings() By default, it is set to Settings::SharedGLContext. */ Settings::GLContextMode Settings::contextMode() const { - return m_contextMode; + return d_ptr->m_contextMode; } /*! Sets the OpenGL context \a mode. */ void Settings::setContextMode(GLContextMode mode) { - m_contextMode = mode; + d_ptr->m_contextMode = mode; } /*! @@ -186,14 +211,14 @@ void Settings::setContextMode(GLContextMode mode) { By default, it is set to QMapLibre::Settings::Continuous. */ Settings::MapMode Settings::mapMode() const { - return m_mapMode; + return d_ptr->m_mapMode; } /*! Sets the map \a mode. */ void Settings::setMapMode(MapMode mode) { - m_mapMode = mode; + d_ptr->m_mapMode = mode; } /*! @@ -203,14 +228,14 @@ void Settings::setMapMode(MapMode mode) { By default, it is set to QMapLibre::Settings::ConstrainHeightOnly. */ Settings::ConstrainMode Settings::constrainMode() const { - return m_constrainMode; + return d_ptr->m_constrainMode; } /*! Sets the map constrain \a mode. */ void Settings::setConstrainMode(ConstrainMode mode) { - m_constrainMode = mode; + d_ptr->m_constrainMode = mode; } /*! @@ -220,14 +245,14 @@ void Settings::setConstrainMode(ConstrainMode mode) { By default, it is set to QMapLibre::Settings::DefaultViewport. */ Settings::ViewportMode Settings::viewportMode() const { - return m_viewportMode; + return d_ptr->m_viewportMode; } /*! Sets the viewport \a mode. */ void Settings::setViewportMode(ViewportMode mode) { - m_viewportMode = mode; + d_ptr->m_viewportMode = mode; } /*! @@ -239,14 +264,14 @@ void Settings::setViewportMode(ViewportMode mode) { By default, it is set to 50 MB. */ unsigned Settings::cacheDatabaseMaximumSize() const { - return m_cacheMaximumSize; + return d_ptr->m_cacheMaximumSize; } /*! Returns the maximum allowed cache database \a size in bytes. */ void Settings::setCacheDatabaseMaximumSize(unsigned size) { - m_cacheMaximumSize = size; + d_ptr->m_cacheMaximumSize = size; } /*! @@ -260,7 +285,7 @@ void Settings::setCacheDatabaseMaximumSize(unsigned size) { cache instead of a file on disk. */ QString Settings::cacheDatabasePath() const { - return m_cacheDatabasePath; + return d_ptr->m_cacheDatabasePath; } /*! @@ -269,7 +294,7 @@ QString Settings::cacheDatabasePath() const { Setting the \a path to \c :memory: will create an in-memory cache. */ void Settings::setCacheDatabasePath(const QString &path) { - m_cacheDatabasePath = path; + d_ptr->m_cacheDatabasePath = path; } /*! @@ -281,14 +306,14 @@ void Settings::setCacheDatabasePath(const QString &path) { By default, it is set to the value returned by QCoreApplication::applicationDirPath(). */ QString Settings::assetPath() const { - return m_assetPath; + return d_ptr->m_assetPath; } /*! Sets the asset \a path. */ void Settings::setAssetPath(const QString &path) { - m_assetPath = path; + d_ptr->m_assetPath = path; } /*! @@ -298,7 +323,7 @@ void Settings::setAssetPath(const QString &path) { or empty if the variable is not set. */ QString Settings::apiKey() const { - return m_apiKey; + return d_ptr->m_apiKey; } /*! @@ -308,14 +333,18 @@ QString Settings::apiKey() const { key or access token. */ void Settings::setApiKey(const QString &key) { - m_apiKey = key; + d_ptr->m_apiKey = key; } /*! Returns the API base URL. */ QString Settings::apiBaseUrl() const { - return QString::fromStdString(m_tileServerOptionsInternal->baseURL()); + if (tileServerOptions() == nullptr) { + return {}; + } + + return QString::fromStdString(tileServerOptions()->baseURL()); } /*! @@ -326,14 +355,14 @@ QString Settings::apiBaseUrl() const { changed, for instance, to a tile cache server address. */ void Settings::setApiBaseUrl(const QString &url) { - m_tileServerOptionsInternal = &m_tileServerOptionsInternal->withBaseURL(url.toStdString()); + d_ptr->setProviderApiBaseUrl(url); } /*! Returns the local font family. Returns an empty string if no local font family is set. */ QString Settings::localFontFamily() const { - return m_localFontFamily; + return d_ptr->m_localFontFamily; } /*! @@ -345,42 +374,42 @@ QString Settings::localFontFamily() const { instead of font data fetched from the server. */ void Settings::setLocalFontFamily(const QString &family) { - m_localFontFamily = family; + d_ptr->m_localFontFamily = family; } /*! Returns the client name. Returns an empty string if no client name is set. */ QString Settings::clientName() const { - return m_clientName; + return d_ptr->m_clientName; } /*! Sets the client name. */ void Settings::setClientName(const QString &name) { - m_clientName = name; + d_ptr->m_clientName = name; } /*! Returns the client version. Returns an empty string if no client version is set. */ QString Settings::clientVersion() const { - return m_clientVersion; + return d_ptr->m_clientVersion; } /*! Sets the client version. */ void Settings::setClientVersion(const QString &version) { - m_clientVersion = version; + d_ptr->m_clientVersion = version; } /*! Returns resource transformation callback used to transform requested URLs. */ std::function Settings::resourceTransform() const { - return m_resourceTransform; + return d_ptr->m_resourceTransform; } /*! @@ -392,7 +421,7 @@ std::function Settings::resourceTransform() co servers or endpoints. */ void Settings::setResourceTransform(const std::function &transform) { - m_resourceTransform = transform; + d_ptr->m_resourceTransform = transform; } /*! @@ -403,36 +432,120 @@ void Settings::setResourceTransform(const std::functionsetProviderTemplate(providerTemplate); } /*! - All predefined styles. + Returns the map styles set by user. - Return all styles that are defined in default settings. + The styles are a list type \c QMapLibre::Style. Each style is a pair + of URL and name/label. */ -QVector> Settings::defaultStyles() const { - QVector> styles; - for (const auto &style : tileServerOptionsInternal()->defaultStyles()) { - styles.append( - QPair(QString::fromStdString(style.getUrl()), QString::fromStdString(style.getName()))); +const Styles &Settings::styles() const { + return d_ptr->m_styles; +} + +/*! + Sets the map styles. + + The styles are a list type \c QMapLibre::Style. Each style is a pair + of URL and name/label. +*/ +void Settings::setStyles(const Styles &styles) { + d_ptr->m_styles = styles; +} + +/*! + All predefined provider styles. + + Return all styles that are defined in provider settings template. +*/ +Styles Settings::providerStyles() const { + Styles styles; + if (tileServerOptions() == nullptr) { + return styles; + } + + for (const auto &style : tileServerOptions()->defaultStyles()) { + styles.append(Style(QString::fromStdString(style.getUrl()), QString::fromStdString(style.getName()))); } return styles; } -mbgl::TileServerOptions *Settings::tileServerOptionsInternal() const { - return m_tileServerOptionsInternal; +/*! + Returns the default coordinate. +*/ +Coordinate Settings::defaultCoordinate() const { + return d_ptr->m_defaultCoordinate; +} + +/*! + Sets the default coordinate. +*/ +void Settings::setDefaultCoordinate(const Coordinate &coordinate) { + d_ptr->m_defaultCoordinate = coordinate; +} + +/*! + Returns the default zoom level. +*/ +double Settings::defaultZoom() const { + return d_ptr->m_defaultZoom; +} + +/*! + Sets the default zoom level. +*/ +void Settings::setDefaultZoom(double zoom) { + d_ptr->m_defaultZoom = zoom; +} + +/*! + Returns the provider tile server options. + + Note that this is mainly for internal use. +*/ +mbgl::TileServerOptions *Settings::tileServerOptions() const { + return d_ptr->m_tileServerOptions; +} + +// Private implementation +SettingsPrivate::SettingsPrivate() + : m_contextMode(Settings::SharedGLContext), + m_mapMode(Settings::Continuous), + m_constrainMode(Settings::ConstrainHeightOnly), + m_viewportMode(Settings::DefaultViewport), + m_providerTemplate(Settings::NoProvider), + m_cacheMaximumSize(mbgl::util::DEFAULT_MAX_CACHE_SIZE), + m_cacheDatabasePath(":memory:"), + m_assetPath(QCoreApplication::applicationDirPath()), + m_apiKey(qgetenv("MLN_API_KEY")) {} + +void SettingsPrivate::setProviderTemplate(Settings::ProviderTemplate providerTemplate) { + if (m_tileServerOptions) { + delete m_tileServerOptions; + m_tileServerOptions = nullptr; + } + + m_providerTemplate = providerTemplate; + + if (providerTemplate == Settings::MapLibreProvider) { + m_tileServerOptions = new mbgl::TileServerOptions(mbgl::TileServerOptions::MapLibreConfiguration()); + } else if (providerTemplate == Settings::MapTilerProvider) { + m_tileServerOptions = new mbgl::TileServerOptions(mbgl::TileServerOptions::MapTilerConfiguration()); + } else if (providerTemplate == Settings::MapboxProvider) { + m_tileServerOptions = new mbgl::TileServerOptions(mbgl::TileServerOptions::MapboxConfiguration()); + } +} + +void SettingsPrivate::setProviderApiBaseUrl(const QString &url) { + if (m_tileServerOptions == nullptr) { + qWarning() << "No provider set so not setting API URL."; + return; + } + + m_tileServerOptions = &m_tileServerOptions->withBaseURL(url.toStdString()); } } // namespace QMapLibre diff --git a/src/core/settings.hpp b/src/core/settings.hpp index 51002df..f30b690 100644 --- a/src/core/settings.hpp +++ b/src/core/settings.hpp @@ -7,6 +7,7 @@ #define QMAPLIBRE_SETTINGS_H #include +#include #include #include @@ -20,10 +21,10 @@ class TileServerOptions; namespace QMapLibre { +class SettingsPrivate; + class Q_MAPLIBRE_CORE_EXPORT Settings { public: - Settings(); - enum GLContextMode { UniqueGLContext = 0, SharedGLContext @@ -45,13 +46,20 @@ class Q_MAPLIBRE_CORE_EXPORT Settings { FlippedYViewport }; - enum SettingsTemplate { - DefaultSettings = 0, - MapLibreSettings, - MapTilerSettings, - MapboxSettings + enum ProviderTemplate { + NoProvider = 0, + MapLibreProvider, + MapTilerProvider, + MapboxProvider }; + explicit Settings(ProviderTemplate provider = NoProvider); + ~Settings(); + Settings(const Settings &); + Settings(Settings &&) noexcept; + Settings &operator=(const Settings &); + Settings &operator=(Settings &&) noexcept; + GLContextMode contextMode() const; void setContextMode(GLContextMode); @@ -91,28 +99,21 @@ class Q_MAPLIBRE_CORE_EXPORT Settings { std::function resourceTransform() const; void setResourceTransform(const std::function &); - void resetToTemplate(SettingsTemplate); + void setProviderTemplate(ProviderTemplate); + void setStyles(const Styles &styles); + + const Styles &styles() const; + Styles providerStyles() const; - QVector> defaultStyles() const; + Coordinate defaultCoordinate() const; + void setDefaultCoordinate(const Coordinate &); + double defaultZoom() const; + void setDefaultZoom(double); - mbgl::TileServerOptions *tileServerOptionsInternal() const; + mbgl::TileServerOptions *tileServerOptions() const; private: - GLContextMode m_contextMode; - MapMode m_mapMode; - ConstrainMode m_constrainMode; - ViewportMode m_viewportMode; - - unsigned m_cacheMaximumSize; - QString m_cacheDatabasePath; - QString m_assetPath; - QString m_apiKey; - QString m_localFontFamily; - QString m_clientName; - QString m_clientVersion; - std::function m_resourceTransform; - - mbgl::TileServerOptions *m_tileServerOptionsInternal{}; + SettingsPrivate *d_ptr; }; } // namespace QMapLibre diff --git a/src/core/settings_p.hpp b/src/core/settings_p.hpp new file mode 100644 index 0000000..20ee672 --- /dev/null +++ b/src/core/settings_p.hpp @@ -0,0 +1,53 @@ +// Copyright (C) 2023 MapLibre contributors +// Copyright (C) 2019 Mapbox, Inc. + +// SPDX-License-Identifier: BSD-2-Clause + +#pragma once + +#include "settings.hpp" +#include "types.hpp" + +#include +#include + +#include + +namespace mbgl { +class TileServerOptions; +} + +namespace QMapLibre { + +class SettingsPrivate { +public: + SettingsPrivate(); + + void setProviderTemplate(Settings::ProviderTemplate providerTemplate); + void setProviderApiBaseUrl(const QString &url); + + Settings::GLContextMode m_contextMode; + Settings::MapMode m_mapMode; + Settings::ConstrainMode m_constrainMode; + Settings::ViewportMode m_viewportMode; + Settings::ProviderTemplate m_providerTemplate; + + unsigned m_cacheMaximumSize; + QString m_cacheDatabasePath; + QString m_assetPath; + QString m_apiKey; + QString m_localFontFamily; + QString m_clientName; + QString m_clientVersion; + + Coordinate m_defaultCoordinate{}; + double m_defaultZoom{}; + + Styles m_styles; + + std::function m_resourceTransform; + + mbgl::TileServerOptions *m_tileServerOptions{}; +}; + +} // namespace QMapLibre diff --git a/src/core/types.hpp b/src/core/types.hpp index 070f0bd..becfbd5 100644 --- a/src/core/types.hpp +++ b/src/core/types.hpp @@ -25,6 +25,35 @@ typedef QVector CoordinatesCollection; typedef QVector CoordinatesCollections; +struct Q_MAPLIBRE_CORE_EXPORT Style { + enum Type { // Taken from Qt to be in sync with QtLocation + NoMap = 0, + StreetMap, + SatelliteMapDay, + SatelliteMapNight, + TerrainMap, + HybridMap, + TransitMap, + GrayStreetMap, + PedestrianMap, + CarNavigationMap, + CycleMap, + CustomMap = 100 + }; + + Style(const QString &url_, const QString &name_ = QString()) + : url(url_), + name(name_) {} + + QString url; + QString name; + QString description; + bool night{}; + Type type{CustomMap}; +}; + +typedef QVector