Coverage for gws-app/gws/plugin/qgis/flatlayer.py: 84%
110 statements
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-24 12:46 +0200
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-24 12:46 +0200
1from typing import Optional
3import gws
4import gws.base.layer
5import gws.config.util
6import gws.lib.crs
7import gws.lib.bounds
8import gws.lib.extent
9import gws.gis.source
10import gws.gis.zoom
11import gws.base.metadata
12import gws.lib.osx
14from . import provider
16gws.ext.new.layer('qgisflat')
19class Config(gws.base.layer.Config):
20 """Flat Qgis layer"""
22 provider: Optional[provider.Config]
23 """Qgis provider."""
24 sourceLayers: Optional[gws.gis.source.LayerFilter]
25 """Source layers to use."""
26 sqlFilters: Optional[dict]
27 """Per-layer sql filters."""
30class Object(gws.base.layer.image.Object):
31 serviceProvider: provider.Object
32 sqlFilters: dict
33 imageLayers: list[gws.SourceLayer]
34 searchLayers: list[gws.SourceLayer]
36 def configure(self):
37 self.sqlFilters = self.cfg('sqlFilters', default={})
38 self.configure_layer()
40 def configure_provider(self):
41 return gws.config.util.configure_service_provider_for(self, provider.Object)
43 def configure_sources(self):
44 if super().configure_sources():
45 return True
47 gws.u.require(self.serviceProvider, 'failed to configure service provider')
49 self.configure_source_layers()
50 self.imageLayers = gws.gis.source.filter_layers(self.sourceLayers, is_image=True)
51 self.searchLayers = gws.gis.source.filter_layers(self.sourceLayers, is_queryable=True)
53 def configure_source_layers(self):
54 return gws.config.util.configure_source_layers_for(
55 self,
56 self.serviceProvider.sourceLayers,
57 is_image=True,
58 is_visible=True,
59 )
61 def configure_models(self):
62 return gws.config.util.configure_models_for(self, with_default=True)
64 def create_model(self, cfg):
65 return self.create_child(
66 gws.ext.object.model,
67 cfg,
68 type='qgis',
69 _defaultProvider=self.serviceProvider,
70 _defaultSourceLayers=self.searchLayers,
71 )
73 def configure_bounds(self):
74 if super().configure_bounds():
75 return True
76 self.bounds = gws.lib.bounds.transform(self.serviceProvider.bounds, self.mapCrs)
77 return True
79 def configure_zoom_bounds(self):
80 if super().configure_zoom_bounds():
81 return True
82 b = gws.gis.source.combined_bounds(self.sourceLayers, self.mapCrs)
83 if b:
84 self.zoomBounds = b
85 return True
87 def configure_resolutions(self):
88 if super().configure_resolutions():
89 return True
90 self.resolutions = gws.gis.zoom.resolutions_from_source_layers(self.sourceLayers, self.cfg('_parentResolutions'))
91 if not self.resolutions:
92 raise gws.Error(f'layer {self.uid!r}: no matching resolutions')
94 def configure_grid(self):
95 if super().configure_grid():
96 return True
97 self.grid = gws.TileGrid(
98 origin=gws.Origin.nw,
99 tileSize=256,
100 bounds=self.bounds,
101 resolutions=self.resolutions,
102 )
103 return True
105 def configure_legend(self):
106 # cannot use super() here, because the config must be extended with defaults
107 if not self.cfg('withLegend'):
108 return True
109 cc = self.cfg('legend')
110 options = gws.u.merge(self.serviceProvider.defaultLegendOptions, cc.options if cc else {})
111 self.legend = self.create_child(
112 gws.ext.object.legend,
113 cc,
114 type='qgis',
115 options=options,
116 _defaultProvider=self.serviceProvider,
117 _defaultSourceLayers=self.imageLayers,
118 )
119 return True
121 def configure_metadata(self):
122 if super().configure_metadata():
123 return True
124 if len(self.sourceLayers) == 1:
125 self.metadata = self.sourceLayers[0].metadata
126 return True
128 def configure_templates(self):
129 return gws.config.util.configure_templates_for(self)
131 def configure_search(self):
132 if super().configure_search():
133 return True
134 if self.searchLayers:
135 self.finders.append(self.create_finder(None))
136 return True
138 def create_finder(self, cfg):
139 return self.create_child(
140 gws.ext.object.finder,
141 cfg,
142 type='qgis',
143 _defaultProvider=self.serviceProvider,
144 _defaultSourceLayers=self.searchLayers,
145 )
147 ##
149 def get_render_params(self, lri: gws.LayerRenderInput, parent_sql_filters: dict=None) -> dict:
150 params = dict(lri.extraParams or {})
152 layers = [sl.name for sl in self.imageLayers]
153 # NB reversed: see the note in plugin/ows_client/wms/provider.py
154 params['LAYERS'] = list(reversed(layers))
156 filters = []
157 sqlf = gws.u.merge({}, self.sqlFilters, parent_sql_filters)
158 for name in layers:
159 flt = sqlf.get(name) or sqlf.get('*')
160 if flt:
161 filters.append(name + ': ' + flt)
162 if filters:
163 params['FILTER'] = ';'.join(filters)
165 return params
167 def render(self, lri):
168 if lri.type != gws.LayerRenderInputType.box:
169 return
171 params = self.get_render_params(lri)
173 def get_box(bounds, width, height):
174 return self.serviceProvider.get_map(self, bounds, width, height, params)
176 content = gws.base.layer.util.generic_render_box(self, lri, get_box)
177 return gws.LayerRenderOutput(content=content)