[Commits] r1295 - in sandbox/elemoine/playground/geoext: examples lib/GeoExt/widgets/tree tests/lib/GeoExt/widgets/tree
commits at geoext.org
commits at geoext.org
Wed Jul 29 16:06:15 CEST 2009
Author: elemoine
Date: 2009-07-29 16:06:15 +0200 (Wed, 29 Jul 2009)
New Revision: 1295
Added:
sandbox/elemoine/playground/geoext/examples/delete.gif
sandbox/elemoine/playground/geoext/examples/info.png
sandbox/elemoine/playground/geoext/examples/move_down.png
sandbox/elemoine/playground/geoext/examples/move_up.png
sandbox/elemoine/playground/geoext/examples/tree-tools.html
sandbox/elemoine/playground/geoext/examples/tree-tools.js
Modified:
sandbox/elemoine/playground/geoext/lib/GeoExt/widgets/tree/LayerNode.js
sandbox/elemoine/playground/geoext/tests/lib/GeoExt/widgets/tree/LayerNode.html
Log:
ugly ugly code for demoing LayerNodeUI extensions
Added: sandbox/elemoine/playground/geoext/examples/delete.gif
===================================================================
(Binary files differ)
Property changes on: sandbox/elemoine/playground/geoext/examples/delete.gif
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: sandbox/elemoine/playground/geoext/examples/info.png
===================================================================
(Binary files differ)
Property changes on: sandbox/elemoine/playground/geoext/examples/info.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: sandbox/elemoine/playground/geoext/examples/move_down.png
===================================================================
(Binary files differ)
Property changes on: sandbox/elemoine/playground/geoext/examples/move_down.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: sandbox/elemoine/playground/geoext/examples/move_up.png
===================================================================
(Binary files differ)
Property changes on: sandbox/elemoine/playground/geoext/examples/move_up.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: sandbox/elemoine/playground/geoext/examples/tree-tools.html
===================================================================
--- sandbox/elemoine/playground/geoext/examples/tree-tools.html (rev 0)
+++ sandbox/elemoine/playground/geoext/examples/tree-tools.html 2009-07-29 14:06:15 UTC (rev 1295)
@@ -0,0 +1,67 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <title>GeoExt Tree Components</title>
+
+ <!--
+ <script type="text/javascript" src="http://extjs.cachefly.net/builds/ext-cdn-771.js"></script>
+ <link rel="stylesheet" type="text/css" href="http://extjs.cachefly.net/ext-2.2.1/resources/css/ext-all.css" />
+ <link rel="stylesheet" type="text/css" href="http://extjs.cachefly.net/ext-2.2.1/examples/shared/examples.css" />
+ -->
+
+ <script type"text/javascript" src="../../ext/adapter/ext/ext-base.js"></script>
+ <script type"text/javascript" src="../../ext/ext-all-debug.js"></script>
+ <link rel="stylesheet" type="text/css" href="../../ext/resources/css/ext-all.css"></script>
+
+ <script src="http://openlayers.org/api/2.8/OpenLayers.js"></script>
+ <script type="text/javascript" src="../lib/GeoExt.js"></script>
+
+ <script type="text/javascript" src="tree-tools.js"></script>
+
+ <style type="text/css">
+ .x-tree-node-actions{
+ float: right;
+ /*display: none;*/
+ }
+ .x-tree-node-action {
+ background-position:center center;
+ background-repeat:no-repeat;
+ border:0 none;
+ height:16px;
+ margin:0;
+ padding:0;
+ vertical-align:top;
+ width:16px;
+ }
+ .x-tree-node-actions .delete {
+ background:transparent url(delete.gif);
+ }
+ .x-tree-node-actions .move-up {
+ background:transparent url(move_up.png);
+ }
+ .x-tree-node-actions .move-down {
+ background:transparent url(move_down.png);
+ }
+ .info {
+ background-image:url(info.png) !important;
+ height:20px !important;
+ width:20px !important;
+ }
+ .gx-toolbar {
+ background:none;
+ border-style:none;
+ }
+ .x-tree-node-collapsed .x-tree-node-icon, .x-tree-node-expanded .x-tree-node-icon, .x-tree-node-leaf .gx-tree-layer-icon {
+ width: 0px; !important;
+ }
+ </style>
+
+ </head>
+ <body>
+ <div id="desc">
+ <h1>GeoExt.tree Components</h1>
+ <p>
+ <p>The js is not minified so it is readable. See
+ <a href="tree-tools.js">tree-tools.js</a>.</p>
+ </div>
+ </body>
+</html>
Added: sandbox/elemoine/playground/geoext/examples/tree-tools.js
===================================================================
--- sandbox/elemoine/playground/geoext/examples/tree-tools.js (rev 0)
+++ sandbox/elemoine/playground/geoext/examples/tree-tools.js 2009-07-29 14:06:15 UTC (rev 1295)
@@ -0,0 +1,99 @@
+/**
+ * Copyright (c) 2008-2009 The Open Source Geospatial Foundation
+ *
+ * Published under the BSD license.
+ * See http://svn.geoext.org/core/trunk/geoext/license.txt for the full text
+ * of the license.
+ */
+
+Ext.onReady(function() {
+
+ var mapPanel = new GeoExt.MapPanel({
+ border: true,
+ region: "center",
+ //map: new OpenLayers.Map({allOverlays: false}),
+ center: [146.1569825, -41.6109735],
+ zoom: 6,
+ layers: [
+ new OpenLayers.Layer.WMS("Global Imagery",
+ "http://demo.opengeo.org/geoserver/wms", {
+ layers: "bluemarble"
+ }, {
+ buffer: 0,
+ visibility: false
+ }),
+ new OpenLayers.Layer.WMS("Tasmania State Boundaries",
+ "http://demo.opengeo.org/geoserver/wms", {
+ layers: "topp:tasmania_state_boundaries"
+ }, {
+ buffer: 0
+ }),
+ new OpenLayers.Layer.WMS("Water",
+ "http://demo.opengeo.org/geoserver/wms", {
+ layers: "topp:tasmania_water_bodies",
+ transparent: true,
+ format: "image/gif"
+ }, {
+ isBaseLayer: false,
+ buffer: 0
+ }),
+ new OpenLayers.Layer.WMS("Cities",
+ "http://demo.opengeo.org/geoserver/wms", {
+ layers: "topp:tasmania_cities",
+ transparent: true,
+ format: "image/gif"
+ }, {
+ isBaseLayer: false,
+ buffer: 0
+ }),
+ new OpenLayers.Layer.WMS("Tasmania Roads",
+ "http://demo.opengeo.org/geoserver/wms", {
+ layers: "topp:tasmania_roads",
+ transparent: true,
+ format: "image/gif"
+ }, {
+ isBaseLayer: false,
+ buffer: 0,
+ // exclude this layer from layer container nodes
+ displayInLayerSwitcher: false
+ })
+ ]
+ });
+
+ var tree = new Ext.tree.TreePanel({
+ border: true,
+ region: "west",
+ title: "Layers",
+ width: 300,
+ split: true,
+ collapsible: true,
+ //collapseMode: "mini",
+ autoScroll: true,
+ loader: {
+ applyLoader: false
+ },
+ root: {
+ nodeType: "gx_layercontainer",
+ loader: {
+ baseAttrs: {
+ deleteAction: true,
+ upAction: true,
+ downAction: true,
+ opacitySlider: true
+ }
+ }
+ },
+ rootVisible: false,
+ lines: false
+ });
+
+ new Ext.Viewport({
+ layout: "fit",
+ hideBorders: true,
+ items: {
+ layout: "border",
+ deferredRender: false,
+ items: [mapPanel, tree]
+ }
+ });
+});
Modified: sandbox/elemoine/playground/geoext/lib/GeoExt/widgets/tree/LayerNode.js
===================================================================
--- sandbox/elemoine/playground/geoext/lib/GeoExt/widgets/tree/LayerNode.js 2009-07-29 09:38:05 UTC (rev 1294)
+++ sandbox/elemoine/playground/geoext/lib/GeoExt/widgets/tree/LayerNode.js 2009-07-29 14:06:15 UTC (rev 1295)
@@ -14,6 +14,9 @@
* Place in a separate file if this should be documented.
*/
GeoExt.tree.LayerNodeUI = Ext.extend(Ext.tree.TreeNodeUI, {
+ // FIXME
+ actionsCls: 'x-tree-node-actions',
+ actionCls: 'x-tree-node-action',
/** private: property[radio]
* ``Ext.Element``
@@ -34,22 +37,114 @@
if (a.checked === undefined) {
a.checked = this.node.layer.getVisibility();
}
- GeoExt.tree.LayerNodeUI.superclass.render.call(this, bulkRender);
- if (a.radioGroup && this.radio === null) {
- this.radio = Ext.DomHelper.insertAfter(this.checkbox,
- ['<input type="radio" class="gx-tree-layer-radio" name="',
- a.radioGroup, '_radio"></input>'].join(""));
+ var rendered = this.rendered;
+ GeoExt.tree.LayerNodeUI.superclass.render.apply(this, arguments);
+ if(!rendered) {
+ var cb = this.checkbox;
+ var rg = a.radioGroup || this.radioGroup;
+ var cg = a.checkedGroup || this.checkedGroup;
+
+ if (rg && this.radio === null) {
+ this.radio = Ext.DomHelper.insertAfter(cb,
+ ['<input type="radio" class="gx-tree-layer-radio" name="',
+ rg, '_radio"></input>'].join(""));
+ }
+ if(cg) {
+ // replace the checkbox with a radio button
+ var radio = Ext.DomHelper.insertAfter(cb,
+ ['<input type="radio" name="', cg,
+ '_checkbox" class="', cb.className,
+ cb.checked ? '" checked="checked"' : '',
+ '"></input>'].join(""));
+ radio.defaultChecked = cb.defaultChecked;
+ Ext.get(cb).remove();
+ this.checkbox = radio;
+ }
+ this.enforceOneVisible();
+
+ var actions = a.actions || this.actions || [];
+ var deleteAction = a.deleteAction || this.deleteAction;
+ if(deleteAction) {
+ if(typeof deleteAction != "object") {
+ deleteAction = {};
+ }
+ actions.push(Ext.apply({
+ action: "delete",
+ qtip: "delete"
+ }, deleteAction));
+ }
+ var upAction = a.upAction || this.upAction;
+ if(upAction) {
+ if(typeof upAction != "object") {
+ upAction = {};
+ }
+ actions.push(Ext.apply({
+ action: "move-up",
+ qtip: "move up"
+ }, upAction));
+ }
+ var downAction = a.downAction || this.downAction;
+ if(downAction) {
+ if(typeof downAction != "object") {
+ downAction = {};
+ }
+ actions.push(Ext.apply({
+ action: "move-down",
+ qtip: "move down"
+ }, downAction));
+ }
+ if(actions.length > 0) {
+ var html = ['<div class="', this.actionsCls, '">'];
+ for(var i=0,len=actions.length; i<len; i++) {
+ var _a = actions[i];
+ html = html.concat(['<img id="'+this.node.id+'_'+_a.action,
+ '" ext:qtip="'+_a.qtip,
+ '" src="'+this.emptyIcon,
+ '" class="'+this.actionCls+' '+_a.action+'" />'
+ ]);
+ }
+ html.concat(['</div>']);
+ Ext.DomHelper.insertFirst(this.elNode, html.join(''));
+ }
+
+ var component = a.component || this.component;
+ var opacitySlider = a.opacitySlider || this.opacitySlider;
+ if(opacitySlider) {
+ // add div in the node
+ var elt = Ext.DomHelper.append(this.elNode, [
+ {"tag": "div"}//, "style": "position:relative;left:20"}
+ ]);
+ var slider = new GeoExt.LayerOpacitySlider({
+ layer: this.node.layer,
+ width: 200
+ });
+ new Ext.Toolbar({
+ renderTo: elt,
+ cls: "gx-toolbar",
+ buttons: [slider, "->", {
+ iconCls: "info",
+ handler: function() {
+ new Ext.Window({
+ html: this.node.layer.name,
+ height: 200,
+ width: 200
+ }).show();
+ },
+ scope: this
+ }]
+ });
+ /*
+ if(typeof comp == "function") {
+ comp(this.node, elt);
+ } else if(typeof comp == "object" &&
+ typeof comp.fn == "function") {
+ comp.apply(comp.scope, [this.node, elt]);
+ } else if(comp instanceof Ext.Component) {
+ comp.render(elt);
+ }
+ */
+ }
}
- if(a.checkedGroup) {
- // replace the checkbox with a radio button
- var radio = Ext.DomHelper.insertAfter(this.checkbox,
- ['<input type="radio" name="', a.checkedGroup,
- '_checkbox" class="', this.checkbox.className,
- this.checkbox.checked ? '" checked="checked"' : '',
- '"></input>'].join(""));
- Ext.get(this.checkbox).remove();
- this.checkbox = radio;
- }
},
/** private: method[onClick]
@@ -59,34 +154,89 @@
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 if(e.getTarget('.' + this.actionCls, 1)) {
+ //var action = t.className.replace(this.actionCls + ' ', '');
+ //FIXME
+ alert("yo");
} 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 +306,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 +358,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 +383,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 +405,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 +415,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 +451,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 +522,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: sandbox/elemoine/playground/geoext/tests/lib/GeoExt/widgets/tree/LayerNode.html
===================================================================
--- sandbox/elemoine/playground/geoext/tests/lib/GeoExt/widgets/tree/LayerNode.html 2009-07-29 09:38:05 UTC (rev 1294)
+++ sandbox/elemoine/playground/geoext/tests/lib/GeoExt/widgets/tree/LayerNode.html 2009-07-29 14:06:15 UTC (rev 1295)
@@ -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