[Commits] r2515 - sandbox/mapgears/geoext.ux/ux/LayerTreeBuilder/lib/GeoExt.ux/widgets/tree
commits at geoext.org
commits at geoext.org
Tue Dec 7 21:16:37 CET 2010
Author: adube
Date: 2010-12-07 21:16:37 +0100 (Tue, 07 Dec 2010)
New Revision: 2515
Modified:
sandbox/mapgears/geoext.ux/ux/LayerTreeBuilder/lib/GeoExt.ux/widgets/tree/LayerTreeBuilder.js
Log:
LayerTreeBuilder - 'checkableGroupNodes' new property to have checkboxes for group nodes
Modified: sandbox/mapgears/geoext.ux/ux/LayerTreeBuilder/lib/GeoExt.ux/widgets/tree/LayerTreeBuilder.js
===================================================================
--- sandbox/mapgears/geoext.ux/ux/LayerTreeBuilder/lib/GeoExt.ux/widgets/tree/LayerTreeBuilder.js 2010-12-05 08:22:00 UTC (rev 2514)
+++ sandbox/mapgears/geoext.ux/ux/LayerTreeBuilder/lib/GeoExt.ux/widgets/tree/LayerTreeBuilder.js 2010-12-07 20:16:37 UTC (rev 2515)
@@ -27,6 +27,13 @@
*/
vectorLegendNodes: true,
+ /** api: config[checkableGroupNodes]
+ * ``Boolean``
+ * Defaults to true. Whether LayerContainer and TreeNode nodes used as
+ * group directories should be checkable or not.
+ */
+ checkableGroupNodes: true,
+
/** api: config[layerStore]
* ``GeoExt.data.LayerStore``
* The layer store containing layers to be displayed in the tree.
@@ -60,51 +67,42 @@
"remove": this.onLayerRemoved,
scope: this
});
+
+ this.layerStore.treeBuilder = this;
},
onLayerRemoved: function(store, records, index){
//todo: remove empty groups
},
- onLayerAdded: function(store, records, index){
+ onLayerAdded: function(store, records, index) {
+ // first, validate all 'group' options
Ext.each(records, function(record, index) {
var layer = record.getLayer();
- var group;
- var groupString;
- // do not add layers that have 'displayInLayerSwitcher' property
- // set to false. Remove its 'group' property and option as well.
- if(layer.displayInLayerSwitcher === false)
- {
- if(layer.group && layer.options && layer.options.group)
- {
+ if(layer.displayInLayerSwitcher === false) {
+ if(layer.group && layer.options && layer.options.group) {
delete layer.group;
delete layer.options.group;
}
return;
- }
-
- // get group array and group string
- if(layer.options && layer.options.group !== undefined)
- {
- group = layer.options.group.split('/');
- groupString = layer.options.group;
- }
- else
- {
- groupString = (layer.isBaseLayer)
+ } else if(layer.options && layer.options.group === undefined) {
+ layer.options.group = (layer.isBaseLayer)
? this.baseLayersText : this.otherLayersText;
- group = [groupString];
- layer.options.group = groupString;
}
+ }, this);
- // get layer title
- var layerTitle = record.data.title
- if(layer.options && layer.options.title)
- {
- layerTitle = layer.options.title;
+ // then, create the nodes according to the records
+ Ext.each(records, function(record, index) {
+ var layer = record.getLayer();
+
+ if(layer.displayInLayerSwitcher === false) {
+ return;
}
+ var group = layer.options.group.split('/');
+ var groupString = layer.options.group;
+
// if layer has no GROUP
if (groupString === "") {
var layerNode = {
@@ -127,6 +125,7 @@
addGroupNodes: function(groups, parentNode, groupString, layerRecord){
var group = groups.shift();
var childNode = this.getNodeByText(parentNode, group);
+ var layer = layerRecord.getLayer();
// if the childNode doesn't exist, we need to create and append it
if (!childNode) {
@@ -134,10 +133,19 @@
// 'LayerContainer'
if (groups.length == 0) {
var createNode;
- var layer = layerRecord.getLayer();
+
+ // default 'baseLayers' and 'otherLayers' groups don't have
+ // checkboxes
+ if (group == this.baseLayersText ||
+ group == this.otherLayersText)
+ {
+ createNode = function(attr) {
+ return GeoExt.tree.LayerLoader.prototype.createNode.call(this, attr);
+ }
+ }
// WMS and Vector layers can have legend nodes if according
// property is enabled
- if (layer instanceof OpenLayers.Layer.WMS
+ else if (layer instanceof OpenLayers.Layer.WMS
&& this.wmsLegendNodes)
{
createNode = function(attr) {
@@ -148,8 +156,16 @@
layerRecord: layerRecord,
showTitle: false,
hidden: !layer.visibility,
- cls: "gx-layertreebuilder-legend"
+ cls: "gx-layertreebuilder-legend",
};
+ if (this.store.treeBuilder.checkableGroupNodes &&
+ !layer.isBaseLayer) {
+ Ext.apply(attr, {
+ listeners: {
+ checkchange: this.store.treeBuilder.checkChange
+ }
+ });
+ }
return GeoExt.tree.LayerLoader.prototype.createNode.call(this, attr);
}
} else if (layer instanceof OpenLayers.Layer.Vector
@@ -165,20 +181,41 @@
hidden: !layer.visibility,
cls: "gx-layertreebuilder-legend"
};
+ if (this.store.treeBuilder.checkableGroupNodes &&
+ !layer.isBaseLayer) {
+ Ext.apply(attr, {
+ listeners: {
+ checkchange: this.store.treeBuilder.checkChange
+ }
+ });
+ }
return GeoExt.tree.LayerLoader.prototype.createNode.call(this, attr);
}
} else {
createNode = function(attr) {
+ if (this.store.treeBuilder.checkableGroupNodes &&
+ !layer.isBaseLayer) {
+ Ext.apply(attr, {
+ listeners: {
+ checkchange: this.store.treeBuilder.checkChange
+ }
+ });
+ }
return GeoExt.tree.LayerLoader.prototype.createNode.call(this, attr);
}
}
-
- parentNode.appendChild({
+
+ childNode = {
text: group,
layerStore: this.layerStore,
allowDrag: false,
nodeType: 'gx_layercontainer',
leaf: false,
+ listeners: {
+ insert: this.onLayerContainerNodeInsert,
+ append: this.onLayerContainerNodeAppend,
+ scope: this
+ },
loader: {
filter: function(record) {
return record.getLayer().options.group == groupString;
@@ -188,24 +225,61 @@
},
createNode: createNode
}
- });
+ };
} else {
// else, create and append a simple node...
- parentNode.appendChild({
+ childNode = {
text: group,
leaf: false,
+ listeners: {
+ append: this.onTreeNodeAppend,
+ scope: this
+ },
allowDrag: false,
nodeType: "node"
- });
+ };
}
+ // apply checkbox if option is set
+ if (this.checkableGroupNodes && group != this.baseLayersText &&
+ group != this.otherLayersText && (!layer || !layer.isBaseLayer))
+ {
+ Ext.apply(childNode, {checked: false});
+ Ext.apply(childNode.listeners, {
+ 'checkchange' : function(node, checked) {
+ // If a parent node is unchecked, uncheck all
+ // the children
+ if (node.getUI().isChecked()) {
+ node.expand();
+ node.eachChild(function(child){
+ child.ui.toggleCheck(true);
+ });
+ }
+ if (!node.getUI().isChecked())
+ {
+ node.expand();
+ node.eachChild(function(child) {
+ child.ui.toggleCheck(false);
+ });
+ }
+ }
+ });
+ }
+
+ parentNode.appendChild(childNode);
+
childNode = this.getNodeByText(parentNode, group);
}
+ // if node contains any child or grand-child with a visible layer,
+ // expand it
+ if (layer && layer.visibility) {
+ childNode.expand();
+ }
+
if (groups.length != 0){
this.addGroupNodes(groups, childNode, groupString, layerRecord);
}
-
},
getNodeByText: function(node, text){
@@ -217,5 +291,161 @@
}
}
return false;
+ },
+
+ checkChange: function(node, checked) {
+ // Map of all the node ids not yet visited by updateNodeCheckbox
+ var unvisitedNodeIds = {};
+ var tree = node.getOwnerTree();
+
+ //
+ // This function updates the node checkbox according to the status of
+ // the descendants. It must be called on a node checkbox nodes only.
+ //
+ // It is called recursively and returns a boolean:
+ // - If the node has no children checkboxes, the status of the checkbox
+ // is returned
+ // - Otherwise, it returns true if all the children witch checkbox are
+ // checked or false in the other case.
+ //
+ // As a side effect, it will update the checkbox state of the node, and
+ // remove visited node ids from the unvisitedNodeIds variable, to
+ // prevent visiting nodes multiple times.
+
+ tree.setNodeChecked= function(nodeOrId, checked, fireEvent) {
+ var node = (nodeOrId instanceof Ext.data.Node) ?
+ nodeOrId : this.getNodeById(nodeOrId);
+
+ if (!node || typeof(node.attributes.checked) != "boolean") {
+ return;
+ }
+
+ if (checked === undefined) {
+ checked = !node.attributes.checked;
+ }
+
+ // update model
+ node.attributes.checked = checked;
+
+ // sync ui
+ if (node.ui && node.ui.checkbox) {
+ node.ui.checkbox.checked = checked;
+ }
+
+ // fire event if required
+ if (fireEvent || (fireEvent === undefined)) {
+ node.fireEvent('checkchange', node, checked);
+ }
+ }
+
+ function updateNodeCheckbox(node) {
+ if (typeof(node.attributes.checked) != "boolean") {
+ throw new Error(arguments.callee.name +
+ " should only be called on checkbox nodes");
+ }
+
+ var checkboxChildren = [];
+ node.eachChild(function(child) {
+ if (typeof(child.attributes.checked) == "boolean")
+ checkboxChildren.push(child);
+ }, this);
+
+ // If this node has no children with checkbox, its checked state
+ // will be returned.
+ if (checkboxChildren.length == 0) {
+ return node.attributes.checked;
+ }
+
+ var allChecked = true;
+ Ext.each(checkboxChildren, function(child) {
+ if (!updateNodeCheckbox(child)) {
+ allChecked = false;
+ return false;
+ }
+ }, this);
+
+ tree.setNodeChecked(node, allChecked, false);
+ delete unvisitedNodeIds[node.id];
+
+ return allChecked;
+ }
+
+ var checkboxNodes = [];
+
+ tree.getRootNode().cascade(function(node) {
+ if (typeof(node.attributes.checked) == "boolean") {
+ checkboxNodes.push(node);
+ unvisitedNodeIds[node.id] = true;
+ }
+ }, this);
+
+ // taking node from the tree order (using shift) should be more
+ // efficient
+ var node;
+ while (node = checkboxNodes.shift()) {
+ if (unvisitedNodeIds[node.id])
+ updateNodeCheckbox(node);
+ }
+ },
+
+ onLayerContainerNodeInsert: function(tree, parentNode, childNode, refNode) {
+ this.validateLayerContainerStatus(parentNode);
+ },
+
+ onLayerContainerNodeAppend: function(tree, parentNode, childNode, index) {
+ this.validateLayerContainerStatus(parentNode);
+ },
+
+ validateLayerContainerStatus: function(node) {
+ var show;
+ Ext.each(node.childNodes, function(childNode, index) {
+ show = true;
+
+ visibility = childNode.layer.visibility;
+ if (!childNode.layer.visibility) {
+ show = false;
+ return false;
+ }
+ });
+
+ // check the checkbox (if any)
+ var checkbox = node.getUI().checkbox;
+ if (checkbox) {
+ checkbox.checked = (show) ? true : false;
+ }
+
+ // expand this node and all its parents
+ show && node.ensureVisible();
+
+ node.parentNode && this.validateTreeNodeStatus(node.parentNode);
+ },
+
+ onTreeNodeAppend: function(tree, parentNode, childNode, index) {
+ this.validateTreeNodeStatus(parentNode);
+ },
+
+ validateTreeNodeStatus: function(node) {
+ var show;
+
+ if (!this.checkableGroupNodes || node.isRoot) {
+ return;
+ }
+
+ Ext.each(node.childNodes, function(childNode, index) {
+ show = true;
+ var checkbox = childNode.getUI().checkbox;
+ if (checkbox && !checkbox.checked) {
+ show = false;
+ return false;
+ }
+ });
+
+ var checkbox = node.getUI().checkbox;
+ if (checkbox) {
+ checkbox.checked = (show) ? true : false;
+ }
+
+ node.parentNode && this.validateTreeNodeStatus(node.parentNode);
}
+
});
More information about the Commits
mailing list