1 /** 2 * @fileOverview 3 * Copyright (c) 2013 Regione Autonoma della Sardegna 4 * Published under the GPL license.<br> 5 * See <a href="https://sardegnageoportale.it/webgis/license.txt">https://sardegnageoportale.it/webgis/license.txt</a> 6 * for the full text of the license. 7 * @version 0.1 8 */ 9 10 /** 11 * @namespace framework.widgets.search 12 */ 13 Ext.namespace("framework.widgets.search"); 14 15 /** api: (define) 16 * module = framework.widgets.search 17 * class = LayersGridPanel 18 * base_link = `Ext.Panel <http://dev.sencha.com/deploy/ext-3.3.1/docs/?class=Ext.Panel>`_ 19 */ 20 21 22 /** 23 * A Panel designed to hold a Ext.grid.GridPanel. It makes layers search by custom parameters. 24 * @name_ LayersGridPanel 25 * @class A Panel designed to hold a Ext.grid.GridPanel. It makes layers search by custom parameters. 26 * @constructor 27 @extends <a target="_blank" href="http://docs.sencha.com/extjs/3.4.0/#!/api/Ext.Panel">Ext.Panel</a> 28 */ 29 framework.widgets.search.LayersGridPanel = Ext.extend(Ext.Panel, 30 /** 31 * @lends framework.widgets.search.LayersGridPanel.prototype 32 */ 33 { 34 /** api: title 35 * 36 * Default title of the panel. If not set 37 * the value ``Feature Info`` will be used. 38 * @public 39 * @type String 40 */ 41 title: null, 42 /** api: config[infoFormat] 43 * 44 * Default GFI INFO_FORMAT parameter, may be overruled per Layer object infoFormat WMS param. If not set 45 * the value ``application/vnd.ogc.gml`` will be used. 46 * @public 47 * @type String 48 */ 49 infoFormat: 'application/vnd.ogc.gml', 50 /** Internal vars */ 51 /** api: config[map] 52 * 53 * A configured map or a configuration object 54 * @public 55 * @type OpenLayers.Map or Object 56 */ 57 map: null, 58 /** Init the component creating a store and object'events. 59 * @private 60 */ 61 initComponent: function() { 62 63 Ext.apply(this, { 64 layout: "fit" 65 }); 66 67 this.loadNum = 0; 68 69 this.format = new OpenLayers.Format.WMSGetFeatureInfo(); 70 71 this.display = this.displayGrid; 72 73 this.grid = new Ext.grid.GridPanel({ 74 store: new Ext.data.ArrayStore({ 75 fields: [ 76 {name: 'id'}, 77 {name: 'progressivo'}, 78 {name: 'nome'}, 79 {name: 'metadato'}, 80 {name: 'anno'}, 81 {name: 'tipologia'}, 82 {name: 'selectedLayer'}, 83 {name: 'note'} 84 ], 85 data: [], 86 listeners: { 87 update: function(obj, record, operation) { 88 if (record.data.selectedLayer == true) { 89 90 var cqlFilter = this.searchLayerFilterGeometry?"INTERSECTS(SHAPE," + this.map.boundRicerca + ")":null; 91 var layer = new OpenLayers.Layer.WMS(record.data.nome, 92 this.geoServerUrl + 'wms', 93 { 94 LAYERS: this.workspaceGeoServer + ':' + record.data.id, 95 STYLES: '', 96 format: "image/png", 97 transparent: true, 98 tiled: true, 99 INFO_FORMAT: this.infoFormat, 100 visibility: true 101 , cql_filter: cqlFilter 102 }, 103 { 104 tileOptions: {maxGetUrlLength: 2048}, 105 isBaseLayer: false 106 } 107 ); 108 layer.tipologia = record.data.tipologia; 109 layer.metadato = record.data.metadato; 110 layer.anno = record.data.anno; 111 layer.note = record.data.note; 112 if (!this.loadingLayer) { 113 this.loadingLayer = new Ext.LoadMask( 114 this.map.div, { 115 msg: 'caricamento ...' 116 } 117 ); 118 } 119 120 layer.events.register('loadstart', this, function() { 121 this.loadingLayer.show(); 122 }); 123 layer.events.register('loadend', this, function() { 124 this.loadingLayer.hide(); 125 }); 126 this.map.addLayer(layer); 127 this.layersSearchOnMap[record.data.id] = layer; 128 } else { 129 this.map.removeLayer(this.layersSearchOnMap[record.data.id]); 130 delete this.layersSearchOnMap[record.data.id]; 131 } 132 // attiva/disattiva il controllo getFeatureInfo 133 if (Object.keys(this.layersSearchOnMap).length == 1) { 134 Ext.getCmp(this.btnGetFeatureInfo).toggle(true); 135 this.layerShadowExtent.removeAllFeatures({silent: true}); 136 if (window.popupAddr) { 137 window.popupAddr.close(); 138 window.popupAddr.destroy(); 139 delete window.popupAddr; 140 } 141 } else if (Object.keys(this.layersSearchOnMap).length == 0) { 142 Ext.getCmp(this.btnGetFeatureInfo).toggle(false); 143 } 144 }, scope: this 145 } 146 }), 147 colModel: new Ext.grid.ColumnModel({ 148 defaults: { 149 width: 120, 150 sortable: true 151 }, 152 columns: [ 153 {id: 'id', width: 20, sortable: true, dataIndex: 'progressivo'}, 154 {description: 'description', header: 'Nome', sortable: true, dataIndex: 'nome'}, 155 {xtype: 'checkcolumn', header: 'Select', width: 25, dataIndex: 'selectedLayer', father: this} 156 ] 157 }), 158 viewConfig: { 159 forceFit: true 160 }, 161 sm: new Ext.grid.RowSelectionModel({singleSelect: true}), 162 preventBodyReset: true, 163 autoScroll: true, 164 autoWidth: true, 165 autoHeight: true, 166 frame: true, 167 title: 'Ricerca', 168 iconCls: 'icon-grid' 169 }); 170 171 this.noResultPanel = new Ext.Panel({ 172 html: '<div class="hr-html-panel-body"><pre>Nessun layer trovato!</pre></div>', 173 title: 'Ricerca', 174 preventBodyReset: true, 175 autoScroll: true, 176 hidden: true 177 }); 178 179 this.items = [this.grid, this.noResultPanel]; 180 181 182 183 framework.widgets.search.LayersGridPanel.superclass.initComponent.call(this); 184 185 if (!this.map) 186 this.map = this.target.mapPanel.map; 187 }, 188 /** Create a query string for the wfs call 189 * @private 190 */ 191 buildWMSOptions: function(productType, yearFrom, yearTo) { 192 var params = {}; 193 var cqlFilter = ''; 194 195 if (productType.length > 0) { 196 cqlFilter = "TIPOLOGIA='" + productType + "' AND "; 197 } 198 if (yearFrom != "") { 199 cqlFilter = cqlFilter + "ANNO >= " + yearFrom + " AND "; 200 } 201 if (yearTo != "") { 202 cqlFilter = cqlFilter + "ANNO <= " + yearTo + " AND "; 203 } 204 205 cqlFilter = cqlFilter + "INTERSECTS(SHAPE," + this.map.boundRicerca + ")"; 206 207 params["typename"] = this.layerShadow; 208 params["SERVICE"] = "WFS"; 209 params["VERSION"] = "1.0.0"; 210 params["REQUEST"] = "GetFeature"; 211 params["SRS"] = "3A3003"; 212 params["cql_filter"] = cqlFilter; 213 return params; 214 }, 215 /** execute layer search and fill a gridPanel with the result 216 * @public 217 * @param {String} productType type of product to search 218 * @param {Number} yearFrom search product for year 219 * @param {Number} yearTo search product to year 220 */ 221 searchFeature: function(productType, yearFrom, yearTo) { 222 var self = this; 223 var sUrl = ""; 224 if (this.proxy) 225 sUrl = this.proxy + escape(this.url); 226 else 227 sUrl = this.url; 228 //this.father.resultPanel.searchFeature(this.father.cmbProductType.getValue(),years[0],years[1]); 229 if (!this.busyMask) { 230 this.busyMask = new Ext.LoadMask( 231 this.map.div, { 232 msg: 'ricerca in corso ...' 233 } 234 ); 235 } 236 this.noResultPanel.hide(); 237 this.grid.hide(); 238 this.busyMask.show(); 239 Ext.Ajax.request({ 240 url: sUrl, 241 method: 'POST', 242 params: self.buildWMSOptions(productType, yearFrom, yearTo), 243 success: function(result, request) { 244 var features = self.format.read(result.responseText); 245 var evt = {}; 246 evt.features = features; 247 self.busyMask.hide(); 248 if (evt.features.length > 0) 249 self.displayGrid(evt); 250 else { 251 self.noResultPanel.show(); 252 } 253 }, 254 failure: function(result, request) { 255 self.busyMask.hide(); 256 alert('error in ajax request'); 257 } 258 }); 259 260 }, 261 /*** 262 * private: method[displayGrid] 263 * Fill up gridPanel with features in input 264 * @private 265 */ 266 displayGrid: function(evt) { 267 if (this.map.activeSearchPanel) { 268 this.map.activeSearchPanel.remove(this.map.activeSearchPanel.tabPanel); 269 } 270 this.map.activeSearchPanel = this; 271 272 Ext.getCmp(this.btnGetFeatureInfo).toggle(false); 273 274 this.removeLayersOldSearch(); 275 276 var data = []; 277 var objData = {}; 278 var productName = ''; 279 var productTitle = ''; 280 var count = 0; 281 for (var i = 0; i < evt.features.length; i++) { 282 productName = evt.features[i].attributes.PRODUCT; 283 if (evt.features[i].attributes.NOME) 284 productTitle = evt.features[i].attributes.NOME; 285 else 286 productTitle = productName; 287 if (!objData[productName]) { 288 objData[productName] = 'ok'; 289 data.push([productName, ++count, productTitle, evt.features[i].attributes.METADATO, evt.features[i].attributes.ANNO, evt.features[i].attributes.TIPOLOGIA, false, evt.features[i].attributes.NOTE]); 290 } 291 } 292 this.grid.store.loadData(data); 293 this.grid.show(); 294 295 }, 296 /*** 297 * private: method[removeLayersOldSearch] 298 * Clean the map from search layer 299 * @private 300 */ 301 removeLayersOldSearch: function() { 302 if (this.layersSearchOnMap) { 303 for (var layer in this.layersSearchOnMap) { 304 this.map.removeLayer(this.layersSearchOnMap[layer]); 305 } 306 } 307 this.map.events.triggerEvent('cleanSearchObjects'); 308 this.layersSearchOnMap = {}; 309 }, 310 /*** 311 * private: method[getPoligonMapExtent] 312 * Get a poligon query string from extent (OpenLayers.Bounds) 313 * @private 314 */ 315 getPoligonMapExtent: function() { 316 var extent = this.map.boundRicerca; 317 if (extent instanceof OpenLayers.Geometry.MultiPolygon || extent instanceof OpenLayers.Geometry.Polygon) { 318 return extent; 319 } 320 return extent.left + "," + extent.top + " " + extent.right + "," + extent.top + " " + extent.right + "," + extent.bottom + 321 " " + extent.left + "," + extent.bottom + " " + extent.left + "," + extent.top; 322 } 323 }) 324 325 /** api: xtype = framework_layersgridpanel */ 326 Ext.reg('framework_layersgridpanel', framework.widgets.search.LayersGridPanel); 327 328 329