[Commits] r249 - in sandbox/opengeo/geoexplorer/lib: . GeoExt/widgets GeoExt/widgets/tree
commits at geoext.org
commits at geoext.org
Mon Mar 23 20:03:48 CET 2009
Author: tschaub
Date: 2009-03-23 20:03:47 +0100 (Mon, 23 Mar 2009)
New Revision: 249
Added:
sandbox/opengeo/geoexplorer/lib/GeoExt/widgets/tree/
sandbox/opengeo/geoexplorer/lib/GeoExt/widgets/tree/LayerContainer.js
sandbox/opengeo/geoexplorer/lib/GeoExt/widgets/tree/LayerNode.js
sandbox/opengeo/geoexplorer/lib/GeoExt/widgets/tree/TristateCheckboxNode.js
sandbox/opengeo/geoexplorer/lib/GeoExt/widgets/tree/TristateCheckboxNodeUI.js
Modified:
sandbox/opengeo/geoexplorer/lib/GeoExt.js
Log:
mimimum code to get working layer tree (see #24)
Added: sandbox/opengeo/geoexplorer/lib/GeoExt/widgets/tree/LayerContainer.js
===================================================================
--- sandbox/opengeo/geoexplorer/lib/GeoExt/widgets/tree/LayerContainer.js (rev 0)
+++ sandbox/opengeo/geoexplorer/lib/GeoExt/widgets/tree/LayerContainer.js 2009-03-23 19:03:47 UTC (rev 249)
@@ -0,0 +1,120 @@
+/**
+ * Copyright (c) 2008 The Open Planning Project
+ */
+Ext.namespace("GeoExt.tree");
+
+/**
+ * Class: GeoExt.tree.LayerContainer
+ *
+ * A subclass of {Ext.tree.TreeNode} that will collect all layers of an
+ * OpenLayers map. Only layers that have displayInLayerSwitcher set to true
+ * will be included. The childrens' iconCls will be set to "baselayer-icon"
+ * for base layers, and to "layer-icon" for overlay layers.
+ *
+ * To use this node type in JSON config, set nodeType to "gxLayerContainer".
+ *
+ * Inherits from:
+ * - <Ext.tree.TreeNode>
+ */
+GeoExt.tree.LayerContainer = Ext.extend(Ext.tree.TreeNode, {
+
+ /**
+ * ConfigProperty: map
+ * {OpenLayers.Map} or {String} - map or id of an {Ext.Component} that
+ * has a map property with an {OpenLayers.Map} set. This node will
+ * be connected to that map. If omitted, the node will query the
+ * ComponentManager for the first component that has a map property
+ * with an {OpenLayers.Map} set.
+ */
+ map: null,
+
+ /**
+ * Constructor: GeoExt.tree.LayerContainer
+ *
+ * Parameters:
+ * config - {Object}
+ */
+ constructor: function(config) {
+ this.map = config.map;
+
+ this.addEvents("customizeconfig");
+
+ GeoExt.tree.LayerContainer.superclass.constructor.apply(this, arguments);
+ },
+
+ /**
+ * Method: render
+ *
+ * Parameters:
+ * bulkRender - {Boolean}
+ */
+ render: function(bulkRender) {
+ if (!this.rendered) {
+ var map = this.map instanceof OpenLayers.Map ? this.map :
+ (typeof this.map == "string" ? Ext.getCmp(this.map).map :
+ Ext.ComponentMgr.all.find(function(o) {
+ return o.map instanceof OpenLayers.Map;
+ }).map);
+ if (map.layers) {
+ var layer, node;
+ for (var i = 0, len = map.layers.length; i < len; ++i) {
+ layer = map.layers[i];
+ this.addLayerNode(layer);
+ }
+ }
+ map.events.register("addlayer", this, function(e) {
+ this.addLayerNode(e.layer);
+ });
+ map.events.register("removelayer", this, function(e) {
+ this.removeLayerNode(e.layer);
+ });
+ }
+ GeoExt.tree.LayerContainer.superclass.render.call(this, bulkRender);
+ },
+
+ /**
+ * Method: addLayerNode
+ * Adds a child node representing a layer of the map
+ *
+ * Parameters:
+ * layer - {OpenLayers.Layer} the layer to add a node for
+ */
+ addLayerNode: function(layer) {
+ if (layer.displayInLayerSwitcher == true) {
+
+ var config = {
+ iconCls: layer.isBaseLayer ? 'baselayer-icon' : 'layer-icon',
+ layer: layer
+ }
+
+ this.fireEvent("customizeconfig", config, layer);
+
+ node = new GeoExt.tree.LayerNode(config);
+
+ this.appendChild(node);
+ }
+ },
+
+ /**
+ * Method: removeLayerNode
+ * Removes a child node representing a layer of the map
+ *
+ * Parameters:
+ * layer - {OpenLayers.Layer} the layer to remove the node for
+ */
+ removeLayerNode: function(layer) {
+ if (layer.displayInLayerSwitcher == true) {
+ var node = this.findChildBy(function(node) {
+ return node.layer == layer;
+ });
+ if(node) {
+ node.remove();
+ }
+ }
+ }
+});
+
+/**
+ * NodeType: gxLayerContainer
+ */
+Ext.tree.TreePanel.nodeTypes.gxLayerContainer = GeoExt.tree.LayerContainer;
Added: sandbox/opengeo/geoexplorer/lib/GeoExt/widgets/tree/LayerNode.js
===================================================================
--- sandbox/opengeo/geoexplorer/lib/GeoExt/widgets/tree/LayerNode.js (rev 0)
+++ sandbox/opengeo/geoexplorer/lib/GeoExt/widgets/tree/LayerNode.js 2009-03-23 19:03:47 UTC (rev 249)
@@ -0,0 +1,184 @@
+/**
+ * Copyright (c) 2008 The Open Planning Project
+ *
+ * @requires GeoExt/widgets/tree/TristateCheckboxNode.js
+ */
+Ext.namespace("GeoExt.tree");
+
+/**
+ * Class: GeoExt.tree.LayerNode
+ *
+ * A subclass of {Ext.tree.AsyncTreeNode} that is connected to an
+ * {OpenLayers.Layer} by setting the node's layer property. Checking or
+ * unchecking the checkbox of this node will directly affect the layer and
+ * vice versa. The default iconCls for this node's icon is "layer-icon",
+ * unless it has children.
+ *
+ * This node can contain children, e.g. filter nodes.
+ *
+ * Setting the node's layer property to a layer name instead of an object
+ * will also work. As soon as a layer is found, it will be stored as layer
+ * property in the attributes hash.
+ *
+ * The node's text property defaults to the layer name.
+ *
+ * If the layer has a queryable property set to true, the node will render a
+ * radio button to select the query layer. Clicking on the radio button will
+ * fire the querychange event, with the layer as argument. A queryGroup
+ * attribute, set to the map's id, will be added to the attributes hash.
+ *
+ * To use this node type in a JSON config, set nodeType to "gxLayer".
+ *
+ * Inherits from:
+ * - <GeoExt.tree.TristateCheckboxNode>
+ */
+GeoExt.tree.LayerNode = Ext.extend(GeoExt.tree.TristateCheckboxNode, {
+
+ /**
+ * ConfigProperty: layer
+ * {OpenLayers.Layer} or {String}. The layer that this layer node will
+ * be bound to, or the name of the layer (has to match the layer's name
+ * property). Subclasses or applications can always rely on finding an
+ * {OpenLayers.Layer} object in attributes.layer.
+ */
+ layer: null,
+
+ /**
+ * ConfigProperty: map
+ * {OpenLayers.Map} or {String}. Map or id of an {Ext.Component} that
+ * has a map property with an {OpenLayers.Map} set. This node will
+ * be connected to that map. If omitted, the node will query the
+ * ComponentManager for the first component that has a map property
+ * with an {OpenLayers.Map} set.
+ */
+ map: null,
+
+ /**
+ * Property: haveLayer
+ * {Boolean} will be set to true as soon as this node is connected to a
+ * layer.
+ */
+ haveLayer: null,
+
+ /**
+ * Property: updating
+ * {Boolean} The visibility status of the layer is being updated by itself
+ * (i.e. not by clicking on this node, but by layer visibilitychanged)
+ */
+ updating: false,
+
+ /**
+ * Constructor: GeoExt.tree.LayerNode
+ *
+ * Parameters:
+ * config - {Object}
+ */
+ constructor: function(config) {
+ this.layer = config.layer;
+ this.map = config.map;
+ this.haveLayer = false;
+
+ config.leaf = config.leaf || !config.children;
+ config.iconCls = typeof config.iconCls == "undefined" &&
+ !config.children ? "layer-icon" : config.iconCls;
+ // checked status will be set by layer event, so setting it to false
+ // to always get the checkbox rendered
+ config.checked = false;
+
+ this.defaultUI = this.defaultUI || GeoExt.tree.LayerNodeUI;
+ this.addEvents.apply(this, GeoExt.tree.LayerNode.EVENT_TYPES);
+
+ GeoExt.tree.LayerNode.superclass.constructor.apply(this, arguments);
+ },
+
+ /**
+ * Method: render
+ *
+ * Properties:
+ * bulkRender {Boolean} - optional
+ * layer {<OpenLayers.Layer>} - optional
+ */
+ render: function(bulkRender) {
+ if (!this.rendered || !this.haveLayer) {
+ var map = this.map instanceof OpenLayers.Map ? this.map :
+ (typeof this.map == "string" ? Ext.getCmp(this.map).map :
+ Ext.ComponentMgr.all.find(function(o) {
+ return o.map instanceof OpenLayers.Map;
+ }).map);
+ var layer = this.attributes.layer || this.layer;
+ this.haveLayer = layer && typeof layer == "object";
+ if(typeof layer == "string") {
+ var matchingLayers = map.getLayersByName(layer);
+ if(matchingLayers.length > 0) {
+ layer = matchingLayers[0];
+ this.haveLayer = true;
+ }
+ }
+ var ui = this.getUI();
+ if(this.haveLayer) {
+ this.attributes.layer = layer;
+ if(layer.queryable == true) {
+ this.attributes.radioGroup = layer.map.id;
+ }
+ if(!this.text) {
+ this.text = layer.name;
+ }
+ ui.show();
+ ui.toggleCheck(layer.getVisibility());
+ layer.events.register("visibilitychanged", this, function(){
+ this.updating = true;
+ if(this.attributes.checked != layer.getVisibility()) {
+ ui.toggleCheck(layer.getVisibility());
+ }
+ this.updating = false;
+ });
+ this.on("checkchange", function(node, checked){
+ if(!this.updating) {
+ if(checked && layer.isBaseLayer) {
+ map.setBaseLayer(layer);
+ }
+ layer.setVisibility(checked);
+ }
+ }, this);
+
+ // set initial checked status
+ this.attributes.checked = layer.getVisibility();
+ } else {
+ ui.hide();
+ }
+ map.events.register("addlayer", this, function(e) {
+ if(layer == e.layer) {
+ this.getUI().show();
+ } else if (layer == e.layer.name) {
+ // layer is a string, which means the node has not
+ // yet been rendered because the layer was not found.
+ // But now we have the layer and can render.
+ this.render(bulkRender);
+ return;
+ }
+ });
+ map.events.register("removelayer", this, function(e) {
+ if(layer == e.layer) {
+ this.getUI().hide();
+ }
+ });
+ }
+ GeoExt.tree.LayerNode.superclass.render.call(this, bulkRender);
+ }
+});
+
+/**
+ * Constant: GeoExt.tree.LayerNode.EVENT_TYPES
+ * {Array(String)} - supported event types
+ *
+ * Event types supported for this class, in additon to the ones inherited
+ * from {<GeoExt.tree.TristateCheckboxNode>}:
+ * - *querylayerchange* notifies listener when the query layer has
+ * changed. Will be called with the new query layer as argument.
+ */
+GeoExt.tree.LayerNode.EVENT_TYPES = ["querylayerchange"];
+
+/**
+ * NodeType: gxLayer
+ */
+Ext.tree.TreePanel.nodeTypes.gxLayer = GeoExt.tree.LayerNode;
\ No newline at end of file
Added: sandbox/opengeo/geoexplorer/lib/GeoExt/widgets/tree/TristateCheckboxNode.js
===================================================================
--- sandbox/opengeo/geoexplorer/lib/GeoExt/widgets/tree/TristateCheckboxNode.js (rev 0)
+++ sandbox/opengeo/geoexplorer/lib/GeoExt/widgets/tree/TristateCheckboxNode.js 2009-03-23 19:03:47 UTC (rev 249)
@@ -0,0 +1,197 @@
+/**
+ * Copyright (c) 2008 The Open Planning Project
+ */
+Ext.namespace("GeoExt.tree");
+
+/**
+ * Class: GeoExt.tree.TristateCheckboxNode
+ *
+ * Provides a tree node that will have a third state (stored in
+ * attributes.thirdState) to have a proper semi-checked state for
+ * nodes with only *some* children checked. attributes.thirdState will be
+ * undefined if the node is checked or unchecked, and true if the node is
+ * semi-checked.
+ *
+ * This node has also a childcheckchange event that will be triggered with a
+ * child node and it's checked state to notify listeners when a the checked
+ * state of a child's node has changed.
+ *
+ * Applications using this class should not rely on the checkchange event to
+ * determine the checked state of non-leaf nodes. Instead, applications should
+ * also listen to the childcheckchange event and read out attributes.checked
+ * and attributes.thirdState to get the node's checked state.
+ *
+ * To use this node type in a JSON config, set nodeType to "tristateCheckbox".
+ *
+ * Inherits from:
+ * - <Ext.tree.TreeNode>
+ */
+GeoExt.tree.TristateCheckboxNode = Ext.extend(Ext.tree.TreeNode, {
+
+ /**
+ * Property: checkedChildNodes
+ * {Object} Hash of 0.1 for thirdState nodes and 1 for fully checked
+ * nodes, keyed by node ids. In combination with
+ * {<checkedCount>}, this provides an
+ * efficient way of keeping track of the childnodes' checked status.
+ */
+ checkedChildNodes: null,
+
+ /**
+ * Property: checkedCount
+ * {Number} A cache for the sum of checkedChildNodes' values.
+ */
+ checkedCount: null,
+
+ /**
+ * Constructor: GeoExt.tree.TristateCheckboxNode
+ *
+ * Parameters:
+ * config - {Object}
+ */
+ constructor: function(config) {
+ this.checkedChildNodes = {};
+ this.checkedCount = 0;
+
+ this.defaultUI = this.defaultUI || GeoExt.tree.TristateCheckboxNodeUI;
+ this.addEvents.apply(this, GeoExt.tree.TristateCheckboxNode.EVENT_TYPES);
+
+ GeoExt.tree.TristateCheckboxNode.superclass.constructor.apply(this, arguments);
+
+ this.on("childcheckchange", this.updateCheckedChildNodes, this);
+ },
+
+ /**
+ * Method: render
+ *
+ * Parameters:
+ * bulkRender - {Boolean}
+ */
+ render: function(bulkRender) {
+ var rendered = this.rendered;
+ var checked = this.attributes.checked;
+ this.attributes.checked =
+ typeof this.attributes.checked == "undefined" ? false :
+ this.attributes.checked;
+ GeoExt.tree.TristateCheckboxNode.superclass.render.call(this, bulkRender);
+ var ui = this.getUI();
+ if(!rendered) {
+ if(typeof checked == "undefined" && this.parentNode.ui.checkbox) {
+ ui.toggleCheck(this.parentNode.ui.checkbox.checked);
+ }
+ this.parentNode.on("checkchange", function(node, checked) {
+ ui.toggleCheck(checked);
+ }, this);
+ }
+ },
+
+ /**
+ * Method: updateCheckedChildNodes
+ * Updates the status cache of checked child nodes.
+ *
+ * Parameters:
+ * node - {Ext.tree.Node} child node that has changed
+ * checked - {Boolean} new checked status of the changed child node
+ */
+ updateCheckedChildNodes: function(node, checked) {
+ if(checked) {
+ this.addChecked(node, node.attributes.thirdState);
+ } else {
+ this.removeChecked(node);
+ }
+
+ var childrenChecked, childrenThirdState;
+ if(this.checkedCount.toFixed() == this.childNodes.length) {
+ childrenChecked = true;
+ childrenThirdState = false;
+ } else if(this.checkedCount.toFixed(1) == 0) {
+ childrenChecked = false;
+ childrenThirdState = false;
+ } else {
+ childrenChecked = true;
+ childrenThirdState = true;
+ }
+ // do a special silent toggleCheck to avoid checkchange events being
+ // triggered
+ this.getUI().toggleCheck(childrenChecked, childrenThirdState,
+ {silent: true});
+ if(this.parentNode) {
+ this.parentNode.fireEvent("childcheckchange", this,
+ childrenChecked);
+ }
+ },
+
+ /**
+ * Method: appendChild
+ *
+ * Parameters:
+ * node - {Ext.tree.Node}
+ */
+ appendChild: function(node) {
+ GeoExt.tree.TristateCheckboxNode.superclass.appendChild.call(this, node);
+ if(this.attributes.checked || node.attributes.checked) {
+ this.addChecked(node);
+ }
+ // We do not want this event handler to trigger checkchange events on
+ // parent nodes, because this would cause bouncing between this
+ // handler and the handler for (un-)checking children on a parent's
+ // checkchange event. So we introduce a special childcheckchange
+ // event with a handler that will also trigger this event on the
+ // parent.
+ node.on("checkchange", function(node, checked) {
+ if (this.childrenRendered) {
+ this.fireEvent("childcheckchange", node, checked);
+ }
+ }, this);
+ },
+
+ /**
+ * Method: addChecked
+ * Adds a child node to the checkedChildNodes hash. Adds 1 for fully
+ * checked nodes, 0.1 for third state checked nodes.
+ *
+ * Parameters:
+ * node - {Ext.tree.Node}
+ * thirdState - {Boolean}
+ */
+ addChecked: function(node, thirdState) {
+ // subtract current value (if any). This is needed to change from a
+ // tristate to a fully checked state and vice versa.
+ this.checkedCount -= (this.checkedChildNodes[node.id] || 0);
+
+ var add = thirdState ? 0.1 : 1;
+ this.checkedChildNodes[node.id] = add;
+ this.checkedCount += add;
+ },
+
+ /**
+ * Method: removeChecked
+ * Removes a child node from the checkedChildNodes hash.
+ *
+ * Parameters:
+ * node - {Ext.tree.Node}
+ */
+ removeChecked: function(node) {
+ var remove = this.checkedChildNodes[node.id]
+ if(remove) {
+ delete this.checkedChildNodes[node.id];
+ this.checkedCount -= remove;
+ }
+ }
+});
+
+/**
+ * Constant: EVENT_TYPES
+ * {Array(String)} - supported event types
+ *
+ * Event types supported for this class, in additon to the ones inherited
+ * from {<GeoExt.tree.TristateCheckboxNode>}:
+ * - *childcheckchange* fired to notify a parent node that the status of
+ * its checked child nodes has changed
+ */
+GeoExt.tree.TristateCheckboxNode.EVENT_TYPES = ["childcheckchange"];
+
+/**
+ * NodeType: tristateCheckbox
+ */
+Ext.tree.TreePanel.nodeTypes.tristateCheckbox = GeoExt.tree.TristateCheckboxNode;
Added: sandbox/opengeo/geoexplorer/lib/GeoExt/widgets/tree/TristateCheckboxNodeUI.js
===================================================================
--- sandbox/opengeo/geoexplorer/lib/GeoExt/widgets/tree/TristateCheckboxNodeUI.js (rev 0)
+++ sandbox/opengeo/geoexplorer/lib/GeoExt/widgets/tree/TristateCheckboxNodeUI.js 2009-03-23 19:03:47 UTC (rev 249)
@@ -0,0 +1,56 @@
+/**
+ * Copyright (c) 2008 The Open Planning Project
+ */
+Ext.namespace("GeoExt.tree");
+
+/**
+ * Class: GeoExt.tree.TristateCheckboxNodeUI
+ *
+ * Inherits from:
+ * - <Ext.tree.TreeNodeUI>
+ */
+GeoExt.tree.TristateCheckboxNodeUI = Ext.extend(Ext.tree.TreeNodeUI, {
+
+ /**
+ * Constructor: GeoExt.tree.TristateCheckbosNodeUI
+ *
+ * Parameters:
+ * config - {Object}
+ */
+ constructor: function(config) {
+ GeoExt.tree.TristateCheckboxNodeUI.superclass.constructor.apply(this, arguments);
+ },
+
+ /**
+ * Method: toggleCheck
+ *
+ * Parameters:
+ * value - {Boolean} checked status
+ * thirdState - {Boolean}
+ * options - {Object} Hash of options for this method
+ *
+ * Currently supported options:
+ * silent - {Boolean} set to true if no checkchange event should be
+ * fired
+ */
+ toggleCheck: function(value, thirdState, options) {
+ var cb = this.checkbox;
+ if(thirdState == true) {
+ if(cb) {
+ Ext.get(cb).setOpacity(0.5);
+ }
+ this.node.attributes.thirdState = true;
+ } else {
+ if(cb) {
+ Ext.get(cb).clearOpacity();
+ }
+ delete this.node.attributes.thirdState;
+ }
+ if(options && options.silent == true){
+ this.node.suspendEvents();
+ }
+ GeoExt.tree.TristateCheckboxNodeUI.superclass.toggleCheck.call(this,
+ value);
+ this.node.resumeEvents();
+ }
+});
\ No newline at end of file
Modified: sandbox/opengeo/geoexplorer/lib/GeoExt.js
===================================================================
--- sandbox/opengeo/geoexplorer/lib/GeoExt.js 2009-03-23 18:09:14 UTC (rev 248)
+++ sandbox/opengeo/geoexplorer/lib/GeoExt.js 2009-03-23 19:03:47 UTC (rev 249)
@@ -64,7 +64,11 @@
"GeoExt/data/LayerRecord.js",
"GeoExt/data/LayerStoreMediator.js",
"GeoExt/data/ProtocolProxy.js",
- "GeoExt/widgets/MapPanel.js"
+ "GeoExt/widgets/MapPanel.js",
+ "GeoExt/widgets/tree/TristateCheckboxNode.js",
+ "GeoExt/widgets/tree/TristateCheckboxNodeUI.js",
+ "GeoExt/widgets/tree/LayerNode.js",
+ "GeoExt/widgets/tree/LayerContainer.js"
);
var agent = navigator.userAgent;
More information about the Commits
mailing list