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

1from typing import Optional 

2 

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 

13 

14from . import provider 

15 

16gws.ext.new.layer('qgisflat') 

17 

18 

19class Config(gws.base.layer.Config): 

20 """Flat Qgis layer""" 

21 

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.""" 

28 

29 

30class Object(gws.base.layer.image.Object): 

31 serviceProvider: provider.Object 

32 sqlFilters: dict 

33 imageLayers: list[gws.SourceLayer] 

34 searchLayers: list[gws.SourceLayer] 

35 

36 def configure(self): 

37 self.sqlFilters = self.cfg('sqlFilters', default={}) 

38 self.configure_layer() 

39 

40 def configure_provider(self): 

41 return gws.config.util.configure_service_provider_for(self, provider.Object) 

42 

43 def configure_sources(self): 

44 if super().configure_sources(): 

45 return True 

46 

47 gws.u.require(self.serviceProvider, 'failed to configure service provider') 

48 

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) 

52 

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 ) 

60 

61 def configure_models(self): 

62 return gws.config.util.configure_models_for(self, with_default=True) 

63 

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 ) 

72 

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 

78 

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 

86 

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') 

93 

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 

104 

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 

120 

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 

127 

128 def configure_templates(self): 

129 return gws.config.util.configure_templates_for(self) 

130 

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 

137 

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 ) 

146 

147 ## 

148 

149 def get_render_params(self, lri: gws.LayerRenderInput, parent_sql_filters: dict=None) -> dict: 

150 params = dict(lri.extraParams or {}) 

151 

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)) 

155 

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) 

164 

165 return params 

166 

167 def render(self, lri): 

168 if lri.type != gws.LayerRenderInputType.box: 

169 return 

170 

171 params = self.get_render_params(lri) 

172 

173 def get_box(bounds, width, height): 

174 return self.serviceProvider.get_map(self, bounds, width, height, params) 

175 

176 content = gws.base.layer.util.generic_render_box(self, lri, get_box) 

177 return gws.LayerRenderOutput(content=content)