diff --git a/examples/tree/tree-hierarchy.html b/examples/tree/tree-hierarchy.html new file mode 100644 index 000000000..47a30667e --- /dev/null +++ b/examples/tree/tree-hierarchy.html @@ -0,0 +1,52 @@ + + + + GeoExt Tree Components + + + + + + + + + + + + + + + + + + + +
+

GeoExt.tree Components

+ +

This example shows how to work with a hierarchy layer tree.

+ +

Each layer can have an optional group attribute. The group attribute can have '/' to create the hierarchy, like: +

group: 'Additional layers/World/Administrative'
+

+ +

If no group attribute is assigned, the layer goes by to either the baseLayers or otherLayers group. The default labels for these two groups are: + +

baseLayersText: "Base layers",
+otherLayersText: "Other layers"
+        
+ + These labels can be changed. +

+ + + + + + +

The js is not minified so it is readable. See + tree-hierarchy.js.

+ +
+ + diff --git a/examples/tree/tree-hierarchy.js b/examples/tree/tree-hierarchy.js new file mode 100644 index 000000000..7f5dc5c86 --- /dev/null +++ b/examples/tree/tree-hierarchy.js @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2008-2015 The Open Source Geospatial Foundation + * + * Published under the BSD license. + * See https://github.com/geoext/geoext2/blob/master/license.txt for the full + * text of the license. + */ + +Ext.require([ + 'Ext.container.Viewport', + 'Ext.layout.container.Border', + 'GeoExt.tree.Panel', + 'Ext.tree.plugin.TreeViewDragDrop', + 'GeoExt.panel.Map', + 'GeoExt.tree.OverlayLayerContainer', + 'GeoExt.tree.BaseLayerContainer', + 'GeoExt.data.LayerTreeModel', + 'GeoExt.tree.View', + 'GeoExt.tree.Column', + 'GeoExt.tree.LayerTreeBuilder' +]); + +var mapPanel, tree; + +Ext.application({ + name: 'Tree', + launch: function() { + // create a map panel with some layers that we will show in our layer tree + // below. + mapPanel = Ext.create('GeoExt.panel.Map', { + border: true, + region: "center", + // we do not want all overlays, to try the OverlayLayerContainer + map: {allOverlays: false}, + center: [14, 37.5], + zoom: 7, + layers: [ + new OpenLayers.Layer.WMS("Global Imagery", + "http://maps.opengeo.org/geowebcache/service/wms", { + layers: "bluemarble", + format: "image/png8" + }, { + buffer: 0, + visibility: false, + group: 'World base maps/Imagery' + } + ), + new OpenLayers.Layer.WMS("OpenStreetMap WMS", + "http://ows.terrestris.de/osm/service?", + {layers: 'OSM-WMS'}, + { + attribution: '© terrestris GmbH & Co. KG
' + + 'Data © OpenStreetMap ' + + 'contributors', + group: 'World base maps/Vector' + } + ), + new OpenLayers.Layer.WMS("Country Borders", + "http://ows.terrestris.de/geoserver/osm/wms", { + layers: "osm:osm-country-borders", + transparent: true, + format: "image/png" + }, { + isBaseLayer: false, + resolutions: [ + 1.40625, + 0.703125, + 0.3515625, + 0.17578125, + 0.087890625, + 0.0439453125, + 0.02197265625, + 0.010986328125, + 0.0054931640625 + ], + buffer: 0, + group: 'Additional layers/World/Administrative' + } + ), + new OpenLayers.Layer.WMS("Gas Stations", + "http://ows.terrestris.de/geoserver/osm/wms", { + layers: "osm:osm-fuel", + transparent: true, + format: "image/png" + }, { + isBaseLayer: false, + buffer: 0 + } + ), + new OpenLayers.Layer.WMS("Bus Stops", + "http://ows.terrestris.de/osm-haltestellen?", + { + layers: 'OSM-Bushaltestellen', + format: 'image/png', + transparent: true + }, + { + singleTile: true, + visibility: false + } + ) + ] + }); + + var novatree = Ext.create('GeoExt.tree.LayerTreeBuilder', { + enableWmsLegends: false, + enableVectorLegends: false, + otherLayersText: 'Utilities', + border: true, + layerStore: mapPanel.layers, + region: "west", + title: "Layers", + width: 250, + split: true, + collapsible: true, + collapseMode: "mini", + autoScroll: true + }); + + Ext.create('Ext.Viewport', { + layout: "fit", + hideBorders: true, + items: { + layout: "border", + deferredRender: false, + items: [mapPanel, novatree, { + contentEl: "desc", + region: "east", + bodyStyle: {"padding": "5px"}, + collapsible: true, + collapseMode: "mini", + split: true, + width: 200, + title: "Description" + }] + } + }); + } +}); diff --git a/src/GeoExt/tree/LayerGroupContainer.js b/src/GeoExt/tree/LayerGroupContainer.js new file mode 100644 index 000000000..69bbbb806 --- /dev/null +++ b/src/GeoExt/tree/LayerGroupContainer.js @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2008-2012 The Open Source Geospatial Foundation + * + * Published under the BSD license. + * See https://github.com/geoext/geoext2/blob/master/license.txt for the full + * text of the license. + */ + +/* + * @include GeoExt/tree/LayerContainer.js + * @include GeoExt/container/WmsLegend.js + * @include GeoExt/container/VectorLegend.js + * @include GeoExt/data/LayerStore.js + */ + +/** + * + */ +Ext.define('GeoExt.tree.LayerGroupContainer', { + extend: 'GeoExt.tree.LayerContainer', + requires: [ + 'GeoExt.container.WmsLegend', + 'GeoExt.container.VectorLegend', + 'GeoExt.data.LayerStore' + ], + alias: 'plugin.gx_layergroupcontainer', + + defaultText: 'Layers', + + enableLegends: true, + + enableWmsLegends: true, + + enableVectorLegends: true, + + layerGroup: null, + + /** + * @private + */ + init: function(target) { + var me = this, + loader = me.loader, + createNode, + superProto = GeoExt.tree.LayerLoader.prototype; + + // set the 'createNode' method for the loader + if (me.enableLegends) { + createNode = function(attr) { + if (attr.layer.href) { + attr.href = attr.layer.href; + attr.cls = 'linknode'; + if (attr.layer.hrefTarget) attr.hrefTarget = attr.layer.hrefTarget; + } + if (attr.layer.qtip) attr.qtip = attr.layer.qtip; + var record = this.store.getByLayer(attr.layer), + layer = record.getLayer(); + + if (layer instanceof OpenLayers.Layer.WMS && + me.enableWmsLegends + ) { + attr.component = { + xtype: "gx_wmslegend", + layerRecord: record, + showTitle: false, + hidden: !layer.visibility || layer.hideInLegend + || !layer.inRange, + cls: "gx-layertreebuilder-legend" + }; + } else if (layer instanceof OpenLayers.Layer.Vector && + me.enableVectorLegends + ) { + attr.component = { + xtype: "gx_vectorlegend", + layerRecord: record, + showTitle: false, + hidden: !layer.visibility || layer.hideInLegend + || !layer.inRange, + cls: "gx-layertreebuilder-legend" + }; + } + + if (layer.hideInLegend) { + record.set("hideInLegend", layer.hideInLegend); + } + + return superProto.createNode.call(this, attr); + } + } + else { + createNode = function(attr) { + return superProto.createNode.call(this, attr); + } + } + + // set the loader + me.loader = Ext.applyIf(loader || {}, { + baseAttrs: Ext.applyIf((loader && loader.baseAttrs) || {}, { + uiProvider: "custom_ui", + layerGroup: this.layerGroup + }), + createNode: createNode, + filter: function(record) { + var layer = record.getLayer(); + return layer.displayInLayerSwitcher === true && + layer.options.group === this.baseAttrs.layerGroup; + } + }); + + me.callParent(arguments); + } +}); diff --git a/src/GeoExt/tree/LayerTreeBuilder.js b/src/GeoExt/tree/LayerTreeBuilder.js new file mode 100644 index 000000000..b4c328561 --- /dev/null +++ b/src/GeoExt/tree/LayerTreeBuilder.js @@ -0,0 +1,261 @@ +/* + * Copyright (c) 2008-2012 The Open Source Geospatial Foundation + * + * Published under the BSD license. + * See https://github.com/geoext/geoext2/blob/master/license.txt for the full + * text of the license. + */ + +/* + * @include GeoExt/tree/Panel.js + * @include GeoExt/tree/LayerGroupContainer.js + * @include GeoExt/data/LayerStore.js + * @include GeoExt/panel/Map.js + */ + +Ext.define('GeoExt.tree.LayerTreeBuilder', { + extend: 'GeoExt.tree.Panel', + requires: [ + 'GeoExt.data.LayerStore', + 'GeoExt.panel.Map', + 'GeoExt.tree.LayerGroupContainer' + ], + alias: 'widget.gx_layertreebuilder', + + /** + * @cfg {String} Text to display the default "base layers" group (i18n). + */ + baseLayersText: "Base layers", + + /** + * @cfg {String} Text to display the default "other layers" group (i18n). + */ + otherLayersText: "Other layers", + + layerStore: null, + + enableWmsLegends: true, + + enableVectorLegends: true, + + checkableContainerGroupNodes: true, + + checkableLeafGroupNodes: true, + + initComponent: function(){ + Ext.apply(this, { + autoScroll: true, + lines: false, + rootVisible: false, + store: Ext.create('Ext.data.TreeStore', { + model: 'GeoExt.data.LayerTreeModel' + }) + }); + + // Don't do anything if a layerstore hasn't been provided yet. + // Developer will need to set the layerStore and call + // initLayerStore again + if (this.layerStore) { + this.initLayerStore(); + } + + this.callParent(arguments); + }, + + initLayerStore: function() { + + // Process new layers as they come in + this.layerStore.on({ + "add": this.onLayerAdded, + scope: this + }); + + // after the layertree has been rendered, look for already added + // layer records, else, wait till afterrender event has fired + if (this.rendered) { + this.processLayerStore(); + } else { + // after the layertree has been rendered, look for already added + // layer records + this.on({ + "afterrender": this.processLayerStore, + scope: this + }); + // add a handler for checkboxes associated with nodes + this.on({ + 'checkchange' : function(node) { + // If a parent node is unchecked, uncheck all + // the children and vice versa + var me = this; + if(node.data.checked) { + node.eachChild(function(child) { + child.set('checked',true); + me.fireEvent('checkchange',child,true); + }); + } else { + node.eachChild(function(child) { + child.set('checked',false); + me.fireEvent('checkchange',child,false); + }); + } + this.updateCheckboxes(node.parentNode); + }, + scope: this + }); + } + }, + + // private + processLayerStore: function() { + if (this.layerStore.getCount() > 0) { + this.onLayerAdded( + this.layerStore, + this.layerStore.data.items + ); + } + }, + + + // make sure that a parent checkbox is only checked if all of it's + // children are also checked + updateCheckboxes: function(node) { + if(node.isRoot()) return; + var allChecked = true; + for(var i=0; i