From e7e489bce92ec6901b0d4b84c767ac8513d51ff9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Carrillo?= Date: Wed, 8 May 2024 17:47:39 +0200 Subject: [PATCH 1/7] [feature] Add locator filter to load Swiss vector tiles (basemaps) --- swiss_locator/core/filters/filter_type.py | 1 + .../core/filters/swiss_locator_filter.py | 42 +++++++++- .../swiss_locator_filter_vector_tiles.py | 82 +++++++++++++++++++ swiss_locator/core/results.py | 33 ++++++++ swiss_locator/core/settings.py | 8 ++ swiss_locator/swiss_locator_plugin.py | 4 + 6 files changed, 167 insertions(+), 3 deletions(-) create mode 100644 swiss_locator/core/filters/swiss_locator_filter_vector_tiles.py diff --git a/swiss_locator/core/filters/filter_type.py b/swiss_locator/core/filters/filter_type.py index 87f480c..aa9c59d 100644 --- a/swiss_locator/core/filters/filter_type.py +++ b/swiss_locator/core/filters/filter_type.py @@ -6,3 +6,4 @@ class FilterType(Enum): Layers = "layers" # this is used in map.geo.admin as the search type Feature = "featuresearch" # this is used in map.geo.admin as the search type WMTS = "wmts" + VectorTiles = "vectortiles" diff --git a/swiss_locator/core/filters/swiss_locator_filter.py b/swiss_locator/core/filters/swiss_locator_filter.py index e63ed66..11dbe98 100644 --- a/swiss_locator/core/filters/swiss_locator_filter.py +++ b/swiss_locator/core/filters/swiss_locator_filter.py @@ -43,6 +43,7 @@ QgsLocatorContext, QgsFeedback, QgsRasterLayer, + QgsVectorTileLayer, ) from qgis.gui import QgsRubberBand, QgisInterface @@ -53,6 +54,7 @@ WMSLayerResult, LocationResult, FeatureResult, + VectorTilesLayerResult, NoResult, ) from swiss_locator.core.settings import Settings @@ -74,6 +76,8 @@ def result_from_data(result: QgsLocatorResult): return LocationResult.from_dict(dict_data) if dict_data["type"] == "FeatureResult": return FeatureResult.from_dict(dict_data) + if dict_data["type"] == "VectorTilesLayerResult": + return VectorTilesLayerResult.from_dict(dict_data) return NoResult() @@ -384,7 +388,7 @@ def triggerResult(self, result: QgsLocatorResult): url_with_params = "&".join([f"{k}={v}" for (k, v) in params.items()]) self.info(f"Loading layer: {url_with_params}") - wms_layer = QgsRasterLayer(url_with_params, result.displayString, "wms") + vt_layer = QgsRasterLayer(url_with_params, result.displayString, "wms") label = QLabel() label.setTextFormat(Qt.RichText) label.setTextInteractionFlags(Qt.TextBrowserInteraction) @@ -399,7 +403,7 @@ def triggerResult(self, result: QgsLocatorResult): ) ) - if not wms_layer.isValid(): + if not vt_layer.isValid(): msg = self.tr( "Cannot load Layers layer: {} ({})".format( swiss_result.title, swiss_result.layer @@ -415,7 +419,7 @@ def triggerResult(self, result: QgsLocatorResult): ) level = Qgis.Info - QgsProject.instance().addMapLayer(wms_layer) + QgsProject.instance().addMapLayer(vt_layer) self.message_emitted.emit(self.displayName(), msg, level, label) @@ -427,6 +431,38 @@ def triggerResult(self, result: QgsLocatorResult): if self.settings.value("show_map_tip"): self.show_map_tip(swiss_result.layer, swiss_result.feature_id, point) + # Vector tiles + elif type(swiss_result) == VectorTilesLayerResult: + params = dict() + params["styleUrl"] = swiss_result.style or "" + params["url"] = swiss_result.url + params["type"] = "xyz" + params["zmax"] = "14" + params["zmin"] = "0" + + url_with_params = "&".join([f"{k}={v}" for (k, v) in params.items()]) + + self.info(f"Loading layer: {url_with_params}") + vt_layer = QgsVectorTileLayer(url_with_params, result.displayString) + + if not vt_layer.isValid(): + msg = self.tr( + "Cannot load Vector Tiles layer: {}".format( + swiss_result.title + ) + ) + level = Qgis.Warning + self.info(msg, level) + else: + msg = self.tr( + "Layer added to the map: {}".format( + swiss_result.title + ) + ) + level = Qgis.Info + + QgsProject.instance().addMapLayer(vt_layer) + # Location else: point = QgsGeometry.fromPointXY(swiss_result.point) diff --git a/swiss_locator/core/filters/swiss_locator_filter_vector_tiles.py b/swiss_locator/core/filters/swiss_locator_filter_vector_tiles.py new file mode 100644 index 0000000..2f946fd --- /dev/null +++ b/swiss_locator/core/filters/swiss_locator_filter_vector_tiles.py @@ -0,0 +1,82 @@ +from qgis.PyQt.QtCore import QUrl +from qgis.PyQt.QtNetwork import QNetworkRequest + +from qgis.gui import QgisInterface +from qgis.core import ( + QgsApplication, + QgsBlockingNetworkRequest, + QgsFetchedContent, + QgsLocatorResult, + QgsFeedback, +) +from swiss_locator.core.filters.swiss_locator_filter import ( + SwissLocatorFilter, +) +from swiss_locator.core.filters.filter_type import FilterType +from swiss_locator.core.results import VectorTilesLayerResult + +import xml.etree.ElementTree as ET +import urllib.parse + + +class SwissLocatorFilterVectorTiles(SwissLocatorFilter): + def __init__(self, iface: QgisInterface = None, crs: str = None): + super().__init__(FilterType.VectorTiles, iface, crs) + + def clone(self): + return SwissLocatorFilterVectorTiles(crs=self.crs) + + def displayName(self): + return self.tr("Swiss Geoportal Vector Tile Layers") + + def prefix(self): + return "chb" + + def hasConfigWidget(self): + return False + + def perform_fetch_results(self, search: str, feedback: QgsFeedback): + data = { + "base map": { + "title": "Base map", + "description": "", + "url": "https://vectortiles.geo.admin.ch/tiles/ch.swisstopo.base.vt/v1.0.0/{z}/{x}/{y}.pbf", + "style": "https://vectortiles.geo.admin.ch/styles/ch.swisstopo.basemap.vt/style.json" + }, + "light base map": { + "title": "Light base map", "description": "", + "url": "https://vectortiles.geo.admin.ch/tiles/ch.swisstopo.base.vt/v1.0.0/{z}/{x}/{y}.pbf", + "style": "https://vectortiles.geo.admin.ch/styles/ch.swisstopo.basemap.vt/style.json" + }, + "imagery base map": { + "title": "Imagery base map", "description": "", + "url": "https://vectortiles.geo.admin.ch/tiles/ch.swisstopo.base.vt/v1.0.0/{z}/{x}/{y}.pbf", + "style": "https://vectortiles.geo.admin.ch/styles/ch.swisstopo.basemap.vt/style.json" + } + } + + for keyword in list(data.keys()): + results = {} + score = 1 + if search in keyword: + result = QgsLocatorResult() + result.filter = self + #result.icon = QgsApplication.getThemeIcon("/mActionAddWmsLayer.svg") + + result.displayString = data[keyword]["title"] + result.description = data[keyword]["description"] + result.userData = VectorTilesLayerResult( + layer=data[keyword]["title"], + title=data[keyword]["title"], + url=data[keyword]["url"], + style=data[keyword]["style"], + ).as_definition() + + results[result] = score + + # sort the results with score + #results = sorted([result for (result, score) in results.items()]) + + for result in results: + self.resultFetched.emit(result) + self.result_found = True diff --git a/swiss_locator/core/results.py b/swiss_locator/core/results.py index 3cbc81e..1bdabb6 100644 --- a/swiss_locator/core/results.py +++ b/swiss_locator/core/results.py @@ -127,6 +127,39 @@ def as_definition(self): return json.dumps(definition) +class VectorTilesLayerResult: + def __init__( + self, + layer, + title, + url, + style: str = None, + ): + self.title = title + self.layer = layer + self.url = url + self.style = style + + @staticmethod + def from_dict(dict_data: dict): + return VectorTilesLayerResult( + dict_data["layer"], + dict_data["title"], + dict_data["url"], + style=dict_data.get("style"), + ) + + def as_definition(self): + definition = { + "type": "VectorTilesLayerResult", + "title": self.title, + "layer": self.layer, + "url": self.url, + "style": self.style, + } + return json.dumps(definition) + + class NoResult: def __init__(self): pass diff --git a/swiss_locator/core/settings.py b/swiss_locator/core/settings.py index c702cf9..c0550b3 100644 --- a/swiss_locator/core/settings.py +++ b/swiss_locator/core/settings.py @@ -74,6 +74,14 @@ def __init__(self): ) ) self.add_setting(Integer(f"{FilterType.WMTS.value}_limit", Scope.Global, 8)) + self.add_setting( + Enum( + f"{FilterType.VectorTiles.value}_priority", + Scope.Global, + QgsLocatorFilter.Medium, + ) + ) + self.add_setting(Integer(f"{FilterType.VectorTiles.value}_limit", Scope.Global, 8)) self.add_setting( Enum( f"{FilterType.Feature.value}_priority", diff --git a/swiss_locator/swiss_locator_plugin.py b/swiss_locator/swiss_locator_plugin.py index 29c9afc..9896152 100644 --- a/swiss_locator/swiss_locator_plugin.py +++ b/swiss_locator/swiss_locator_plugin.py @@ -33,6 +33,9 @@ SwissLocatorFilterLocation, ) from swiss_locator.core.filters.swiss_locator_filter_wmts import SwissLocatorFilterWMTS +from swiss_locator.core.filters.swiss_locator_filter_vector_tiles import ( + SwissLocatorFilterVectorTiles, +) class SwissLocatorPlugin: @@ -55,6 +58,7 @@ def initGui(self): SwissLocatorFilterLocation, SwissLocatorFilterWMTS, SwissLocatorFilterLayer, + SwissLocatorFilterVectorTiles, SwissLocatorFilterFeature, ): self.locator_filters.append(_filter(self.iface)) From 320b8985846d0f90da6c88d409f0a723952cd949 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Carrillo?= Date: Thu, 9 May 2024 14:39:04 +0200 Subject: [PATCH 2/7] Configure several vector tile layers and styles; load styles; load sublayers as grouped layers --- .../core/filters/swiss_locator_filter.py | 45 ++++++++++++++++++- .../swiss_locator_filter_vector_tiles.py | 16 +++++-- 2 files changed, 56 insertions(+), 5 deletions(-) diff --git a/swiss_locator/core/filters/swiss_locator_filter.py b/swiss_locator/core/filters/swiss_locator_filter.py index 11dbe98..4c89afa 100644 --- a/swiss_locator/core/filters/swiss_locator_filter.py +++ b/swiss_locator/core/filters/swiss_locator_filter.py @@ -439,7 +439,7 @@ def triggerResult(self, result: QgsLocatorResult): params["type"] = "xyz" params["zmax"] = "14" params["zmin"] = "0" - + url_with_params = "&".join([f"{k}={v}" for (k, v) in params.items()]) self.info(f"Loading layer: {url_with_params}") @@ -454,14 +454,55 @@ def triggerResult(self, result: QgsLocatorResult): level = Qgis.Warning self.info(msg, level) else: + vt_layer.setLabelsEnabled(True) + vt_layer.loadDefaultMetadata() + + error, warnings = '', [] + res, sublayers = vt_layer.loadDefaultStyleAndSubLayers(error, warnings) + + if sublayers: + msg = self.tr( + "Sublayers found ({}): {}".format( + swiss_result.title, + "; ".join([sublayer.name() for sublayer in sublayers]) + ) + ) + level = Qgis.Info + self.info(msg, level) + if error or warnings: + msg = self.tr( + "Error/warning found while loading default styles and sublayers for layer {}. Error: {} Warning: {}".format( + swiss_result.title, + error, + "; ".join(warnings) + ) + ) + level = Qgis.Warning + self.info(msg, level) + msg = self.tr( "Layer added to the map: {}".format( swiss_result.title ) ) level = Qgis.Info + self.info(msg, level) + + root = QgsProject.instance().layerTreeRoot() + if sublayers: + # Sublayers should load on top of the vector tiles layer + # We group them to keep them all together + group = root.insertGroup(-1, vt_layer.name()) + for sublayer in sublayers: + QgsProject.instance().addMapLayer(sublayer, False) + group.addLayer(sublayer) + + QgsProject.instance().addMapLayer(vt_layer, False) + group.addLayer(vt_layer) + else: + QgsProject.instance().addMapLayer(vt_layer, False) + root.insertLayer(-1, vt_layer) - QgsProject.instance().addMapLayer(vt_layer) # Location else: diff --git a/swiss_locator/core/filters/swiss_locator_filter_vector_tiles.py b/swiss_locator/core/filters/swiss_locator_filter_vector_tiles.py index 2f946fd..5e9da65 100644 --- a/swiss_locator/core/filters/swiss_locator_filter_vector_tiles.py +++ b/swiss_locator/core/filters/swiss_locator_filter_vector_tiles.py @@ -46,13 +46,23 @@ def perform_fetch_results(self, search: str, feedback: QgsFeedback): "light base map": { "title": "Light base map", "description": "", "url": "https://vectortiles.geo.admin.ch/tiles/ch.swisstopo.base.vt/v1.0.0/{z}/{x}/{y}.pbf", - "style": "https://vectortiles.geo.admin.ch/styles/ch.swisstopo.basemap.vt/style.json" + "style": "https://vectortiles.geo.admin.ch/styles/ch.swisstopo.lightbasemap.vt/style.json" }, "imagery base map": { "title": "Imagery base map", "description": "", "url": "https://vectortiles.geo.admin.ch/tiles/ch.swisstopo.base.vt/v1.0.0/{z}/{x}/{y}.pbf", - "style": "https://vectortiles.geo.admin.ch/styles/ch.swisstopo.basemap.vt/style.json" - } + "style": "https://vectortiles.geo.admin.ch/styles/ch.swisstopo.imagerybasemap.vt/style.json" + }, + "leichte-basiskarte": { + "title": "leichte-basiskarte", "description": "", + "url": "https://vectortiles.geo.admin.ch/tiles/ch.swisstopo.leichte-basiskarte.vt/v3.0.1/{z}/{x}/{y}.pbf", + "style": "https://vectortiles.geo.admin.ch/styles/ch.swisstopo.leichte-basiskarte.vt/style.json" + }, + "leichte-basiskarte-imagery": { + "title": "leichte-basiskarte-imagery", "description": "", + "url": "https://vectortiles.geo.admin.ch/tiles/ch.swisstopo.leichte-basiskarte.vt/v3.0.1/{z}/{x}/{y}.pbf", + "style": "https://vectortiles.geo.admin.ch/styles/ch.swisstopo.leichte-basiskarte-imagery.vt/style.json" + }, } for keyword in list(data.keys()): From 5b6f4cb5f575c19808133dbbbe1502c24d7af20b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Carrillo?= Date: Mon, 13 May 2024 08:52:43 -0500 Subject: [PATCH 3/7] Add icon for vector tiles (base maps) items, code cleanup --- swiss_locator/core/filters/swiss_locator_filter.py | 2 +- .../core/filters/swiss_locator_filter_vector_tiles.py | 8 +------- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/swiss_locator/core/filters/swiss_locator_filter.py b/swiss_locator/core/filters/swiss_locator_filter.py index 4c89afa..3d83579 100644 --- a/swiss_locator/core/filters/swiss_locator_filter.py +++ b/swiss_locator/core/filters/swiss_locator_filter.py @@ -488,6 +488,7 @@ def triggerResult(self, result: QgsLocatorResult): level = Qgis.Info self.info(msg, level) + # Load basemap layers at the bottom of the layer tree root = QgsProject.instance().layerTreeRoot() if sublayers: # Sublayers should load on top of the vector tiles layer @@ -503,7 +504,6 @@ def triggerResult(self, result: QgsLocatorResult): QgsProject.instance().addMapLayer(vt_layer, False) root.insertLayer(-1, vt_layer) - # Location else: point = QgsGeometry.fromPointXY(swiss_result.point) diff --git a/swiss_locator/core/filters/swiss_locator_filter_vector_tiles.py b/swiss_locator/core/filters/swiss_locator_filter_vector_tiles.py index 5e9da65..05c5115 100644 --- a/swiss_locator/core/filters/swiss_locator_filter_vector_tiles.py +++ b/swiss_locator/core/filters/swiss_locator_filter_vector_tiles.py @@ -1,6 +1,3 @@ -from qgis.PyQt.QtCore import QUrl -from qgis.PyQt.QtNetwork import QNetworkRequest - from qgis.gui import QgisInterface from qgis.core import ( QgsApplication, @@ -15,9 +12,6 @@ from swiss_locator.core.filters.filter_type import FilterType from swiss_locator.core.results import VectorTilesLayerResult -import xml.etree.ElementTree as ET -import urllib.parse - class SwissLocatorFilterVectorTiles(SwissLocatorFilter): def __init__(self, iface: QgisInterface = None, crs: str = None): @@ -71,7 +65,7 @@ def perform_fetch_results(self, search: str, feedback: QgsFeedback): if search in keyword: result = QgsLocatorResult() result.filter = self - #result.icon = QgsApplication.getThemeIcon("/mActionAddWmsLayer.svg") + result.icon = QgsApplication.getThemeIcon("/mActionAddVectorTileLayer.svg") result.displayString = data[keyword]["title"] result.description = data[keyword]["description"] From fbf7644f7967493adaf11ef0b605f95032e37015 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Carrillo?= Date: Mon, 13 May 2024 09:08:47 -0500 Subject: [PATCH 4/7] Vector tiles: accept search keywords with capital letters --- swiss_locator/core/filters/swiss_locator_filter_vector_tiles.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/swiss_locator/core/filters/swiss_locator_filter_vector_tiles.py b/swiss_locator/core/filters/swiss_locator_filter_vector_tiles.py index 05c5115..7b14a10 100644 --- a/swiss_locator/core/filters/swiss_locator_filter_vector_tiles.py +++ b/swiss_locator/core/filters/swiss_locator_filter_vector_tiles.py @@ -62,7 +62,7 @@ def perform_fetch_results(self, search: str, feedback: QgsFeedback): for keyword in list(data.keys()): results = {} score = 1 - if search in keyword: + if search.lower() in keyword: result = QgsLocatorResult() result.filter = self result.icon = QgsApplication.getThemeIcon("/mActionAddVectorTileLayer.svg") From 2498d268e05f8dec5892fa287552eb18df8c2575 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Carrillo?= Date: Tue, 14 May 2024 12:25:34 -0500 Subject: [PATCH 5/7] Address review for Vector Tiles support --- .../core/filters/swiss_locator_filter.py | 26 +++++++++---------- .../swiss_locator_filter_vector_tiles.py | 2 +- swiss_locator/core/settings.py | 2 +- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/swiss_locator/core/filters/swiss_locator_filter.py b/swiss_locator/core/filters/swiss_locator_filter.py index 3d83579..19976b7 100644 --- a/swiss_locator/core/filters/swiss_locator_filter.py +++ b/swiss_locator/core/filters/swiss_locator_filter.py @@ -388,7 +388,7 @@ def triggerResult(self, result: QgsLocatorResult): url_with_params = "&".join([f"{k}={v}" for (k, v) in params.items()]) self.info(f"Loading layer: {url_with_params}") - vt_layer = QgsRasterLayer(url_with_params, result.displayString, "wms") + ch_layer = QgsRasterLayer(url_with_params, result.displayString, "wms") label = QLabel() label.setTextFormat(Qt.RichText) label.setTextInteractionFlags(Qt.TextBrowserInteraction) @@ -403,7 +403,7 @@ def triggerResult(self, result: QgsLocatorResult): ) ) - if not vt_layer.isValid(): + if not ch_layer.isValid(): msg = self.tr( "Cannot load Layers layer: {} ({})".format( swiss_result.title, swiss_result.layer @@ -419,7 +419,7 @@ def triggerResult(self, result: QgsLocatorResult): ) level = Qgis.Info - QgsProject.instance().addMapLayer(vt_layer) + QgsProject.instance().addMapLayer(ch_layer) self.message_emitted.emit(self.displayName(), msg, level, label) @@ -443,9 +443,9 @@ def triggerResult(self, result: QgsLocatorResult): url_with_params = "&".join([f"{k}={v}" for (k, v) in params.items()]) self.info(f"Loading layer: {url_with_params}") - vt_layer = QgsVectorTileLayer(url_with_params, result.displayString) + ch_layer = QgsVectorTileLayer(url_with_params, result.displayString) - if not vt_layer.isValid(): + if not ch_layer.isValid(): msg = self.tr( "Cannot load Vector Tiles layer: {}".format( swiss_result.title @@ -454,11 +454,11 @@ def triggerResult(self, result: QgsLocatorResult): level = Qgis.Warning self.info(msg, level) else: - vt_layer.setLabelsEnabled(True) - vt_layer.loadDefaultMetadata() + ch_layer.setLabelsEnabled(True) + ch_layer.loadDefaultMetadata() error, warnings = '', [] - res, sublayers = vt_layer.loadDefaultStyleAndSubLayers(error, warnings) + res, sublayers = ch_layer.loadDefaultStyleAndSubLayers(error, warnings) if sublayers: msg = self.tr( @@ -493,16 +493,16 @@ def triggerResult(self, result: QgsLocatorResult): if sublayers: # Sublayers should load on top of the vector tiles layer # We group them to keep them all together - group = root.insertGroup(-1, vt_layer.name()) + group = root.insertGroup(-1, ch_layer.name()) for sublayer in sublayers: QgsProject.instance().addMapLayer(sublayer, False) group.addLayer(sublayer) - QgsProject.instance().addMapLayer(vt_layer, False) - group.addLayer(vt_layer) + QgsProject.instance().addMapLayer(ch_layer, False) + group.addLayer(ch_layer) else: - QgsProject.instance().addMapLayer(vt_layer, False) - root.insertLayer(-1, vt_layer) + QgsProject.instance().addMapLayer(ch_layer, False) + root.insertLayer(-1, ch_layer) # Location else: diff --git a/swiss_locator/core/filters/swiss_locator_filter_vector_tiles.py b/swiss_locator/core/filters/swiss_locator_filter_vector_tiles.py index 7b14a10..0ac1dd5 100644 --- a/swiss_locator/core/filters/swiss_locator_filter_vector_tiles.py +++ b/swiss_locator/core/filters/swiss_locator_filter_vector_tiles.py @@ -21,7 +21,7 @@ def clone(self): return SwissLocatorFilterVectorTiles(crs=self.crs) def displayName(self): - return self.tr("Swiss Geoportal Vector Tile Layers") + return self.tr("Swiss Geoportal Vector Tile Base Map Layers") def prefix(self): return "chb" diff --git a/swiss_locator/core/settings.py b/swiss_locator/core/settings.py index c0550b3..c2889a6 100644 --- a/swiss_locator/core/settings.py +++ b/swiss_locator/core/settings.py @@ -86,7 +86,7 @@ def __init__(self): Enum( f"{FilterType.Feature.value}_priority", Scope.Global, - QgsLocatorFilter.Medium, + QgsLocatorFilter.Highest, ) ) self.add_setting(Integer(f"{FilterType.Feature.value}_limit", Scope.Global, 8)) From 96081fc87dd47a39ba613f4d1185595fbbd3a84e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Carrillo?= Date: Wed, 15 May 2024 09:30:27 -0500 Subject: [PATCH 6/7] Address review: use addMapLayers() --- .../core/filters/swiss_locator_filter.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/swiss_locator/core/filters/swiss_locator_filter.py b/swiss_locator/core/filters/swiss_locator_filter.py index 19976b7..aa4a0e5 100644 --- a/swiss_locator/core/filters/swiss_locator_filter.py +++ b/swiss_locator/core/filters/swiss_locator_filter.py @@ -437,6 +437,9 @@ def triggerResult(self, result: QgsLocatorResult): params["styleUrl"] = swiss_result.style or "" params["url"] = swiss_result.url params["type"] = "xyz" + # Max and min zoom levels cound be retrieved from metadata JSON files like: + # https://vectortiles.geo.admin.ch/tiles/ch.swisstopo.base.vt/v1.0.0/tiles.json + # All Swiss services use 0-14 levels (level 14 goes up to buildings) params["zmax"] = "14" params["zmin"] = "0" @@ -491,15 +494,13 @@ def triggerResult(self, result: QgsLocatorResult): # Load basemap layers at the bottom of the layer tree root = QgsProject.instance().layerTreeRoot() if sublayers: - # Sublayers should load on top of the vector tiles layer - # We group them to keep them all together + # Sublayers should be loaded on top of the vector tile + # layer. We group them to keep them all together. group = root.insertGroup(-1, ch_layer.name()) - for sublayer in sublayers: - QgsProject.instance().addMapLayer(sublayer, False) - group.addLayer(sublayer) - - QgsProject.instance().addMapLayer(ch_layer, False) - group.addLayer(ch_layer) + all_layers = sublayers + [ch_layer] + QgsProject.instance().addMapLayers(all_layers, False) + for _layer in all_layers: + group.addLayer(_layer) else: QgsProject.instance().addMapLayer(ch_layer, False) root.insertLayer(-1, ch_layer) From 4631f047cb176a777ecc64c2233dbb8accadddf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Carrillo?= Date: Wed, 15 May 2024 09:39:21 -0500 Subject: [PATCH 7/7] Show available basemaps by selecting or entering the filter prefix (chb) and not requiring any search (searches are also supported anyways) --- .../core/filters/swiss_locator_filter_vector_tiles.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/swiss_locator/core/filters/swiss_locator_filter_vector_tiles.py b/swiss_locator/core/filters/swiss_locator_filter_vector_tiles.py index 0ac1dd5..cc8b937 100644 --- a/swiss_locator/core/filters/swiss_locator_filter_vector_tiles.py +++ b/swiss_locator/core/filters/swiss_locator_filter_vector_tiles.py @@ -17,6 +17,9 @@ class SwissLocatorFilterVectorTiles(SwissLocatorFilter): def __init__(self, iface: QgisInterface = None, crs: str = None): super().__init__(FilterType.VectorTiles, iface, crs) + # Show all available base maps without requiring a search + self.minimum_search_length = 0 + def clone(self): return SwissLocatorFilterVectorTiles(crs=self.crs) @@ -62,7 +65,7 @@ def perform_fetch_results(self, search: str, feedback: QgsFeedback): for keyword in list(data.keys()): results = {} score = 1 - if search.lower() in keyword: + if not search or search.lower() in keyword: result = QgsLocatorResult() result.filter = self result.icon = QgsApplication.getThemeIcon("/mActionAddVectorTileLayer.svg")