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 /** 16 * A Panel designed to hold WMS GetFeatureInfo (GFI) data for one or more WMS layers. 17 * @name_ FeatureSearchGridPanel 18 * @class A Panel designed to hold WMS GetFeatureInfo (GFI) data for one or more WMS layers. 19 * @constructor 20 @extends <a target="_blank" href="http://docs.sencha.com/extjs/3.4.0/#!/api/Ext.grid.GridPanel">Ext.grid.GridPanel,</a> 21 */ 22 framework.widgets.search.FeatureSearchGridPanel = Ext.extend(Ext.grid.GridPanel, 23 /** 24 * @lends framework.widgets.search.FeatureSearchGridPanel.prototype 25 */ 26 { 27 /** api: config[downloadable] 28 * ``Boolean`` 29 * Should the features in the grid be downloadble? 30 * Download can be effected in 3 ways: 31 * 1. via Grid export (CSV and XLS only) 32 * 2. downloading the original feature format (GML2) 33 * 3. (GeoServer only) requesting the server for a triggered download (all Geoserver WFS formats), 34 * @public 35 * @type Boolean 36 */ 37 downloadable: true, 38 /** api: config[exportFormats] 39 * 40 * Array of document formats to be used when exporting the content of a GFI response. This requires the server-side CGI script 41 * ``heron.cgi`` to be installed. Exporting results in a download of a document with the contents of the (Grid) Panel. 42 * For example when 'XLS' is configured, exporting will result in the Excel (or compatible) program to be 43 * started with the GFI data in an Excel worksheet. 44 * Option values are 'CSV' and/or 'XLS', default is, ``null``, meaning no export (results in no export menu). 45 * The value ['CSV', 'XLS'] configures a menu to choose from a ``.csv`` or ``.xls`` export document format. 46 * @public 47 * @type [object] String Array 48 * */ 49 exportFormats: ['CSV', 'XLS', 'GMLv2', 'GeoJSON', 'WellKnownText'], 50 /** api: config[columnCapitalize] 51 * 52 * Should the column names be capitalized when autoconfig is true? 53 * @public 54 * @type Boolean 55 */ 56 columnCapitalize: true, 57 /** api: config[showTopToolbar] 58 * 59 * Should a top toolbar with feature count, clear button and download combo be shown? Default ``true``. 60 * @public 61 * @type Boolean 62 */ 63 showTopToolbar: true, 64 /** api: config[showGeometries] 65 * ``Boolean`` 66 * Should the feature geometries be shown? Default ``true``. 67 */ 68 showGeometries: true, 69 /** api: config[featureSelection] 70 * 71 * Should the feature geometries that are shown be selectable in grid and map? Default ``true``. 72 * @public 73 * @type Boolean 74 */ 75 featureSelection: true, 76 /** api: config[loadMask] 77 * 78 * @public 79 * @type Boolean 80 */ 81 loadMask: true, 82 /** api: config[bbar] 83 * 84 * @public 85 * @type Object Ext.PagingToolbar 86 */ 87 /* bbar: new Ext.PagingToolbar({ 88 pageSize: 25, 89 store: store, 90 displayInfo: true, 91 displayMsg: 'Displaying objects {0} - {1} of {2}', 92 emptyMsg: "No objects to display" 93 }),*/ 94 95 /** api: config[exportConfigs] 96 * 97 * The supported configs for formatting and exporting feature data. Actual presented download options 98 * are configured with exportFormats. 99 * @public 100 * @type Object 101 */ 102 exportConfigs: { 103 CSV: { 104 formatter: 'CSVFormatter', 105 fileExt: '.csv', 106 mimeType: 'text/csv' 107 }, 108 XLS: { 109 formatter: 'ExcelFormatter', 110 fileExt: '.xls', 111 mimeType: 'application/vnd.ms-excel' 112 }, 113 GMLv2: { 114 formatter: 'OpenLayersFormatter', 115 format: new OpenLayers.Format.GML.v2({featureType: 'heronfeat', featureNS: 'http://heron-mc.org'}), 116 fileExt: '.gml', 117 mimeType: 'text/xml' 118 }, 119 GeoJSON: { 120 formatter: 'OpenLayersFormatter', 121 format: 'OpenLayers.Format.GeoJSON', 122 fileExt: '.json', 123 mimeType: 'text/plain' 124 }, 125 WellKnownText: { 126 formatter: 'OpenLayersFormatter', 127 format: 'OpenLayers.Format.WKT', 128 fileExt: '.wkt', 129 mimeType: 'text/plain' 130 } 131 }, 132 /** api: config[separateSelectionLayer] 133 * 134 * Should selected features be managed in separate overlay Layer (handy for printing) ?. 135 * @public 136 * @type Boolean 137 */ 138 separateSelectionLayer: false, 139 /** api: config[zoomOnFeatureSelect] 140 * 141 * Zoom to feature (extent) when selected ?. 142 * @public 143 * @type Boolean 144 */ 145 zoomOnFeatureSelect: false, 146 /** api: config[zoomOnRowDoubleClick] 147 * 148 * Zoom to feature (extent) when row is double clicked ?. 149 * @public 150 * @type Boolean 151 */ 152 zoomOnRowDoubleClick: true, 153 /** api: config[zoomLevelPointSelect] 154 * 155 * Zoom level for point features when selected, default ``10``. 156 * @public 157 * @type Integer 158 */ 159 zoomLevelPointSelect: 10, 160 /** api: config[zoomLevelPoint] 161 * 162 * Zoom level when layer is single point feature, default ``10``. 163 * @public 164 * @type Integer 165 */ 166 zoomLevelPoint: 10, 167 /** api: config[zoomToDataExtent] 168 * 169 * Zoom to layer data extent when loaded ?. 170 * @public 171 * @type Boolean 172 */ 173 zoomToDataExtent: false, 174 /** api: config[autoConfig] 175 * 176 * Should the store and grid columns autoconfigure from loaded features?. 177 * @public 178 * @type Boolean 179 */ 180 autoConfig: true, 181 /** api: config[vectorLayerOptions] 182 * 183 * Options to be passed on Vector constructors. 184 * @public 185 * @type Object 186 */ 187 vectorLayerOptions: {noLegend: true, displayInLayerSwitcher: false}, 188 /** 189 * If it's true there will be added a button to perform "showAerialPhoto" event, 190 * otherwise it will be performed using double click on selected row. 191 * Default is true. 192 * @public 193 * @type boolean 194 */ 195 openOnButton: true, 196 197 /** api: config[cartPanel] 198 * 199 * id cart panel. 200 * @public 201 * @type String 202 */ 203 cartPanel: null, 204 /** api: config[basePathResources] 205 * 206 * path products resources 207 * @public 208 * @type String 209 */ 210 basePathResources: null, 211 /** api: config[managerProductPanel] 212 * 213 * id products panel 214 * @public 215 * @type String 216 */ 217 managerProductPanel: null, 218 /** api: config[urlGeoNetwork] 219 * 220 * Url goeNetwork 221 * @public 222 * @type String 223 */ 224 urlGeoNetwork: null, 225 /** 226 * Override init component 227 * @private 228 */ 229 initComponent: function() { 230 // If columns specified we don't do autoconfig (column guessing from features) 231 if (this.columns) { 232 this.autoConfig = false; 233 } 234 235 // specific config (besides GridPanel config) 236 Ext.apply(this, this.hropts); 237 238 // If we have feature selection enabled we must show geometries 239 if (this.featureSelection) { 240 this.showGeometries = true; 241 } 242 243 if (this.showGeometries) { 244 // Define OL Vector Layer to display search result features 245 var layer = this.layer = new OpenLayers.Layer.Vector(this.title, this.vectorLayerOptions); 246 247 if (!this.map) 248 this.map = this.target.mapPanel.map; 249 this.map.addLayer(this.layer); 250 251 var layerSelected = this.map.getLayersByName(this.layer.name)[0]; 252 this.metadato = layerSelected.metadato; 253 this.tipologia = layerSelected.tipologia; 254 this.anno = layerSelected.anno; 255 this.note = layerSelected.note; 256 this.hdd = layerSelected.hdd; 257 258 var self = this; 259 260 if (self.cartPanel) { 261 this.layer.events.on( 262 {featureselected: function(e) { 263 //create popup 264 self.currentFeature = e.feature; 265 self.cleanWindow(); 266 window.popupAddr = new GeoExt.Popup({ 267 //title: 'Ricerca indirizzo', 268 map: e.feature.layer.map, 269 location: e.feature, 270 father: self, 271 width: 320, 272 border: false, 273 maximizable: false, 274 collapsible: false, 275 resizable: false, 276 items: [ 277 {xtype: "label", 278 html: '<div class="popupAddr"><b>' + e.object.name + '</b><br>' + 279 'Foto <b>' + e.feature.attributes.IMAGE + '</b>' + 280 '<br><br><a href="' + self.metadato + '" target="_blank">Scheda metadato</a>' + 281 '<br><a href="#" onClick="Ext.getCmp(\'btnFireShowPhoto\').handler.call(Ext.getCmp(\'btnFireShowPhoto\').scope);">Anteprima</a>' + 282 '<br><br>Immagine in alta risoluzione' + 283 '<br><input type="text" value="' + self.getPathImageHR(e.feature.gml.featureType,e.feature.attributes.IMAGE,self.hdd) + '" readonly size="30"><br>' + 284 '</div>' 285 286 }, { 287 xtype: "button", 288 id: 'btnFireShowPhoto', 289 hidden: true, 290 margin: {left: '10px'}, 291 handler: function() { 292 self.showFoto(self.currentFeature.gml.featureType, self.currentFeature.data.IMAGE); 293 } 294 }, { 295 xtype: "button", 296 disabled:e.feature.attributes.IMAGE != null?false:true, 297 cls:'addToCartButton', 298 text: 'AGGIUNGI AL CARRELLO', 299 handler: function() { 300 var items = self.store.data.items; 301 var item; 302 for (var i = 0; i < items.length; i++) { 303 if (items[i].data.feature.id == self.currentFeature.id) { 304 if (items[i].data.onCart != true) { 305 self.store.getAt(i).set('onCart', true); 306 self.store.getAt(i).commit(); 307 } 308 return; 309 } 310 } 311 312 } 313 }, { 314 xtype: "button", 315 cls:'modifyProductButton', 316 hidden: (window.btnProdotti && window.btnProdotti.isVisible()) ? false : true, 317 text: 'MODIFICA PRODOTTO', 318 handler: function() { 319 if (window.btnProdotti && window.btnProdotti.isVisible()) { 320 window.btnProdotti.toggle(); 321 window.btnProdotti.handler.call(window.btnProdotti); 322 var productJson = {productId: self.currentFeature.gml.featureType, productName: self.title, productType: self.tipologia, productYear: self.anno, productSchedaMetadatoEsistente: true, productMetadata: self.metadato,productNote:self.note}; 323 Ext.getCmp(self.managerProductPanel).fireEvent("modifyProduct", productJson); 324 self.cleanWindow(); 325 } else 326 alert('Modifica non abilitata!'); 327 328 } 329 },{xtype: "label", 330 html:'<br><br><br>' 331 } 332 ] 333 } 334 335 ); 336 window.popupAddr.show(); 337 var winContent = self.ownerCt; 338 while(winContent.ownerCt){ 339 winContent = winContent.ownerCt; 340 } 341 winContent.setPosition(0,0); 342 }}, 343 {featureunselected: this.cleanWindow} 344 345 ) 346 } 347 348 if (this.featureSelection && this.zoomOnFeatureSelect) { 349 // See http://www.geoext.org/pipermail/users/2011-March/002052.html 350 layer.events.on({ 351 "featureselected": function(e) { 352 self.zoomToFeature(self, e.feature.geometry); 353 }, 354 "dblclick": function(e) { 355 self.zoomToFeature(self, e.feature.geometry); 356 }, 357 "scope": layer 358 }); 359 } 360 361 // May zoom to feature when grid row is double-clicked. 362 if (this.zoomOnRowDoubleClick) { 363 this.on('celldblclick', function(grid, rowIndex, columnIndex, e) { 364 var record = grid.getStore().getAt(rowIndex); 365 var feature = record.getFeature(); 366 self.zoomToFeature(self, feature.geometry); 367 if (!this.openOnButton) 368 //this.fireEvent('showAerialPhoto', record); 369 this.showFoto(''); 370 }); 371 } 372 373 if (this.separateSelectionLayer) { 374 this.selLayer = new OpenLayers.Layer.Vector(this.title + '_Sel', {noLegend: true, displayInLayerSwitcher: false}); 375 // selLayer.style = layer.styleMap.styles['select'].clone(); 376 this.selLayer.styleMap.styles['default'] = layer.styleMap.styles['select']; 377 this.selLayer.style = this.selLayer.styleMap.styles['default'].defaultStyle; 378 // this.selLayer.style = layer.styleMap.styles['select'].clone(); 379 layer.styleMap.styles['select'] = layer.styleMap.styles['default'].clone(); 380 layer.styleMap.styles['select'].defaultStyle.fillColor = 'white'; 381 layer.styleMap.styles['select'].defaultStyle.fillOpacity = 0.0; 382 this.map.addLayer(this.selLayer); 383 this.map.setLayerIndex(this.selLayer, this.map.layers.length - 1); 384 this.layer.events.on({ 385 featureselected: this.updateSelectionLayer, 386 featureunselected: this.updateSelectionLayer, 387 scope: this 388 }); 389 } 390 } 391 392 this.setupStore(this.features); 393 394 // Will take effort to support paging... 395 // http://dev.sencha.com/deploy/ext-3.3.1/examples/grid/paging.html 396 /* 397 this.bbar = new Ext.PagingToolbar({ 398 pageSize: 5, 399 store: this.store, 400 displayInfo: true, 401 displayMsg: 'Displaying objects {0} - {1} of {2}', 402 emptyMsg: "No objects to display" 403 }); 404 */ 405 406 407 // Enables the interaction between features on the Map and Grid 408 if (this.featureSelection && !this.sm) { 409 this.sm = new GeoExt.grid.FeatureSelectionModel(); 410 } 411 412 if (this.showTopToolbar) { 413 this.tbar = this.createTopToolbar(); 414 } 415 416 framework.widgets.search.FeatureSearchGridPanel.superclass.initComponent.call(this); 417 418 // ExtJS lifecycle events 419 this.addListener("afterrender", this.onPanelRendered, this); 420 this.addListener("show", this.onPanelShow, this); 421 this.addListener("hide", this.onPanelHide, this); 422 if (this.cartPanel) { 423 this.selModel.on("rowdeselect", this.cleanWindow) 424 } 425 }, 426 427 /** api: method[createTopToolbar] 428 * Create the top toolbar. 429 * @private 430 */ 431 createTopToolbar: function() { 432 433 // Top toolbar text, keep var for updating 434 var tbarItems = [this.tbarText = new Ext.Toolbar.TextItem({text: __(' ')})]; 435 tbarItems.push('->'); 436 437 if (this.downloadable) { 438 439 // Multiple display types configured: add toolbar tabs 440 // var downloadMenuItems = ['<b class="menu-title">' + __('Choose an Export Format') + '</b>']; 441 var downloadMenuItems = []; 442 var item; 443 for (var j = 0; j < this.exportFormats.length; j++) { 444 var exportFormat = this.exportFormats[j]; 445 item = { 446 text: __('as') + ' ' + exportFormat, 447 cls: 'x-btn', 448 iconCls: 'icon-table-export', 449 scope: this, 450 exportFormat: exportFormat, 451 handler: function(evt) { 452 this.exportData(evt.exportFormat); 453 } 454 }; 455 downloadMenuItems.push(item); 456 } 457 458 if (this.downloadInfo && this.downloadInfo.downloadFormats) { 459 var downloadFormats = this.downloadInfo.downloadFormats; 460 for (var k = 0; k < downloadFormats.length; k++) { 461 var downloadFormat = downloadFormats[k]; 462 item = { 463 text: __('as') + ' ' + downloadFormat.name, 464 cls: 'x-btn', 465 iconCls: 'icon-table-export', 466 downloadFormat: downloadFormat.outputFormat, 467 fileExt: downloadFormat.fileExt, 468 scope: this, 469 handler: function(evt) { 470 this.downloadData(evt.downloadFormat, evt.fileExt); 471 } 472 }; 473 downloadMenuItems.push(item); 474 } 475 } 476 477 if (downloadMenuItems.length > 0) { 478 /* Add to toolbar. */ 479 tbarItems.push({ 480 text: __('Download'), 481 cls: 'x-btn-text-icon', 482 iconCls: 'icon-table-save', 483 tooltip: __('Choose a Download Format'), 484 menu: new Ext.menu.Menu({ 485 style: { 486 overflow: 'visible' // For the Combo popup 487 }, 488 items: downloadMenuItems 489 }) 490 }); 491 } 492 } 493 494 tbarItems.push('->'); 495 tbarItems.push({ 496 text: __('Clear'), 497 cls: 'x-btn-text-icon', 498 iconCls: 'icon-table-clear', 499 tooltip: __('Remove all results'), 500 scope: this, 501 handler: function() { 502 this.removeFeatures(); 503 } 504 }); 505 506 return new Ext.Toolbar({enableOverflow: true, items: tbarItems}); 507 }, 508 /** api: method[loadFeatures] 509 * Loads array of feature objects in store and shows them on grid and map. 510 * @private 511 */ 512 loadFeatures: function(features, featureType) { 513 this.removeFeatures(); 514 this.featureType = featureType; 515 516 // Defensive programming 517 if (!features || features.length == 0) { 518 return; 519 } 520 521 this.showLayer(); 522 this.removeFeaturesDuplicates(); 523 this.store.loadData(features); 524 this.updateTbarText(); 525 526 // Whenever Paging is supported... 527 // http://dev.sencha.com/deploy/ext-3.3.1/examples/grid/paging.html 528 // this.store.load({params:{start:0, limit:25}}); 529 530 if (this.zoomToDataExtent) { 531 if (features.length == 1 && features[0].geometry.CLASS_NAME == "OpenLayers.Geometry.Point") { 532 var point = features[0].geometry.getCentroid(); 533 this.map.setCenter(new OpenLayers.LonLat(point.x, point.y), this.zoomLevelPoint); 534 } else if (this.layer) { 535 if (this.map.layersWithFeature) 536 this.map.layersWithFeature.push(this.layer); 537 var extent = this.layer.getDataExtent(); 538 if (this.father.searchExtent) { 539 this.father.searchExtent.extend(this.layer.getDataExtent()); 540 } else { 541 this.father.searchExtent = this.layer.getDataExtent(); 542 543 } 544 this.map.zoomToExtent(this.father.searchExtent); 545 } 546 } 547 }, 548 /** api: method[hasFeatures] 549 * Does this Panel have features?. 550 * @private 551 */ 552 removeFeaturesDuplicates: function(){ 553 var map = {}; 554 var array = []; 555 for(var i=0;i<this.features.length;i++){ 556 if(!map[this.features[i].attributes.IMAGE]){ 557 map[this.features[i].attributes.IMAGE] = 'ok'; 558 array.push(this.features[i]); 559 } 560 } 561 this.features = array; 562 }, 563 /** api: method[hasFeatures] 564 * Does this Panel have features?. 565 * @private 566 */ 567 hasFeatures: function() { 568 return this.store && this.store.getCount() > 0; 569 }, 570 /** api: method[removeFeatures] 571 * Removes all feature objects from store . 572 * @private 573 */ 574 removeFeatures: function() { 575 if (this.store) { 576 this.store.removeAll(false); 577 } 578 if (this.selLayer) { 579 this.selLayer.removeAllFeatures({silent: true}); 580 } 581 this.updateTbarText(); 582 }, 583 /** api: method[showLayer] 584 * Show the layer with features on the map. 585 * @private 586 */ 587 showLayer: function() { 588 // this.removeFeatures(); 589 if (this.layer) { 590 if (this.selLayer) { 591 this.map.setLayerIndex(this.selLayer, this.map.layers.length - 1); 592 this.map.setLayerIndex(this.layer, this.map.layers.length - 2); 593 } else { 594 this.map.setLayerIndex(this.layer, this.map.layers.length - 1); 595 } 596 if (!this.layer.getVisibility()) { 597 this.layer.setVisibility(true); 598 } 599 if (this.selLayer && !this.selLayer.getVisibility()) { 600 this.selLayer.setVisibility(true); 601 } 602 } 603 }, 604 /** api: method[hideLayer] 605 * Hide the layer with features on the map. 606 * @private 607 */ 608 hideLayer: function() { 609 // this.removeFeatures(); 610 if (this.layer && this.layer.getVisibility()) { 611 this.layer.setVisibility(false); 612 } 613 if (this.selLayer && this.selLayer.getVisibility()) { 614 this.selLayer.setVisibility(false); 615 } 616 this.cleanWindow(); 617 618 }, 619 /** api: method[hideLayer] 620 * Hide the layer with features on the map. 621 * @private 622 */ 623 zoomToFeature: function(self, geometry) { 624 if (!geometry) { 625 return; 626 } 627 628 // For point features center map otherwise zoom to geometry bounds 629 if (geometry.getVertices().length == 1) { 630 var point = geometry.getCentroid(); 631 self.map.setCenter(new OpenLayers.LonLat(point.x, point.y), self.zoomLevelPointSelect); 632 } else { 633 self.map.zoomToExtent(geometry.getBounds()); 634 } 635 }, 636 /** api: method[zoomButtonRenderer] 637 * 638 * @private 639 */ 640 zoomButtonRenderer: function() { 641 var id = Ext.id(); 642 643 (function() { 644 new Ext.Button({ 645 renderTo: id, 646 text: 'Zoom' 647 }); 648 649 }).defer(25); 650 651 return (String.format('<div id="{0}"></div>', id)); 652 }, 653 /** private: method[setupStore] 654 * :param features: ``Array`` optional features. 655 * @private 656 */ 657 setupStore: function(features) { 658 if (this.store && !this.autoConfig) { 659 return; 660 } 661 662 // Prepare fields array for store from columns in Grid config. 663 var storeFields = []; 664 if (this.autoConfig && features) { 665 this.columns = []; 666 if (features.length > 0) { 667 var feature = features[0]; 668 var fieldName; 669 for (fieldName in feature.attributes) { 670 var column; 671 // Capitalize header names 672 if (fieldName != 'onCart') { 673 column = { 674 header: this.columnCapitalize ? fieldName.substr(0, 1).toUpperCase() + fieldName.substr(1).toLowerCase() : fieldName, 675 width: 100, 676 dataIndex: fieldName, 677 sortable: true 678 }; 679 680 // Look for custom rendering 681 if (this.gridCellRenderers && this.featureType) { 682 var gridCellRenderer; 683 for (var k = 0; k < this.gridCellRenderers.length; k++) { 684 gridCellRenderer = this.gridCellRenderers[k]; 685 if (gridCellRenderer.attrName && fieldName == gridCellRenderer.attrName) { 686 if (gridCellRenderer.featureType && this.featureType == gridCellRenderer.featureType || !gridCellRenderer.featureType) { 687 column.options = gridCellRenderer.renderer.options; 688 column.renderer = gridCellRenderer.renderer.fn; 689 } 690 } 691 } 692 } 693 this.columns.push(column); 694 storeFields.push({name: column.dataIndex}); 695 } 696 } //end of attributes scanning 697 //if requested, we'll add a button 698 if (this.openOnButton) { 699 var column = { 700 xtype: 'actioncolumn', 701 width: 32, 702 sortable: false, 703 items: [{ 704 icon: 'theme/app/img/camera16x16.png', 705 tooltip: 'Apri foto aerea', 706 handler: function(grid, rowIndex, colIndex) { 707 var img = grid.getStore().getAt(rowIndex).data.IMAGE; 708 this.showFoto(grid.featureType, img); 709 }, 710 scope: this 711 }] 712 }; 713 this.columns.push(column); 714 storeFields.push({name: 'button'}); 715 } 716 //if requested, we'll add a checkBox 717 if (feature.attributes.onCart != undefined) { 718 var column = { 719 xtype: 'checkcolumn', 720 header: 'Carrello', 721 dataIndex: 'onCart', 722 father: this 723 }; 724 this.columns.push(column); 725 storeFields.push({name: 'onCart'}); 726 } 727 } 728 } else { 729 Ext.each(this.columns, function(column) { 730 if (column.dataIndex) { 731 storeFields.push({name: column.dataIndex, type: column.type}); 732 } 733 column.sortable = true; 734 }); 735 } 736 737 // this.columns.push({ header: 'Zoom', width: 60, sortable: false, renderer: self.zoomButtonRenderer }); 738 739 // Define the Store 740 var storeConfig = {layer: this.layer, fields: storeFields}; 741 742 // Optional extra store options in config 743 Ext.apply(storeConfig, this.hropts.storeOpts); 744 745 this.store = new GeoExt.data.FeatureStore(storeConfig); 746 this.store.father = this; 747 this.store.layerId= feature.gml.featureType; 748 this.store.on({ 749 update: function(obj, record, operation) { 750 var grid = this.father; 751 if (!this.father.cart) { 752 this.father.cart = Ext.getCmp(this.father.cartPanel); 753 } 754 if (record.data.onCart == true) { 755 var id = grid.featureType + '_' + record.data.IMAGE; 756 this.father.cart.fireEvent('addOnCart', id, this.father.title, grid.featureType, record.data.FOTOGRAMMA, record.data.STRISCIATA, grid.featureType, record.data.IMAGE); 757 } else { 758 var id = grid.featureType + '_' + record.data.IMAGE; 759 this.father.cart.fireEvent('removeFromCart', id); 760 } 761 }, 762 rowdeselect: function() { 763 } 764 765 }); 766 }, 767 /** private: method[updateSelectionLayer] 768 * :param evt: ``Object`` An object with a feature property referencing 769 * the selected or unselected feature. 770 * @private 771 */ 772 updateSelectionLayer: function(evt) { 773 if (!this.showGeometries) { 774 return; 775 } 776 this.selLayer.removeAllFeatures({silent: true}); 777 var features = this.layer.selectedFeatures; 778 for (var i = 0; i < features.length; i++) { 779 var feature = features[i].clone(); 780 this.selLayer.addFeatures(feature); 781 } 782 }, 783 /** api: method[onPanelRendered] 784 * Called when Panel has been rendered. 785 * @private 786 */ 787 onPanelRendered: function() { 788 if (this.ownerCt) { 789 this.ownerCt.addListener("parenthide", this.onParentHide, this); 790 this.ownerCt.addListener("parentshow", this.onParentShow, this); 791 } 792 }, 793 /** private: method[onPanelShow] 794 * Called after our panel is shown. 795 * @private 796 */ 797 onPanelShow: function() { 798 if (this.selModel && this.selModel.selectControl) { 799 this.selModel.selectControl.activate(); 800 } 801 }, 802 /** private: method[onPanelHide] 803 * Called before our panel is hidden. 804 * @private 805 */ 806 onPanelHide: function() { 807 if (this.selModel && this.selModel.selectControl) { 808 this.selModel.selectControl.deactivate(); 809 } 810 }, 811 /** private: method[onParentShow] 812 * Called usually before our panel is created. 813 * @private 814 */ 815 onParentShow: function() { 816 this.showLayer(); 817 }, 818 /** private: method[onParentHide] 819 * Cleanup usually before our panel is hidden. 820 * @private 821 */ 822 onParentHide: function() { 823 this.removeFeatures(); 824 this.hideLayer(); 825 this.cleanWindow(); 826 }, 827 /** private: method[cleanup] 828 * Cleanup usually before our panel is destroyed. 829 * @private 830 */ 831 cleanup: function() { 832 this.removeFeatures(); 833 if (this.selModel && this.selModel.selectControl) { 834 this.selModel.selectControl.deactivate(); 835 this.selModel = null; 836 } 837 838 if (this.layer) { 839 this.map.removeLayer(this.layer); 840 } 841 842 if (this.selLayer) { 843 this.map.removeLayer(this.selLayer); 844 } 845 return true; 846 }, 847 /** private: method[updateTbarText] 848 * Update text message in top toolbar. 849 * @private 850 */ 851 updateTbarText: function() { 852 if (!this.tbarText) { 853 return; 854 } 855 var objCount = this.store ? this.store.getCount() : 0; 856 this.tbarText.setText(objCount + ' ' + (objCount != 1 ? __('Results') : __('Result'))); 857 }, 858 /** private: method[exportData] 859 * Callback handler function for exporting and downloading the data to specified format. 860 * @private 861 */ 862 exportData: function(exportFormat) { 863 864 var store = this.store; 865 866 // Get config from preconfigured configs 867 var config = this.exportConfigs[exportFormat]; 868 if (!config) { 869 Ext.Msg.alert(__('Warning'), __('Invalid export format configured: ' + exportFormat)); 870 return; 871 } 872 873 // Create the filename for download 874 var featureType = this.featureType ? this.featureType : 'heron'; 875 config.fileName = featureType + config.fileExt; 876 877 // Use only the columns from the original data, not the internal feature store columns 878 // 'fid', 'state' and the feature object itthis, see issue 181. These are the first 3 fields in 879 // a GeoExt FeatureStore. 880 config.columns = (store.fields && store.fields.items && store.fields.items.length > 3) ? store.fields.items.slice(3) : null; 881 882 // Format the feature or grid data to chosen format and force user-download 883 var data = framework.data.DataExporter.formatStore(store, config, true); 884 framework.data.DataExporter.download(data, config); 885 }, 886 /** private: method[downloadData] 887 * Callback handler function for direct downloading the data in specified format. 888 * @private 889 */ 890 downloadData: function(downloadFormat, fileExt) { 891 892 var downloadInfo = this.downloadInfo; 893 downloadInfo.params.outputFormat = downloadFormat; 894 downloadInfo.params.filename = downloadInfo.params.typename + fileExt; 895 896 var paramStr = OpenLayers.Util.getParameterString(downloadInfo.params); 897 898 var url = OpenLayers.Util.urlAppend(downloadInfo.url, paramStr); 899 if (url.length > 2048) { 900 Ext.Msg.alert(__('Warning'), __('Download URL string too long (max 2048 chars): ') + url.length); 901 return; 902 } 903 904 // Force user-download 905 framework.data.DataExporter.directDownload(url); 906 }, 907 /** public: method[showFoto] 908 * show a photo in a new window 909 * @public 910 * @param {String} url photo 911 */ 912 showFoto: function(productName,photoName) { 913 if (!window.winFoto) { 914 window.winFoto = new Ext.Window({ 915 constrainHeader: true, 916 layout: 'fit', 917 closeAction: 'hide', 918 html: '<img src="resources/' + productName + '/low/' + photoName + '">', // 919 width: 315, 920 height: 333, 921 title: this.title + " - " + photoName, 922 listeners: { 923 close: function() { 924 window.winFoto.destroy(); 925 }, scope: this 926 } 927 }).show(); 928 } else { 929 window.winFoto.setTitle(this.title + " - " + photoName); 930 window.winFoto.update('<img src="resources/' + productName + '/low/' + photoName + '">'); 931 window.winFoto.setVisible(true); 932 } 933 }, 934 /** public: method[cleanWindow] 935 * clean screen from windows photo and window feature info 936 * @public 937 * @param {String} url photo 938 */ 939 cleanWindow: function(){ 940 if (window.popupAddr) { 941 window.popupAddr.close(); 942 window.popupAddr.destroy(); 943 delete window.popupAddr; 944 } 945 if (window.winFoto) { 946 window.winFoto.close(); 947 window.winFoto.destroy(); 948 delete window.winFoto; 949 } 950 }, 951 952 getPathImageHR: function(product,image,hdd){ 953 var sep = '/'; 954 var path = this.basePathResources[hdd]; 955 if(path.indexOf('/') == -1){ 956 sep = '\\'; 957 path = sep + sep + path; 958 } 959 return path + sep + product + sep + 'HR' + sep + image; 960 } 961 962 }); 963 964 /** api: xtype = framework_featuresearchgridpanel */ 965 Ext.reg('framework_featuresearchgridpanel', framework.widgets.search.FeatureSearchGridPanel); 966