[Commits] r1294 - in core/trunk/geoext: lib/GeoExt/widgets/tree tests/lib/GeoExt/widgets/tree
commits at geoext.org
commits at geoext.org
Wed Jul 29 11:38:05 CEST 2009
Author: ahocevar
Date: 2009-07-29 11:38:05 +0200 (Wed, 29 Jul 2009)
New Revision: 1294
Modified:
core/trunk/geoext/lib/GeoExt/widgets/tree/LayerNode.js
core/trunk/geoext/tests/lib/GeoExt/widgets/tree/LayerNode.html
Log:
enforce one layer visible when checkedGroup is set. r=elemoine (closes #109)
Modified: core/trunk/geoext/lib/GeoExt/widgets/tree/LayerNode.js
===================================================================
--- core/trunk/geoext/lib/GeoExt/widgets/tree/LayerNode.js 2009-07-29 08:52:37 UTC (rev 1293)
+++ core/trunk/geoext/lib/GeoExt/widgets/tree/LayerNode.js 2009-07-29 09:38:05 UTC (rev 1294)
@@ -34,22 +34,25 @@
if (a.checked === undefined) {
a.checked = this.node.layer.getVisibility();
}
- GeoExt.tree.LayerNodeUI.superclass.render.call(this, bulkRender);
+ GeoExt.tree.LayerNodeUI.superclass.render.apply(this, arguments);
+ var cb = this.checkbox;
if (a.radioGroup && this.radio === null) {
- this.radio = Ext.DomHelper.insertAfter(this.checkbox,
+ this.radio = Ext.DomHelper.insertAfter(cb,
['<input type="radio" class="gx-tree-layer-radio" name="',
a.radioGroup, '_radio"></input>'].join(""));
}
if(a.checkedGroup) {
// replace the checkbox with a radio button
- var radio = Ext.DomHelper.insertAfter(this.checkbox,
+ var radio = Ext.DomHelper.insertAfter(cb,
['<input type="radio" name="', a.checkedGroup,
- '_checkbox" class="', this.checkbox.className,
- this.checkbox.checked ? '" checked="checked"' : '',
+ '_checkbox" class="', cb.className,
+ cb.checked ? '" checked="checked"' : '',
'"></input>'].join(""));
- Ext.get(this.checkbox).remove();
+ radio.defaultChecked = cb.defaultChecked;
+ Ext.get(cb).remove();
this.checkbox = radio;
}
+ this.enforceOneVisible();
},
/** private: method[onClick]
@@ -59,34 +62,85 @@
if (e.getTarget('.gx-tree-layer-radio', 1)) {
this.fireEvent("radiochange", this.node);
} else if(e.getTarget('.x-tree-node-cb', 1)) {
- GeoExt.tree.LayerNodeUI.superclass.onCheckChange.call(this);
+ this.onCheckChange();
} else {
- GeoExt.tree.LayerNodeUI.superclass.onClick.call(this, e);
+ GeoExt.tree.LayerNodeUI.superclass.onClick.apply(this, arguments);
}
},
/** private: method[toggleCheck]
- * :param value: ``Boolean``
+ * :param value: ``Boolean``
*/
toggleCheck: function(value) {
- GeoExt.tree.LayerNodeUI.superclass.toggleCheck.call(this, value);
- var node = this.node;
- var layer = this.node.layer;
- node.visibilityChanging = true;
- if(this.checkbox && (layer.getVisibility() != this.isChecked())) {
- layer.setVisibility(this.isChecked());
+ if(!this._visibilityChanging) {
+ this._visibilityChanging = true;
+
+ // make sure we do not hide the checked layer from a checkedGroup
+ value = (value === undefined ? !this.isChecked() : value) ||
+ (this.isChecked() && !!this.node.attributes.checkedGroup);
+ GeoExt.tree.LayerNodeUI.superclass.toggleCheck.call(this, value);
+
+ this.enforceOneVisible();
+
+ delete this._visibilityChanging;
}
- node.visibilityChanging = false;
},
+ /** private: method[enforceOneVisible]
+ *
+ * Makes sure that only one layer is visible if checkedGroup is set.
+ * This can only work when ``layer.setVisibility()`` does not trigger
+ * ``this.toggleCheck()``. If it does, ``this._visibilityChanging`` has
+ * to be set to true before calling this method.
+ */
+ enforceOneVisible: function() {
+ var attributes = this.node.attributes;
+ var group = attributes.checkedGroup;
+ if(group) {
+ var layer = this.node.layer;
+ var checkedNodes = this.node.getOwnerTree().getChecked();
+ var checkedCount = 0;
+ // enforce "not more than one visible"
+ Ext.each(checkedNodes, function(n){
+ var ui = n.getUI();
+ var l = n.layer
+ if(!n.hidden && n.attributes.checkedGroup === group) {
+ checkedCount++;
+ if(l != layer && attributes.checked) {
+ // toggleCheck won't be called (_visibilityChanging
+ // set to true when we are called from toggleCheck(),
+ // and layer visibility handler is not yet set when we
+ // are called from render()), so we synchronize the
+ // button state manually
+ ui.checkbox.defaultChecked = false;
+ ui.checkbox.checked = false;
+ l.setVisibility(false);
+ }
+ }
+ });
+ // enforce "at least one visible"
+ if(checkedCount === 0 && attributes.checked == false) {
+ var ui = this.node.getUI();
+ // toggleCheck won't be called (_visibilityChanging set to
+ // true when we are called from toggleCheck(), and layer
+ // visibility handler is not yet set when we are called from
+ // render()), so we synchronize the button state manually
+ ui.checkbox.defaultChecked = true;
+ ui.checkbox.checked = true;
+ layer.setVisibility(true);
+ }
+ }
+ },
+
/** private: method[destroy]
*/
destroy: function() {
delete this.radio;
- GeoExt.tree.LayerNodeUI.superclass.destroy.call(this);
+ GeoExt.tree.LayerNodeUI.superclass.destroy.apply(this, arguments);
}
});
+
/** api: (define)
* module = GeoExt.tree
* class = LayerNode
@@ -156,21 +210,15 @@
*/
childNodeType: null,
- /** private: property[visibilityChanging]
- * {Boolean} private property indicating layer visibility being changed
- * by this node in order to prevent visibilitychanged events bouncing
- * back and forth
- */
- visibilityChanging: false,
-
/** private: method[constructor]
* Private constructor override.
*/
constructor: function(config) {
config.leaf = config.leaf || !config.children;
- config.iconCls = typeof config.iconCls == "undefined" &&
- !config.children ? "layer-icon" : config.iconCls;
+ if(!config.iconCls && !config.children) {
+ config.iconCls = "gx-tree-layer-icon";
+ }
this.defaultUI = this.defaultUI || GeoExt.tree.LayerNodeUI;
this.addEvents(
@@ -214,6 +262,13 @@
if(layer) {
this.layer = layer;
+ // no DD and radio buttons for base layers
+ if(layer.isBaseLayer) {
+ this.draggable = false;
+ Ext.applyIf(this.attributes, {
+ checkedGroup: "gx_baselayer"
+ });
+ }
if(!this.text) {
this.text = layer.name;
}
@@ -232,7 +287,7 @@
this.addStoreEventHandlers(layer);
}
}
- GeoExt.tree.LayerNode.superclass.render.call(this, bulkRender);
+ GeoExt.tree.LayerNode.superclass.render.apply(this, arguments);
},
/** private: method[addVisibilityHandlers]
@@ -254,10 +309,7 @@
* handler for visibilitychanged events on the layer
*/
onLayerVisibilityChanged: function() {
- if(!this.visibilityChanging &&
- this.attributes.checked != this.layer.getVisibility()) {
- this.getUI().toggleCheck(this.layer.getVisibility());
- }
+ this.getUI().toggleCheck(this.layer.getVisibility());
},
/** private: method[onCheckChange]
@@ -267,10 +319,14 @@
* handler for checkchange events
*/
onCheckChange: function(node, checked) {
- if (checked && this.layer.isBaseLayer && this.layer.map) {
- this.layer.map.setBaseLayer(this.layer);
+ if(checked != this.layer.getVisibility()) {
+ var layer = this.layer;
+ if(checked && layer.isBaseLayer && layer.map) {
+ layer.map.setBaseLayer(layer);
+ } else {
+ layer.setVisibility(checked);
+ }
}
- this.layer.setVisibility(checked);
},
/** private: method[addStoreEventHandlers]
@@ -299,12 +355,13 @@
l = records[i].get("layer");
if(this.layer == l) {
this.getUI().show();
+ break;
} else if (this.layer == l.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;
+ this.render();
+ break;
}
}
},
@@ -369,7 +426,7 @@
delete this.layerStore;
this.un("checkchange", this.onCheckChange, this);
- GeoExt.tree.LayerNode.superclass.destroy.call(this);
+ GeoExt.tree.LayerNode.superclass.destroy.apply(this, arguments);
}
});
Modified: core/trunk/geoext/tests/lib/GeoExt/widgets/tree/LayerNode.html
===================================================================
--- core/trunk/geoext/tests/lib/GeoExt/widgets/tree/LayerNode.html 2009-07-29 08:52:37 UTC (rev 1293)
+++ core/trunk/geoext/tests/lib/GeoExt/widgets/tree/LayerNode.html 2009-07-29 09:38:05 UTC (rev 1294)
@@ -26,7 +26,7 @@
function test_render(t) {
- t.plan(8);
+ t.plan(9);
var layer = new OpenLayers.Layer("foo");
@@ -64,16 +64,93 @@
node.ui.onClick({getTarget: function() {return true}});
t.eq(node.ui.checkbox.type, "radio", "checkbox rendered as radio button when checkedGroup is configured");
- t.eq(node.ui.checkbox.name, "check_checkbox", "option group name set correclty according to checkedGroup");
+ t.eq(node.ui.checkbox.name, "check_checkbox", "option group name set correctly according to checkedGroup");
+ layer.setVisibility(false);
+ t.eq(layer.visibility, true, "unchecking a layer with checkedGroup has no effect");
+
+ delete node.attributes.checkedGroup;
node.ui.toggleCheck();
- t.eq(layer.visibility, false, "unchecking node hides layer");
+ t.eq(layer.visibility, false, "unchecking a layer without checkedGroup hides the layer");
});
mapPanel.render("map");
+ mapPanel.destroy();
}
+
+ function test_enforceOneVisible(t) {
+ t.plan(8);
+ var layers = [
+ new OpenLayers.Layer("foo"),
+ new OpenLayers.Layer("bar")
+ ];
+ var mapPanel = new GeoExt.MapPanel({
+ layers: layers,
+ allOverlays: true
+ });
+ var root = new GeoExt.tree.LayerContainer({
+ loader: {
+ baseAttrs: {checkedGroup: "group"}
+ },
+ expanded: true
+ });
+ var panel = new Ext.tree.TreePanel({
+ renderTo: "tree",
+ root: root
+ });
+ mapPanel.render("map");
+
+ // two overlay layers in the same checkedGroup: only one can be visible
+ var nodes = panel.getRootNode().childNodes;
+ t.eq(nodes[0].layer.getVisibility(), false, "Layer on top is hidden");
+ t.eq(nodes[1].layer.getVisibility(), true, "Layer on bottom is visible");
+
+ delete root.loader.baseAttrs.checkedGroup;
+ mapPanel.map.allOverlays = false;
+
+ // without a custom checkedGroup, base layers get the gx_baselayer group assigned
+ mapPanel.layers.on("add", function(){
+ t.eq(nodes[0].attributes.checkedGroup, "gx_baselayer", "gx_baselayer checkedGroup set for base layer");
+ }, this, {single: true});
+ mapPanel.map.addLayer(new OpenLayers.Layer("foo1", {isBaseLayer: true}));
+
+ root.loader.baseAttrs.checkedGroup = "another_group";
+
+ // a custom checkedGroup will override the gx_baselayer default
+ mapPanel.layers.on("add", function() {
+ t.eq(nodes[0].attributes.checkedGroup, "another_group", "custom checkedGroup set for base layer");
+ }, this, {single: true});
+ mapPanel.map.addLayer(new OpenLayers.Layer("bar", {isBaseLayer: true}));
+
+ // overlays also get the custom checkedGroup assigned
+ mapPanel.layers.on("add", function() {
+ t.eq(nodes[0].attributes.checkedGroup, "another_group", "custom checkedGroup set for overlay");
+ // the another_group baselayer from above is invisible (the gx_baselayer one is visible)
+ t.eq(nodes[0].layer.getVisibility(), true, "overlay in checkedGroup visible because no other layer in group is visible");
+ // now making it visible
+ nodes[1].layer.setVisibility(true);
+ // and the overlay in the same checkedGroup gets hidden
+ t.eq(nodes[0].layer.getVisibility(), false, "overlay in checkedGroup now hidden because base layer in group is visible");
+ }, this, {single: true});
+ mapPanel.map.addLayer(new OpenLayers.Layer("foo2", {isBaseLayer: false}));
+
+ // remove all layers except one visible and one invisible layer
+ mapPanel.map.removeLayer(nodes[0].layer);
+ mapPanel.map.removeLayer(nodes[0].layer);
+ mapPanel.map.removeLayer(nodes[0].layer);
+ // now there is only one layer in the another_group
+ // "bar" (invisible) is now in the group at position [0], "foo" (visible) at [1]
+ mapPanel.layers.on("remove", function() {
+ t.eq(nodes[0].layer.getVisibility(), true, "Previously invisible layer was made visible because the visible layer has been removed")
+ }, this, {single: true});
+ // removing "foo", so "bar" will have to be made visible
+ mapPanel.map.removeLayer(nodes[1].layer);
+
+ mapPanel.destroy();
+ }
+
function test_changelayername(t) {
t.plan(2);
More information about the Commits
mailing list