You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by ca...@apache.org on 2007/01/11 23:36:18 UTC

svn commit: r495409 [39/47] - in /myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource: ./ src/ src/animation/ src/cal/ src/charting/ src/charting/svg/ src/charting/vml/ src/collections/ src/crypto/ src/data/ src/data/...

Added: myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/Toolbar.js
URL: http://svn.apache.org/viewvc/myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/Toolbar.js?view=auto&rev=495409
==============================================================================
--- myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/Toolbar.js (added)
+++ myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/Toolbar.js Thu Jan 11 14:35:53 2007
@@ -0,0 +1,944 @@
+/*
+	Copyright (c) 2004-2006, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.1 or above OR the
+	modified BSD license. For more information on Dojo licensing, see:
+
+		http://dojotoolkit.org/community/licensing.shtml
+*/
+
+dojo.provide("dojo.widget.Toolbar");
+
+dojo.require("dojo.widget.*");
+dojo.require("dojo.html.style");
+
+/* ToolbarContainer
+ *******************/
+dojo.widget.defineWidget(
+	"dojo.widget.ToolbarContainer",
+	dojo.widget.HtmlWidget,
+{
+	isContainer: true,
+
+	templateString: '<div class="toolbarContainer" dojoAttachPoint="containerNode"></div>',
+	templateCssPath: dojo.uri.dojoUri("src/widget/templates/Toolbar.css"),
+
+	getItem: function(name) {
+		if(name instanceof dojo.widget.ToolbarItem) { return name; }
+		for(var i = 0; i < this.children.length; i++) {
+			var child = this.children[i];
+			if(child instanceof dojo.widget.Toolbar) {
+				var item = child.getItem(name);
+				if(item) { return item; }
+			}
+		}
+		return null;
+	},
+
+	getItems: function() {
+		var items = [];
+		for(var i = 0; i < this.children.length; i++) {
+			var child = this.children[i];
+			if(child instanceof dojo.widget.Toolbar) {
+				items = items.concat(child.getItems());
+			}
+		}
+		return items;
+	},
+
+	enable: function() {
+		for(var i = 0; i < this.children.length; i++) {
+			var child = this.children[i];
+			if(child instanceof dojo.widget.Toolbar) {
+				child.enable.apply(child, arguments);
+			}
+		}
+	},
+
+	disable: function() {
+		for(var i = 0; i < this.children.length; i++) {
+			var child = this.children[i];
+			if(child instanceof dojo.widget.Toolbar) {
+				child.disable.apply(child, arguments);
+			}
+		}
+	},
+
+	select: function(name) {
+		for(var i = 0; i < this.children.length; i++) {
+			var child = this.children[i];
+			if(child instanceof dojo.widget.Toolbar) {
+				child.select(arguments);
+			}
+		}
+	},
+
+	deselect: function(name) {
+		for(var i = 0; i < this.children.length; i++) {
+			var child = this.children[i];
+			if(child instanceof dojo.widget.Toolbar) {
+				child.deselect(arguments);
+			}
+		}
+	},
+
+	getItemsState: function() {
+		var values = {};
+		for(var i = 0; i < this.children.length; i++) {
+			var child = this.children[i];
+			if(child instanceof dojo.widget.Toolbar) {
+				dojo.lang.mixin(values, child.getItemsState());
+			}
+		}
+		return values;
+	},
+
+	getItemsActiveState: function() {
+		var values = {};
+		for(var i = 0; i < this.children.length; i++) {
+			var child = this.children[i];
+			if(child instanceof dojo.widget.Toolbar) {
+				dojo.lang.mixin(values, child.getItemsActiveState());
+			}
+		}
+		return values;
+	},
+
+	getItemsSelectedState: function() {
+		var values = {};
+		for(var i = 0; i < this.children.length; i++) {
+			var child = this.children[i];
+			if(child instanceof dojo.widget.Toolbar) {
+				dojo.lang.mixin(values, child.getItemsSelectedState());
+			}
+		}
+		return values;
+	}
+});
+
+/* Toolbar
+ **********/
+
+dojo.widget.defineWidget(
+	"dojo.widget.Toolbar",
+	dojo.widget.HtmlWidget,
+{
+	isContainer: true,
+
+	templateString: '<div class="toolbar" dojoAttachPoint="containerNode" unselectable="on" dojoOnMouseover="_onmouseover" dojoOnMouseout="_onmouseout" dojoOnClick="_onclick" dojoOnMousedown="_onmousedown" dojoOnMouseup="_onmouseup"></div>',
+
+	// given a node, tries to find it's toolbar item
+	_getItem: function(node) {
+		var start = new Date();
+		var widget = null;
+		while(node && node != this.domNode) {
+			if(dojo.html.hasClass(node, "toolbarItem")) {
+				var widgets = dojo.widget.manager.getWidgetsByFilter(function(w) { return w.domNode == node; });
+				if(widgets.length == 1) {
+					widget = widgets[0];
+					break;
+				} else if(widgets.length > 1) {
+					dojo.raise("Toolbar._getItem: More than one widget matches the node");
+				}
+			}
+			node = node.parentNode;
+		}
+		return widget;
+	},
+
+	_onmouseover: function(e) {
+		var widget = this._getItem(e.target);
+		if(widget && widget._onmouseover) { widget._onmouseover(e); }
+	},
+
+	_onmouseout: function(e) {
+		var widget = this._getItem(e.target);
+		if(widget && widget._onmouseout) { widget._onmouseout(e); }
+	},
+
+	_onclick: function(e) {
+		var widget = this._getItem(e.target);
+		if(widget && widget._onclick){
+			widget._onclick(e);
+		}
+	},
+
+	_onmousedown: function(e) {
+		var widget = this._getItem(e.target);
+		if(widget && widget._onmousedown) { widget._onmousedown(e); }
+	},
+
+	_onmouseup: function(e) {
+		var widget = this._getItem(e.target);
+		if(widget && widget._onmouseup) { widget._onmouseup(e); }
+	},
+
+	addChild: function(item, pos, props) {
+		var widget = dojo.widget.ToolbarItem.make(item, null, props);
+		var ret = dojo.widget.Toolbar.superclass.addChild.call(this, widget, null, pos, null);
+		return ret;
+	},
+
+	push: function() {
+		for(var i = 0; i < arguments.length; i++) {
+			this.addChild(arguments[i]);
+		}
+	},
+
+	getItem: function(name) {
+		if(name instanceof dojo.widget.ToolbarItem) { return name; }
+		for(var i = 0; i < this.children.length; i++) {
+			var child = this.children[i];
+			if(child instanceof dojo.widget.ToolbarItem
+				&& child._name == name) { return child; }
+		}
+		return null;
+	},
+
+	getItems: function() {
+		var items = [];
+		for(var i = 0; i < this.children.length; i++) {
+			var child = this.children[i];
+			if(child instanceof dojo.widget.ToolbarItem) {
+				items.push(child);
+			}
+		}
+		return items;
+	},
+
+	getItemsState: function() {
+		var values = {};
+		for(var i = 0; i < this.children.length; i++) {
+			var child = this.children[i];
+			if(child instanceof dojo.widget.ToolbarItem) {
+				values[child._name] = {
+					selected: child._selected,
+					enabled: !child.disabled
+				};
+			}
+		}
+		return values;
+	},
+
+	getItemsActiveState: function() {
+		var values = this.getItemsState();
+		for(var item in values) {
+			values[item] = values[item].enabled;
+		}
+		return values;
+	},
+
+	getItemsSelectedState: function() {
+		var values = this.getItemsState();
+		for(var item in values) {
+			values[item] = values[item].selected;
+		}
+		return values;
+	},
+
+	enable: function() {
+		var items = arguments.length ? arguments : this.children;
+		for(var i = 0; i < items.length; i++) {
+			var child = this.getItem(items[i]);
+			if(child instanceof dojo.widget.ToolbarItem) {
+				child.enable(false, true);
+			}
+		}
+	},
+
+	disable: function() {
+		var items = arguments.length ? arguments : this.children;
+		for(var i = 0; i < items.length; i++) {
+			var child = this.getItem(items[i]);
+			if(child instanceof dojo.widget.ToolbarItem) {
+				child.disable();
+			}
+		}
+	},
+
+	select: function() {
+		for(var i = 0; i < arguments.length; i++) {
+			var name = arguments[i];
+			var item = this.getItem(name);
+			if(item) { item.select(); }
+		}
+	},
+
+	deselect: function() {
+		for(var i = 0; i < arguments.length; i++) {
+			var name = arguments[i];
+			var item = this.getItem(name);
+			if(item) { item.disable(); }
+		}
+	},
+
+	setValue: function() {
+		for(var i = 0; i < arguments.length; i += 2) {
+			var name = arguments[i], value = arguments[i+1];
+			var item = this.getItem(name);
+			if(item) {
+				if(item instanceof dojo.widget.ToolbarItem) {
+					item.setValue(value);
+				}
+			}
+		}
+	}
+});
+
+/* ToolbarItem hierarchy:
+	- ToolbarItem
+		- ToolbarButton
+		- ToolbarDialog
+			- ToolbarMenu
+		- ToolbarSeparator
+			- ToolbarSpace
+				- ToolbarFlexibleSpace
+*/
+
+
+/* ToolbarItem
+ **************/
+dojo.widget.defineWidget(
+	"dojo.widget.ToolbarItem",
+	dojo.widget.HtmlWidget,
+{
+	templateString: '<span unselectable="on" class="toolbarItem"></span>',
+
+	_name: null,
+	getName: function() { return this._name; },
+	setName: function(value) { return (this._name = value); },
+	getValue: function() { return this.getName(); },
+	setValue: function(value) { return this.setName(value); },
+
+	_selected: false,
+	isSelected: function() { return this._selected; },
+	setSelected: function(is, force, preventEvent) {
+		if(!this._toggleItem && !force) { return; }
+		is = Boolean(is);
+		if(force || !this.disabled && this._selected != is) {
+			this._selected = is;
+			this.update();
+			if(!preventEvent) {
+				this._fireEvent(is ? "onSelect" : "onDeselect");
+				this._fireEvent("onChangeSelect");
+			}
+		}
+	},
+	select: function(force, preventEvent) {
+		return this.setSelected(true, force, preventEvent);
+	},
+	deselect: function(force, preventEvent) {
+		return this.setSelected(false, force, preventEvent);
+	},
+
+	_toggleItem: false,
+	isToggleItem: function() { return this._toggleItem; },
+	setToggleItem: function(value) { this._toggleItem = Boolean(value); },
+
+	toggleSelected: function(force) {
+		return this.setSelected(!this._selected, force);
+	},
+
+	isEnabled: function() { return !this.disabled; },
+	setEnabled: function(is, force, preventEvent) {
+		is = Boolean(is);
+		if(force || this.disabled == is) {
+			this.disabled = !is;
+			this.update();
+			if(!preventEvent) {
+				this._fireEvent(this.disabled ? "onDisable" : "onEnable");
+				this._fireEvent("onChangeEnabled");
+			}
+		}
+		return !this.disabled;
+	},
+	enable: function(force, preventEvent) {
+		return this.setEnabled(true, force, preventEvent);
+	},
+	disable: function(force, preventEvent) {
+		return this.setEnabled(false, force, preventEvent);
+	},
+	toggleEnabled: function(force, preventEvent) {
+		return this.setEnabled(this.disabled, force, preventEvent);
+	},
+
+	_icon: null,
+	getIcon: function() { return this._icon; },
+	setIcon: function(value) {
+		var icon = dojo.widget.Icon.make(value);
+		if(this._icon) {
+			this._icon.setIcon(icon);
+		} else {
+			this._icon = icon;
+		}
+		var iconNode = this._icon.getNode();
+		if(iconNode.parentNode != this.domNode) {
+			if(this.domNode.hasChildNodes()) {
+				this.domNode.insertBefore(iconNode, this.domNode.firstChild);
+			} else {
+				this.domNode.appendChild(iconNode);
+			}
+		}
+		return this._icon;
+	},
+
+	// TODO: update the label node (this.labelNode?)
+	_label: "",
+	getLabel: function() { return this._label; },
+	setLabel: function(value) {
+		var ret = (this._label = value);
+		if(!this.labelNode) {
+			this.labelNode = document.createElement("span");
+			this.domNode.appendChild(this.labelNode);
+		}
+		this.labelNode.innerHTML = "";
+		this.labelNode.appendChild(document.createTextNode(this._label));
+		this.update();
+		return ret;
+	},
+
+	// fired from: setSelected, setEnabled, setLabel
+	update: function() {
+		if(this.disabled) {
+			this._selected = false;
+			dojo.html.addClass(this.domNode, "disabled");
+			dojo.html.removeClass(this.domNode, "down");
+			dojo.html.removeClass(this.domNode, "hover");
+		} else {
+			dojo.html.removeClass(this.domNode, "disabled");
+			if(this._selected) {
+				dojo.html.addClass(this.domNode, "selected");
+			} else {
+				dojo.html.removeClass(this.domNode, "selected");
+			}
+		}
+		this._updateIcon();
+	},
+
+	_updateIcon: function() {
+		if(this._icon) {
+			if(this.disabled) {
+				this._icon.disable();
+			} else {
+				if(this._cssHover) {
+					this._icon.hover();
+				} else if(this._selected) {
+					this._icon.select();
+				} else {
+					this._icon.enable();
+				}
+			}
+		}
+	},
+
+	_fireEvent: function(evt) {
+		if(typeof this[evt] == "function") {
+			var args = [this];
+			for(var i = 1; i < arguments.length; i++) {
+				args.push(arguments[i]);
+			}
+			this[evt].apply(this, args);
+		}
+	},
+
+	_onmouseover: function(e) {
+		if(this.disabled) { return; }
+		dojo.html.addClass(this.domNode, "hover");
+		this._fireEvent("onMouseOver");
+	},
+
+	_onmouseout: function(e) {
+		dojo.html.removeClass(this.domNode, "hover");
+		dojo.html.removeClass(this.domNode, "down");
+		if(!this._selected) {
+			dojo.html.removeClass(this.domNode, "selected");
+		}
+		this._fireEvent("onMouseOut");
+	},
+
+	_onclick: function(e) {
+		// dojo.debug("widget:", this.widgetType, ":", this.getName(), ", disabled:", this.disabled);
+		if(!this.disabled && !this._toggleItem) {
+			this._fireEvent("onClick");
+		}
+	},
+
+	_onmousedown: function(e) {
+		if(e.preventDefault) { e.preventDefault(); }
+		if(this.disabled) { return; }
+		dojo.html.addClass(this.domNode, "down");
+		if(this._toggleItem) {
+			if(this.parent.preventDeselect && this._selected) {
+				return;
+			}
+			this.toggleSelected();
+		}
+		this._fireEvent("onMouseDown");
+	},
+
+	_onmouseup: function(e) {
+		dojo.html.removeClass(this.domNode, "down");
+		this._fireEvent("onMouseUp");
+	},
+
+	onClick: function() { },
+	onMouseOver: function() { },
+	onMouseOut: function() { },
+	onMouseDown: function() { },
+	onMouseUp: function() { },
+
+	fillInTemplate: function(args, frag) {
+		if(args.name) { this._name = args.name; }
+		if(args.selected) { this.select(); }
+		if(args.disabled) { this.disable(); }
+		if(args.label) { this.setLabel(args.label); }
+		if(args.icon) { this.setIcon(args.icon); }
+		if(args.toggleitem||args.toggleItem) { this.setToggleItem(true); }
+	}
+});
+
+dojo.widget.ToolbarItem.make = function(wh, whIsType, props) {
+	var item = null;
+
+	if(wh instanceof Array) {
+		item = dojo.widget.createWidget("ToolbarButtonGroup", props);
+		item.setName(wh[0]);
+		for(var i = 1; i < wh.length; i++) {
+			item.addChild(wh[i]);
+		}
+	} else if(wh instanceof dojo.widget.ToolbarItem) {
+		item = wh;
+	} else if(wh instanceof dojo.uri.Uri) {
+		item = dojo.widget.createWidget("ToolbarButton",
+			dojo.lang.mixin(props||{}, {icon: new dojo.widget.Icon(wh.toString())}));
+	} else if(whIsType) {
+		item = dojo.widget.createWidget(wh, props);
+	} else if(typeof wh == "string" || wh instanceof String) {
+		switch(wh.charAt(0)) {
+			case "|":
+			case "-":
+			case "/":
+				item = dojo.widget.createWidget("ToolbarSeparator", props);
+				break;
+			case " ":
+				if(wh.length == 1) {
+					item = dojo.widget.createWidget("ToolbarSpace", props);
+				} else {
+					item = dojo.widget.createWidget("ToolbarFlexibleSpace", props);
+				}
+				break;
+			default:
+				if(/\.(gif|jpg|jpeg|png)$/i.test(wh)) {
+					item = dojo.widget.createWidget("ToolbarButton",
+						dojo.lang.mixin(props||{}, {icon: new dojo.widget.Icon(wh.toString())}));
+				} else {
+					item = dojo.widget.createWidget("ToolbarButton",
+						dojo.lang.mixin(props||{}, {label: wh.toString()}));
+				}
+		}
+	} else if(wh && wh.tagName && /^img$/i.test(wh.tagName)) {
+		item = dojo.widget.createWidget("ToolbarButton",
+			dojo.lang.mixin(props||{}, {icon: wh}));
+	} else {
+		item = dojo.widget.createWidget("ToolbarButton",
+			dojo.lang.mixin(props||{}, {label: wh.toString()}));
+	}
+	return item;
+}
+
+/* ToolbarButtonGroup
+ *********************/
+dojo.widget.defineWidget(
+	"dojo.widget.ToolbarButtonGroup",
+	dojo.widget.ToolbarItem,
+{
+	isContainer: true,
+
+	templateString: '<span unselectable="on" class="toolbarButtonGroup" dojoAttachPoint="containerNode"></span>',
+
+	// if a button has the same name, it will be selected
+	// if this is set to a number, the button at that index will be selected
+	defaultButton: "",
+
+    postCreate: function() {
+        for (var i = 0; i < this.children.length; i++) {
+            this._injectChild(this.children[i]);
+        }
+    },
+
+	addChild: function(item, pos, props) {
+		var widget = dojo.widget.ToolbarItem.make(item, null, dojo.lang.mixin(props||{}, {toggleItem:true}));
+		var ret = dojo.widget.ToolbarButtonGroup.superclass.addChild.call(this, widget, null, pos, null);
+        this._injectChild(widget);
+        return ret;
+    },
+
+    _injectChild: function(widget) {
+        dojo.event.connect(widget, "onSelect", this, "onChildSelected");
+        dojo.event.connect(widget, "onDeselect", this, "onChildDeSelected");
+        if(widget._name == this.defaultButton
+			|| (typeof this.defaultButton == "number"
+			&& this.children.length-1 == this.defaultButton)) {
+			widget.select(false, true);
+		}
+	},
+
+	getItem: function(name) {
+		if(name instanceof dojo.widget.ToolbarItem) { return name; }
+		for(var i = 0; i < this.children.length; i++) {
+			var child = this.children[i];
+			if(child instanceof dojo.widget.ToolbarItem
+				&& child._name == name) { return child; }
+		}
+		return null;
+	},
+
+	getItems: function() {
+		var items = [];
+		for(var i = 0; i < this.children.length; i++) {
+			var child = this.children[i];
+			if(child instanceof dojo.widget.ToolbarItem) {
+				items.push(child);
+			}
+		}
+		return items;
+	},
+
+	onChildSelected: function(e) {
+		this.select(e._name);
+	},
+
+	onChildDeSelected: function(e) {
+		this._fireEvent("onChangeSelect", this._value);
+	},
+
+	enable: function(force, preventEvent) {
+		for(var i = 0; i < this.children.length; i++) {
+			var child = this.children[i];
+			if(child instanceof dojo.widget.ToolbarItem) {
+				child.enable(force, preventEvent);
+				if(child._name == this._value) {
+					child.select(force, preventEvent);
+				}
+			}
+		}
+	},
+
+	disable: function(force, preventEvent) {
+		for(var i = 0; i < this.children.length; i++) {
+			var child = this.children[i];
+			if(child instanceof dojo.widget.ToolbarItem) {
+				child.disable(force, preventEvent);
+			}
+		}
+	},
+
+	_value: "",
+	getValue: function() { return this._value; },
+
+	select: function(name, force, preventEvent) {
+		for(var i = 0; i < this.children.length; i++) {
+			var child = this.children[i];
+			if(child instanceof dojo.widget.ToolbarItem) {
+				if(child._name == name) {
+					child.select(force, preventEvent);
+					this._value = name;
+				} else {
+					child.deselect(true, true);
+				}
+			}
+		}
+		if(!preventEvent) {
+			this._fireEvent("onSelect", this._value);
+			this._fireEvent("onChangeSelect", this._value);
+		}
+	},
+	setValue: this.select,
+
+	preventDeselect: false // if true, once you select one, you can't have none selected
+});
+
+/* ToolbarButton
+ ***********************/
+dojo.widget.defineWidget(
+	"dojo.widget.ToolbarButton",
+	dojo.widget.ToolbarItem,
+{
+	fillInTemplate: function(args, frag) {
+		dojo.widget.ToolbarButton.superclass.fillInTemplate.call(this, args, frag);
+		dojo.html.addClass(this.domNode, "toolbarButton");
+		if(this._icon) {
+			this.setIcon(this._icon);
+		}
+		if(this._label) {
+			this.setLabel(this._label);
+		}
+
+		if(!this._name) {
+			if(this._label) {
+				this.setName(this._label);
+			} else if(this._icon) {
+				var src = this._icon.getSrc("enabled").match(/[\/^]([^\.\/]+)\.(gif|jpg|jpeg|png)$/i);
+				if(src) { this.setName(src[1]); }
+			} else {
+				this._name = this._widgetId;
+			}
+		}
+	}
+});
+
+/* ToolbarDialog
+ **********************/
+dojo.widget.defineWidget(
+	"dojo.widget.ToolbarDialog",
+	dojo.widget.ToolbarButton,
+{
+	fillInTemplate: function (args, frag) {
+		dojo.widget.ToolbarDialog.superclass.fillInTemplate.call(this, args, frag);
+		dojo.event.connect(this, "onSelect", this, "showDialog");
+		dojo.event.connect(this, "onDeselect", this, "hideDialog");
+	},
+
+	showDialog: function (e) {
+		dojo.lang.setTimeout(dojo.event.connect, 1, document, "onmousedown", this, "deselect");
+	},
+
+	hideDialog: function (e) {
+		dojo.event.disconnect(document, "onmousedown", this, "deselect");
+	}
+
+});
+
+/* ToolbarMenu
+ **********************/
+dojo.widget.defineWidget(
+	"dojo.widget.ToolbarMenu",
+	dojo.widget.ToolbarDialog,
+	{}
+);
+
+/* ToolbarMenuItem
+ ******************/
+dojo.widget.ToolbarMenuItem = function() {
+}
+
+/* ToolbarSeparator
+ **********************/
+dojo.widget.defineWidget(
+	"dojo.widget.ToolbarSeparator",
+	dojo.widget.ToolbarItem,
+{
+	templateString: '<span unselectable="on" class="toolbarItem toolbarSeparator"></span>',
+
+	defaultIconPath: new dojo.uri.dojoUri("src/widget/templates/buttons/sep.gif"),
+
+	fillInTemplate: function(args, frag, skip) {
+		dojo.widget.ToolbarSeparator.superclass.fillInTemplate.call(this, args, frag);
+		this._name = this.widgetId;
+		if(!skip) {
+			if(!this._icon) {
+				this.setIcon(this.defaultIconPath);
+			}
+			this.domNode.appendChild(this._icon.getNode());
+		}
+	},
+
+	// don't want events!
+	_onmouseover: null,
+    _onmouseout: null,
+    _onclick: null,
+    _onmousedown: null,
+    _onmouseup: null
+});
+
+/* ToolbarSpace
+ **********************/
+dojo.widget.defineWidget(
+	"dojo.widget.ToolbarSpace",
+	dojo.widget.ToolbarSeparator,
+{
+	fillInTemplate: function(args, frag, skip) {
+		dojo.widget.ToolbarSpace.superclass.fillInTemplate.call(this, args, frag, true);
+		if(!skip) {
+			dojo.html.addClass(this.domNode, "toolbarSpace");
+		}
+	}
+});
+
+/* ToolbarSelect
+ ******************/
+
+dojo.widget.defineWidget(
+	"dojo.widget.ToolbarSelect",
+	dojo.widget.ToolbarItem,
+{
+	templateString: '<span class="toolbarItem toolbarSelect" unselectable="on"><select dojoAttachPoint="selectBox" dojoOnChange="changed"></select></span>',
+
+	fillInTemplate: function(args, frag) {
+		dojo.widget.ToolbarSelect.superclass.fillInTemplate.call(this, args, frag, true);
+		var keys = args.values;
+		var i = 0;
+		for(var val in keys) {
+			var opt = document.createElement("option");
+			opt.setAttribute("value", keys[val]);
+			opt.innerHTML = val;
+			this.selectBox.appendChild(opt);
+		}
+	},
+
+	changed: function(e) {
+		this._fireEvent("onSetValue", this.selectBox.value);
+	},
+
+	setEnabled: function(is, force, preventEvent) {
+		var ret = dojo.widget.ToolbarSelect.superclass.setEnabled.call(this, is, force, preventEvent);
+		this.selectBox.disabled = this.disabled;
+		return ret;
+	},
+
+	// don't want events!
+	_onmouseover: null,
+    _onmouseout: null,
+    _onclick: null,
+    _onmousedown: null,
+    _onmouseup: null
+});
+
+/* Icon
+ *********/
+// arguments can be IMG nodes, Image() instances or URLs -- enabled is the only one required
+dojo.widget.Icon = function(enabled, disabled, hovered, selected){
+	if(!arguments.length){
+		// FIXME: should this be dojo.raise?
+		throw new Error("Icon must have at least an enabled state");
+	}
+	var states = ["enabled", "disabled", "hovered", "selected"];
+	var currentState = "enabled";
+	var domNode = document.createElement("img");
+
+	this.getState = function(){ return currentState; }
+	this.setState = function(value){
+		if(dojo.lang.inArray(states, value)){
+			if(this[value]){
+				currentState = value;
+				var img = this[currentState];
+				if ((dojo.render.html.ie55 || dojo.render.html.ie60) && img.src && img.src.match(/[.]png$/i) ) {
+					domNode.width = img.width||img.offsetWidth;
+					domNode.height = img.height||img.offsetHeight;
+					domNode.setAttribute("src", dojo.uri.dojoUri("src/widget/templates/images/blank.gif").uri);
+					domNode.style.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+img.src+"',sizingMethod='image')";
+				} else {
+					domNode.setAttribute("src", img.src);
+				}
+			}
+		}else{
+			throw new Error("Invalid state set on Icon (state: " + value + ")");
+		}
+	}
+
+	this.setSrc = function(state, value){
+		if(/^img$/i.test(value.tagName)){
+			this[state] = value;
+		}else if(typeof value == "string" || value instanceof String
+			|| value instanceof dojo.uri.Uri){
+			this[state] = new Image();
+			this[state].src = value.toString();
+		}
+		return this[state];
+	}
+
+	this.setIcon = function(icon){
+		for(var i = 0; i < states.length; i++){
+			if(icon[states[i]]){
+				this.setSrc(states[i], icon[states[i]]);
+			}
+		}
+		this.update();
+	}
+
+	this.enable = function(){ this.setState("enabled"); }
+	this.disable = function(){ this.setState("disabled"); }
+	this.hover = function(){ this.setState("hovered"); }
+	this.select = function(){ this.setState("selected"); }
+
+	this.getSize = function(){
+		return {
+			width: domNode.width||domNode.offsetWidth,
+			height: domNode.height||domNode.offsetHeight
+		};
+	}
+
+	this.setSize = function(w, h){
+		domNode.width = w;
+		domNode.height = h;
+		return { width: w, height: h };
+	}
+
+	this.getNode = function(){
+		return domNode;
+	}
+
+	this.getSrc = function(state){
+		if(state){ return this[state].src; }
+		return domNode.src||"";
+	}
+
+	this.update = function(){
+		this.setState(currentState);
+	}
+
+	for(var i = 0; i < states.length; i++){
+		var arg = arguments[i];
+		var state = states[i];
+		this[state] = null;
+		if(!arg){ continue; }
+		this.setSrc(state, arg);
+	}
+
+	this.enable();
+}
+
+dojo.widget.Icon.make = function(a,b,c,d){
+	for(var i = 0; i < arguments.length; i++){
+		if(arguments[i] instanceof dojo.widget.Icon){
+			return arguments[i];
+		}
+	}
+
+	return new dojo.widget.Icon(a,b,c,d);
+}
+
+/* ToolbarColorDialog
+ ******************/
+dojo.widget.defineWidget(
+	"dojo.widget.ToolbarColorDialog",
+	dojo.widget.ToolbarDialog,
+{
+ 	palette: "7x10",
+
+	fillInTemplate: function (args, frag) {
+		dojo.widget.ToolbarColorDialog.superclass.fillInTemplate.call(this, args, frag);
+		this.dialog = dojo.widget.createWidget("ColorPalette", {palette: this.palette});
+		this.dialog.domNode.style.position = "absolute";
+
+		dojo.event.connect(this.dialog, "onColorSelect", this, "_setValue");
+	},
+
+	_setValue: function(color) {
+		this._value = color;
+		this._fireEvent("onSetValue", color);
+	},
+
+	showDialog: function (e) {
+		dojo.widget.ToolbarColorDialog.superclass.showDialog.call(this, e);
+		var abs = dojo.html.getAbsolutePosition(this.domNode, true);
+		var y = abs.y + dojo.html.getBorderBox(this.domNode).height;
+		this.dialog.showAt(abs.x, y);
+	},
+
+	hideDialog: function (e) {
+		dojo.widget.ToolbarColorDialog.superclass.hideDialog.call(this, e);
+		this.dialog.hide();
+	}
+});
\ No newline at end of file

Added: myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/Tooltip.js
URL: http://svn.apache.org/viewvc/myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/Tooltip.js?view=auto&rev=495409
==============================================================================
--- myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/Tooltip.js (added)
+++ myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/Tooltip.js Thu Jan 11 14:35:53 2007
@@ -0,0 +1,183 @@
+/*
+	Copyright (c) 2004-2006, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.1 or above OR the
+	modified BSD license. For more information on Dojo licensing, see:
+
+		http://dojotoolkit.org/community/licensing.shtml
+*/
+
+dojo.provide("dojo.widget.Tooltip");
+
+dojo.require("dojo.widget.ContentPane");
+dojo.require("dojo.widget.PopupContainer");
+dojo.require("dojo.uri.Uri");
+dojo.require("dojo.widget.*");
+dojo.require("dojo.event.*");
+dojo.require("dojo.html.style");
+dojo.require("dojo.html.util");
+
+dojo.widget.defineWidget(
+	"dojo.widget.Tooltip",
+	[dojo.widget.ContentPane, dojo.widget.PopupContainerBase],
+	{
+		// summary
+		//		Pops up a tooltip (a help message) when you hover over a node
+
+		// caption: String
+		//		Text to display in the tooltip.
+		//		Can also be specified as innerHTML (when creating the widget from markup).
+		caption: "",
+		
+		// showDelay: Integer
+		//		Number of milliseconds to wait after hovering over the object, before
+		//		the tooltip is displayed.
+		showDelay: 500,
+		
+		// hideDelay: Integer
+		//		Number of milliseconds to wait after moving mouse off of the object (or
+		//		off of the tooltip itself), before erasing the tooltip
+		hideDelay: 100,
+		
+		// connectId: String
+		//		Id of domNode to attach the tooltip to.
+		//		(When user hovers over specified dom node, the tooltip will appear.)
+		connectId: "",
+
+		templateCssPath: dojo.uri.dojoUri("src/widget/templates/TooltipTemplate.css"),
+
+		fillInTemplate: function(args, frag){
+			if(this.caption != ""){
+				this.domNode.appendChild(document.createTextNode(this.caption));
+			}
+			this._connectNode = dojo.byId(this.connectId);
+			dojo.widget.Tooltip.superclass.fillInTemplate.call(this, args, frag);
+
+			this.addOnLoad(this, "_loadedContent");
+			dojo.html.addClass(this.domNode, "dojoTooltip");
+
+			//copy style from input node to output node
+			var source = this.getFragNodeRef(frag);
+			dojo.html.copyStyle(this.domNode, source);
+
+			//apply the necessary css rules to the node so that it can popup
+			this.applyPopupBasicStyle();
+		},
+
+		postCreate: function(args, frag){
+			dojo.event.connect(this._connectNode, "onmouseover", this, "_onMouseOver");
+			dojo.widget.Tooltip.superclass.postCreate.call(this, args, frag);
+		},
+
+		_onMouseOver: function(e){
+			this._mouse = {x: e.pageX, y: e.pageY};
+
+			// Start tracking mouse movements, so we know when to cancel timers or erase the tooltip
+			if(!this._tracking){
+				dojo.event.connect(document.documentElement, "onmousemove", this, "_onMouseMove");
+				this._tracking=true;
+			}
+
+			this._onHover(e);			
+		},
+
+		_onMouseMove: function(e) {
+			this._mouse = {x: e.pageX, y: e.pageY};
+
+			if(dojo.html.overElement(this._connectNode, e) || dojo.html.overElement(this.domNode, e)){
+				this._onHover(e);
+			} else {
+				// mouse has been moved off the element/tooltip
+				// note: can't use onMouseOut to detect this because the "explode" effect causes
+				// spurious onMouseOut events (due to interference from outline), w/out corresponding _onMouseOver
+				this._onUnHover(e);
+			}
+		},
+
+		_onHover: function(e) {
+			if(this._hover){ return; }
+			this._hover=true;
+
+			// If the tooltip has been scheduled to be erased, cancel that timer
+			// since we are hovering over element/tooltip again
+			if(this._hideTimer) {
+				clearTimeout(this._hideTimer);
+				delete this._hideTimer;
+			}
+			
+			// If tooltip not showing yet then set a timer to show it shortly
+			if(!this.isShowingNow && !this._showTimer){
+				this._showTimer = setTimeout(dojo.lang.hitch(this, "open"), this.showDelay);
+			}
+		},
+
+		_onUnHover: function(e){
+			if(!this._hover){ return; }
+			this._hover=false;
+
+			if(this._showTimer){
+				clearTimeout(this._showTimer);
+				delete this._showTimer;
+			}
+			if(this.isShowingNow && !this._hideTimer){
+				this._hideTimer = setTimeout(dojo.lang.hitch(this, "close"), this.hideDelay);
+			}
+			
+			// If we aren't showing the tooltip, then we can stop tracking the mouse now;
+			// otherwise must track the mouse until tooltip disappears
+			if(!this.isShowingNow){
+				dojo.event.disconnect(document.documentElement, "onmousemove", this, "_onMouseMove");
+				this._tracking=false;
+			}
+		},
+
+		open: function() {
+			// summary: display the tooltip; usually not called directly.
+
+			if (this.isShowingNow) { return; }
+			dojo.widget.PopupContainerBase.prototype.open.call(this, this._mouse.x, this._mouse.y, null, [this._mouse.x, this._mouse.y], "TL,TR,BL,BR", [10,15]);
+		},
+
+		close: function() {
+			// summary: hide the tooltip; usually not called directly.
+			if (this.isShowingNow) {
+				if ( this._showTimer ) {
+					clearTimeout(this._showTimer);
+					delete this._showTimer;
+				}
+				if ( this._hideTimer ) {
+					clearTimeout(this._hideTimer);
+					delete this._hideTimer;
+				}
+				dojo.event.disconnect(document.documentElement, "onmousemove", this, "_onMouseMove");
+				this._tracking=false;
+				dojo.widget.PopupContainerBase.prototype.close.call(this);
+			}
+		},
+
+		_position: function(){
+			this.move(this._mouse.x, this._mouse.y, [10,15], "TL,TR,BL,BR");
+		},
+
+		_loadedContent: function(){
+			if(this.isShowingNow){
+				// the tooltip has changed size due to downloaded contents, so reposition it
+				this._position();
+			}
+		},
+
+		checkSize: function(){
+			// Override checkSize() in HtmlWidget.
+			// checkSize() is called when the user has resized the browser window,
+			// but that doesn't affect this widget (or this widget's children)
+			// so it can be safely ignored
+		},
+
+		uninitialize: function(){
+			this.close();
+			dojo.event.disconnect(this._connectNode, "onmouseover", this, "_onMouseOver");
+		}
+
+	}
+);

Added: myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/Tree.js
URL: http://svn.apache.org/viewvc/myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/Tree.js?view=auto&rev=495409
==============================================================================
--- myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/Tree.js (added)
+++ myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/Tree.js Thu Jan 11 14:35:53 2007
@@ -0,0 +1,563 @@
+/*
+	Copyright (c) 2004-2006, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.1 or above OR the
+	modified BSD license. For more information on Dojo licensing, see:
+
+		http://dojotoolkit.org/community/licensing.shtml
+*/
+
+/**
+ * Tree model does all the drawing, visual node management etc.
+ * Throws events about clicks on it, so someone may catch them and process
+ * Tree knows nothing about DnD stuff, covered in TreeDragAndDrop and (if enabled) attached by controller
+*/
+
+/**
+ * TODO: use domNode.cloneNode instead of createElement for grid
+ * Should be faster (lyxsus)
+ */
+dojo.provide("dojo.widget.Tree");
+
+dojo.require("dojo.widget.*");
+dojo.require("dojo.event.*");
+dojo.require("dojo.io.*");
+dojo.require("dojo.widget.HtmlWidget");
+dojo.require("dojo.widget.TreeNode");
+dojo.require("dojo.html.common");
+dojo.require("dojo.html.selection");
+
+
+dojo.widget.defineWidget("dojo.widget.Tree", dojo.widget.HtmlWidget, function() {
+	this.eventNames = {};
+
+	this.tree = this;
+	this.DNDAcceptTypes = [];
+	this.actionsDisabled = [];
+
+},
+{
+	widgetType: "Tree",
+
+	eventNamesDefault: {
+		// new child does not get domNode filled in (only template draft)
+		// until addChild->createDOMNode is called(program way) OR createDOMNode (html-way)
+		// hook events to operate on new DOMNode, create dropTargets etc
+		createDOMNode: "createDOMNode",
+		// tree created.. Perform tree-wide actions if needed
+		treeCreate: "treeCreate",
+		treeDestroy: "treeDestroy",
+		// expand icon clicked
+		treeClick: "treeClick",
+		// node icon clicked
+		iconClick: "iconClick",
+		// node title clicked
+		titleClick: "titleClick",
+
+		moveFrom: "moveFrom",
+		moveTo: "moveTo",
+		addChild: "addChild",
+		removeNode: "removeNode",
+		expand: "expand",
+		collapse: "collapse"
+	},
+
+	isContainer: true,
+
+	DNDMode: "off",
+
+	lockLevel: 0, // lock ++ unlock --, so nested locking works fine
+
+	strictFolders: true,
+
+	DNDModes: {
+		BETWEEN: 1,
+		ONTO: 2
+	},
+
+	DNDAcceptTypes: "",
+
+	templateCssPath: dojo.uri.dojoUri("src/widget/templates/images/Tree/Tree.css"),
+
+	templateString: '<div class="dojoTree"></div>',
+
+	isExpanded: true, // consider this "root node" to be always expanded
+
+	isTree: true,
+
+	objectId: "",
+
+	// autoCreate if not "off"
+	// used to get the autocreated controller ONLY.
+	// generally, tree DOES NOT KNOW about its CONTROLLER, it just doesn't care
+	// controller gets messages via dojo.event
+	controller: "",
+
+	// autoCreate if not "off"
+	// used to get the autocreated selector ONLY.
+	// generally, tree DOES NOT KNOW its SELECTOR
+	// binding is made with dojo.event
+	selector: "",
+
+	// used ONLY at initialization time
+	menu: "", // autobind menu if menu's widgetId is set here
+
+	expandLevel: "", // expand to level automatically
+
+	//
+	// these icons control the grid and expando buttons for the whole tree
+	//
+
+	blankIconSrc: dojo.uri.dojoUri("src/widget/templates/images/Tree/treenode_blank.gif"),
+
+	gridIconSrcT: dojo.uri.dojoUri("src/widget/templates/images/Tree/treenode_grid_t.gif"), // for non-last child grid
+	gridIconSrcL: dojo.uri.dojoUri("src/widget/templates/images/Tree/treenode_grid_l.gif"), // for last child grid
+	gridIconSrcV: dojo.uri.dojoUri("src/widget/templates/images/Tree/treenode_grid_v.gif"), // vertical line
+	gridIconSrcP: dojo.uri.dojoUri("src/widget/templates/images/Tree/treenode_grid_p.gif"), // for under parent item child icons
+	gridIconSrcC: dojo.uri.dojoUri("src/widget/templates/images/Tree/treenode_grid_c.gif"), // for under child item child icons
+	gridIconSrcX: dojo.uri.dojoUri("src/widget/templates/images/Tree/treenode_grid_x.gif"), // grid for sole root item
+	gridIconSrcY: dojo.uri.dojoUri("src/widget/templates/images/Tree/treenode_grid_y.gif"), // grid for last rrot item
+	gridIconSrcZ: dojo.uri.dojoUri("src/widget/templates/images/Tree/treenode_grid_z.gif"), // for under root parent item child icon
+
+	expandIconSrcPlus: dojo.uri.dojoUri("src/widget/templates/images/Tree/treenode_expand_plus.gif"),
+	expandIconSrcMinus: dojo.uri.dojoUri("src/widget/templates/images/Tree/treenode_expand_minus.gif"),
+	expandIconSrcLoading: dojo.uri.dojoUri("src/widget/templates/images/Tree/treenode_loading.gif"),
+
+
+	iconWidth: 18,
+	iconHeight: 18,
+
+
+	//
+	// tree options
+	//
+
+	showGrid: true,
+	showRootGrid: true,
+
+	actionIsDisabled: function(action) {
+		var _this = this;
+		return dojo.lang.inArray(_this.actionsDisabled, action)
+	},
+
+
+	actions: {
+    	ADDCHILD: "ADDCHILD"
+	},
+
+
+	getInfo: function() {
+		var info = {
+			widgetId: this.widgetId,
+			objectId: this.objectId
+		}
+
+		return info;
+	},
+
+	initializeController: function() {
+		if (this.controller != "off") {
+			if (this.controller) {
+				this.controller = dojo.widget.byId(this.controller);
+			}
+			else {
+				// create default controller here
+				dojo.require("dojo.widget.TreeBasicController");
+				this.controller = dojo.widget.createWidget("TreeBasicController",
+					{ DNDController: (this.DNDMode ? "create" : ""), dieWithTree: true }
+				 );
+
+			}
+			this.controller.listenTree(this); // controller listens to my events
+
+		} else {
+			this.controller = null;
+		}
+	},
+
+	initializeSelector: function() {
+
+		if (this.selector != "off") {
+			if (this.selector) {
+				this.selector = dojo.widget.byId(this.selector);
+			}
+			else {
+				// create default controller here
+				dojo.require("dojo.widget.TreeSelector");
+				this.selector = dojo.widget.createWidget("TreeSelector", {dieWithTree: true});
+			}
+
+			this.selector.listenTree(this);
+
+		} else {
+			this.selector = null;
+		}
+	},
+
+	initialize: function(args, frag){
+
+		var _this = this;
+
+		for(name in this.eventNamesDefault) {
+			if (dojo.lang.isUndefined(this.eventNames[name])) {
+				this.eventNames[name] = this.widgetId+"/"+this.eventNamesDefault[name];
+			}
+		}
+
+		for(var i=0; i<this.actionsDisabled.length; i++) {
+			this.actionsDisabled[i] = this.actionsDisabled[i].toUpperCase();
+		}
+
+		if (this.DNDMode == "off") {
+			this.DNDMode = 0;
+		} else if (this.DNDMode == "between") {
+			this.DNDMode = this.DNDModes.ONTO | this.DNDModes.BETWEEN;
+		} else if (this.DNDMode == "onto") {
+			this.DNDMode = this.DNDModes.ONTO;
+		}
+
+		this.expandLevel = parseInt(this.expandLevel);
+
+		this.initializeSelector();
+		this.initializeController();
+
+		if (this.menu) {
+			this.menu = dojo.widget.byId(this.menu);
+			this.menu.listenTree(this);
+		}
+
+
+		this.containerNode = this.domNode;
+
+	},
+
+
+	postCreate: function() {
+		this.createDOMNode();
+	},
+
+
+	createDOMNode: function() {
+
+		dojo.html.disableSelection(this.domNode);
+
+		for(var i=0; i<this.children.length; i++){
+			this.children[i].parent = this; // root nodes have tree as parent
+
+			var node = this.children[i].createDOMNode(this, 0);
+
+
+			this.domNode.appendChild(node);
+		}
+
+
+		if (!this.showRootGrid){
+			for(var i=0; i<this.children.length; i++){
+				this.children[i].expand();
+			}
+		}
+
+		dojo.event.topic.publish(this.eventNames.treeCreate, { source: this } );
+
+	},
+
+
+	destroy: function() {
+		dojo.event.topic.publish(this.tree.eventNames.treeDestroy, { source: this } );
+
+		return dojo.widget.HtmlWidget.prototype.destroy.apply(this, arguments);
+	},
+
+
+	addChild: function(child, index) {
+
+//		dojo.debug("doAddChild "+index+" called for "+child);
+
+		var message = {
+			child: child,
+			index: index,
+			parent: this,
+			// remember if dom was already initialized
+			// initialized => no createDOMNode => no createDOMNode event
+			domNodeInitialized: child.domNodeInitialized
+		}
+
+		this.doAddChild.apply(this, arguments);
+
+		dojo.event.topic.publish(this.tree.eventNames.addChild, message);
+	},
+
+
+	// not called for initial tree building. See createDOMNode instead.
+	// builds child html node if needed
+	// index is "last node" by default
+	/**
+	 * FIXME: Is it possible that removeNode from the tree will cause leaks cause of attached events ?
+	 * if yes, then only attach events in addChild and detach in remove.. Seems all ok yet.
+	*/
+	doAddChild: function(child, index){
+
+		if (dojo.lang.isUndefined(index)) {
+			index = this.children.length;
+		}
+
+		if (!child.isTreeNode){
+			dojo.raise("You can only add TreeNode widgets to a "+this.widgetType+" widget!");
+			return;
+		}
+
+		// usually it is impossible to change "isFolder" state, but if anyone wants to add a child to leaf,
+		// it is possible program-way.
+		if (this.isTreeNode){
+			if (!this.isFolder) { // just became a folder.
+				//dojo.debug("becoming folder "+this);
+				this.setFolder();
+			}
+		}
+
+		// adjust tree
+		var _this = this;
+		dojo.lang.forEach(child.getDescendants(), function(elem) { elem.tree = _this.tree; });
+
+		// fix parent
+		child.parent = this;
+
+
+		// no dynamic loading for those who become parents
+		if (this.isTreeNode) {
+			this.state = this.loadStates.LOADED;
+		}
+
+		// add new child into DOM after it was added into children
+		if (index < this.children.length) { // children[] already has child
+			//dojo.debug("Inserting before "+this.children[index].title);
+			dojo.html.insertBefore(child.domNode, this.children[index].domNode);
+		} else {
+			this.containerNode.appendChild(child.domNode);
+			if (this.isExpanded && this.isTreeNode) {
+				/* When I add children to hidden containerNode => show container w/ them */
+				this.showChildren();
+			}
+		}
+
+
+		this.children.splice(index, 0, child);
+
+		//dojo.debugShallow(this.children);
+
+
+		// if node exists - adjust its depth, otherwise build it
+		if (child.domNodeInitialized) {
+			var d = this.isTreeNode ? this.depth : -1;
+			child.adjustDepth( d - child.depth + 1 );
+
+
+			// update icons to link generated dom with Tree => updateParentGrid
+			// if I moved child from LastNode inside the tree => need to link it up'n'down =>
+			// updateExpandGridColumn
+			// if I change depth => need to update all grid..
+			child.updateIconTree();
+		} else {
+			//dojo.debug("Create domnode ");
+			child.depth = this.isTreeNode ? this.depth+1 : 0;
+			child.createDOMNode(child.tree, child.depth);
+		}
+
+
+
+		// Use-case:
+		// When previous sibling was created => it was last, no children after it
+		// so it did not create link down => let's add it for all descendants
+		// Use-case:
+		// a child was moved down under the last node so last node should be updated
+		var prevSibling = child.getPreviousSibling();
+		if (child.isLastChild() && prevSibling) {
+			prevSibling.updateExpandGridColumn();
+		}
+
+
+		//dojo.debug("Added child "+child);
+
+
+
+	},
+
+
+
+
+	makeBlankImg: function() {
+		var img = document.createElement('img');
+
+		img.style.width = this.iconWidth + 'px';
+		img.style.height = this.iconHeight + 'px';
+		img.src = this.blankIconSrc;
+		img.style.verticalAlign = 'middle';
+
+		return img;
+	},
+
+
+	updateIconTree: function(){
+
+		//dojo.debug("Update icons for "+this)
+		if (!this.isTree) {
+			this.updateIcons();
+		}
+
+		for(var i=0; i<this.children.length; i++){
+			this.children[i].updateIconTree();
+		}
+
+	},
+
+	toString: function() {
+		return "["+this.widgetType+" ID:"+this.widgetId+"]"
+	},
+
+
+
+
+	/**
+	 * Move child to newParent as last child
+	 * redraw tree and update icons.
+	 *
+	 * Called by target, saves source in event.
+	 * events are published for BOTH trees AFTER update.
+	*/
+	move: function(child, newParent, index) {
+
+		//dojo.debug(child+" "+newParent+" at "+index);
+
+		var oldParent = child.parent;
+		var oldTree = child.tree;
+
+		this.doMove.apply(this, arguments);
+
+		var newParent = child.parent;
+		var newTree = child.tree;
+
+		var message = {
+				oldParent: oldParent, oldTree: oldTree,
+				newParent: newParent, newTree: newTree,
+				child: child
+		};
+
+		/* publish events here about structural changes for both source and target trees */
+		dojo.event.topic.publish(oldTree.eventNames.moveFrom, message);
+		dojo.event.topic.publish(newTree.eventNames.moveTo, message);
+
+	},
+
+
+	/* do actual parent change here. Write remove child first */
+	doMove: function(child, newParent, index) {
+		//var parent = child.parent;
+		child.parent.doRemoveNode(child);
+
+		newParent.doAddChild(child, index);
+	},
+
+
+
+// ================================ removeNode ===================================
+
+	removeNode: function(child) {
+		if (!child.parent) return;
+
+		var oldTree = child.tree;
+		var oldParent = child.parent;
+
+		var removedChild = this.doRemoveNode.apply(this, arguments);
+
+
+		dojo.event.topic.publish(this.tree.eventNames.removeNode,
+			{ child: removedChild, tree: oldTree, parent: oldParent }
+		);
+
+		return removedChild;
+	},
+
+
+	doRemoveNode: function(child) {
+		if (!child.parent) return;
+
+		var parent = child.parent;
+
+		var children = parent.children;
+
+
+		var index = child.getParentIndex();
+		if (index < 0) {
+			dojo.raise("Couldn't find node "+child+" for removal");
+		}
+
+
+		children.splice(index,1);
+		dojo.html.removeNode(child.domNode);
+
+		if (parent.children.length == 0 && !parent.isTree) {
+			parent.containerNode.style.display = "none";
+		}
+
+		// if WAS last node (children.length decreased already) and has prevSibling
+		if (index == children.length && index>0) {
+			children[index-1].updateExpandGridColumn();
+		}
+		// if it WAS first node in WHOLE TREE -
+		// update link up of its former lower neighbour(if exists still)
+		if (parent instanceof dojo.widget.Tree && index == 0 && children.length>0) {
+			children[0].updateExpandGrid();
+		}
+
+		//parent.updateIconTree();
+
+
+		child.parent = child.tree = null;
+
+		return child;
+	},
+
+	markLoading: function() {
+		// no way to mark tree loading
+	},
+
+	unMarkLoading: function() {
+		// no way to show that tree finished loading
+	},
+
+
+	lock: function() {
+		!this.lockLevel && this.markLoading();
+		this.lockLevel++;
+	},
+	unlock: function() {
+		if (!this.lockLevel) {
+			dojo.raise("unlock: not locked");
+		}
+		this.lockLevel--;
+		!this.lockLevel && this.unMarkLoading();
+	},
+
+	isLocked: function() {
+		var node = this;
+		while (true) {
+			if (node.lockLevel) {
+				return true;
+			}
+			if (node instanceof dojo.widget.Tree) {
+				break;
+			}
+			node = node.parent;
+		}
+
+		return false;
+	},
+
+	flushLock: function() {
+		this.lockLevel = 0;
+		this.unMarkLoading();
+	}
+});
+
+

Added: myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/TreeBasicController.js
URL: http://svn.apache.org/viewvc/myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/TreeBasicController.js?view=auto&rev=495409
==============================================================================
--- myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/TreeBasicController.js (added)
+++ myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/TreeBasicController.js Thu Jan 11 14:35:53 2007
@@ -0,0 +1,284 @@
+/*
+	Copyright (c) 2004-2006, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.1 or above OR the
+	modified BSD license. For more information on Dojo licensing, see:
+
+		http://dojotoolkit.org/community/licensing.shtml
+*/
+
+
+dojo.provide("dojo.widget.TreeBasicController");
+
+dojo.require("dojo.event.*");
+dojo.require("dojo.json")
+dojo.require("dojo.io.*");
+
+
+dojo.widget.defineWidget("dojo.widget.TreeBasicController", dojo.widget.HtmlWidget, {
+	widgetType: "TreeBasicController",
+
+	DNDController: "",
+
+	dieWithTree: false,
+
+	initialize: function(args, frag){
+
+		/* no DND by default for compatibility */
+		if (this.DNDController == "create") {
+			dojo.require("dojo.dnd.TreeDragAndDrop");
+			this.DNDController = new dojo.dnd.TreeDNDController(this);
+		}
+
+
+
+	},
+
+
+	/**
+	 * Binds controller to all tree events
+	*/
+	listenTree: function(tree) {
+		//dojo.debug("Event "+tree.eventNames.treeClick);
+		dojo.event.topic.subscribe(tree.eventNames.createDOMNode, this, "onCreateDOMNode");
+		dojo.event.topic.subscribe(tree.eventNames.treeClick, this, "onTreeClick");
+		dojo.event.topic.subscribe(tree.eventNames.treeCreate, this, "onTreeCreate");
+		dojo.event.topic.subscribe(tree.eventNames.treeDestroy, this, "onTreeDestroy");
+
+		if (this.DNDController) {
+			this.DNDController.listenTree(tree);
+		}
+	},
+
+	unlistenTree: function(tree) {
+		dojo.event.topic.unsubscribe(tree.eventNames.createDOMNode, this, "onCreateDOMNode");
+		dojo.event.topic.unsubscribe(tree.eventNames.treeClick, this, "onTreeClick");
+		dojo.event.topic.unsubscribe(tree.eventNames.treeCreate, this, "onTreeCreate");
+		dojo.event.topic.unsubscribe(tree.eventNames.treeDestroy, this, "onTreeDestroy");
+	},
+
+	onTreeDestroy: function(message) {
+		var tree = message.source;
+
+		this.unlistenTree(tree);
+
+		if (this.dieWithTree) {
+			//alert("Killing myself "+this.widgetId);
+			this.destroy();
+			//dojo.debug("done");
+		}
+	},
+
+	onCreateDOMNode: function(message) {
+
+		var node = message.source;
+
+
+		if (node.expandLevel > 0) {
+			this.expandToLevel(node, node.expandLevel);
+		}
+	},
+
+	// perform actions-initializers for tree
+	onTreeCreate: function(message) {
+		var tree = message.source;
+		var _this = this;
+		if (tree.expandLevel) {
+			dojo.lang.forEach(tree.children,
+				function(child) {
+					_this.expandToLevel(child, tree.expandLevel-1)
+				}
+			);
+		}
+	},
+
+	expandToLevel: function(node, level) {
+		if (level == 0) return;
+
+		var children = node.children;
+		var _this = this;
+
+		var handler = function(node, expandLevel) {
+			this.node = node;
+			this.expandLevel = expandLevel;
+			// recursively expand opened node
+			this.process = function() {
+				//dojo.debug("Process "+node+" level "+level);
+				for(var i=0; i<this.node.children.length; i++) {
+					var child = node.children[i];
+
+					_this.expandToLevel(child, this.expandLevel);
+				}
+			};
+		}
+
+		var h = new handler(node, level-1);
+
+
+		this.expand(node, false, h, h.process);
+
+	},
+
+
+
+
+	onTreeClick: function(message){
+		var node = message.source;
+
+		if(node.isLocked()) {
+			return false;
+		}
+
+		if (node.isExpanded){
+			this.collapse(node);
+		} else {
+			this.expand(node);
+		}
+	},
+
+	expand: function(node, sync, callObj, callFunc) {
+		node.expand();
+		if (callFunc) callFunc.apply(callObj, [node]);
+	},
+
+	collapse: function(node) {
+
+		node.collapse();
+	},
+
+// =============================== move ============================
+
+	/**
+	 * Checks whether it is ok to change parent of child to newParent
+	 * May incur type checks etc
+	 *
+	 * It should check only hierarchical possibility w/o index, etc
+	 * because in onDragOver event for Between DND mode we can't calculate index at once on onDragOVer.
+	 * index changes as client moves mouse up-down over the node
+	 */
+	canMove: function(child, newParent){
+
+		if (child.actionIsDisabled(child.actions.MOVE)) {
+			return false;
+		}
+
+		// if we move under same parent then no matter if ADDCHILD disabled for him
+		// but if we move to NEW parent then check if action is disabled for him
+		// also covers case for newParent being a non-folder in strict mode etc
+		if (child.parent !== newParent && newParent.actionIsDisabled(newParent.actions.ADDCHILD)) {
+			return false;
+		}
+
+		// Can't move parent under child. check whether new parent is child of "child".
+		var node = newParent;
+		while(node.isTreeNode) {
+			//dojo.debugShallow(node.title)
+			if (node === child) {
+				// parent of newParent is child
+				return false;
+			}
+			node = node.parent;
+		}
+
+		return true;
+	},
+
+
+	move: function(child, newParent, index) {
+
+		/* move sourceTreeNode to new parent */
+		if (!this.canMove(child, newParent)) {
+			return false;
+		}
+
+		var result = this.doMove(child, newParent, index);
+
+		if (!result) return result;
+
+		if (newParent.isTreeNode) {
+			this.expand(newParent);
+		}
+
+		return result;
+	},
+
+	doMove: function(child, newParent, index) {
+		child.tree.move(child, newParent, index);
+
+		return true;
+	},
+
+// =============================== removeNode ============================
+
+
+	canRemoveNode: function(child) {
+		if (child.actionIsDisabled(child.actions.REMOVE)) {
+			return false;
+		}
+
+		return true;
+	},
+
+
+	removeNode: function(node, callObj, callFunc) {
+		if (!this.canRemoveNode(node)) {
+			return false;
+		}
+
+		return this.doRemoveNode(node, callObj, callFunc);
+	},
+
+
+	doRemoveNode: function(node, callObj, callFunc) {
+		node.tree.removeNode(node);
+
+		if (callFunc) {
+			callFunc.apply(dojo.lang.isUndefined(callObj) ? this : callObj, [node]);
+		}
+	},
+
+
+	// -----------------------------------------------------------------------------
+	//                             Create node stuff
+	// -----------------------------------------------------------------------------
+
+
+	canCreateChild: function(parent, index, data) {
+		if (parent.actionIsDisabled(parent.actions.ADDCHILD)) return false;
+
+		return true;
+	},
+
+
+	/* send data to server and add child from server */
+	/* data may contain an almost ready child, or anything else, suggested to server */
+	/*in RPC controllers server responds with child data to be inserted */
+	createChild: function(parent, index, data, callObj, callFunc) {
+		if (!this.canCreateChild(parent, index, data)) {
+			return false;
+		}
+
+		return this.doCreateChild.apply(this, arguments);
+	},
+
+	doCreateChild: function(parent, index, data, callObj, callFunc) {
+
+		var widgetType = data.widgetType ? data.widgetType : "TreeNode";
+
+		var newChild = dojo.widget.createWidget(widgetType, data);
+
+		parent.addChild(newChild, index);
+
+		this.expand(parent);
+
+		if (callFunc) {
+			callFunc.apply(callObj, [newChild]);
+		}
+
+		return newChild;
+	}
+
+
+
+});

Added: myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/TreeBasicControllerV3.js
URL: http://svn.apache.org/viewvc/myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/TreeBasicControllerV3.js?view=auto&rev=495409
==============================================================================
--- myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/TreeBasicControllerV3.js (added)
+++ myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/TreeBasicControllerV3.js Thu Jan 11 14:35:53 2007
@@ -0,0 +1,831 @@
+/*
+	Copyright (c) 2004-2006, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.1 or above OR the
+	modified BSD license. For more information on Dojo licensing, see:
+
+		http://dojotoolkit.org/community/licensing.shtml
+*/
+
+
+dojo.provide("dojo.widget.TreeBasicControllerV3");
+
+dojo.require("dojo.event.*");
+dojo.require("dojo.json")
+dojo.require("dojo.io.*");
+dojo.require("dojo.widget.TreeCommon");
+dojo.require("dojo.widget.TreeNodeV3");
+dojo.require("dojo.widget.TreeV3");
+
+dojo.widget.defineWidget(
+	"dojo.widget.TreeBasicControllerV3",
+	[dojo.widget.HtmlWidget, dojo.widget.TreeCommon],
+	function(){
+		this.listenedTrees = {};
+	},
+{
+	// TODO: do something with addChild / setChild, so that RpcController become able
+	// to hook on this and report to server
+	
+	// TODO: make sure keyboard control stuff works when node is moved between trees
+	// node should be unfocus()'ed when it its ancestor is moved and tree,lastFocus - cleared
+
+	/**
+	 * TreeCommon.listenTree will attach listeners to these events
+	 *
+	 * The logic behind the naming:
+	 * 1. (after|before)
+	 * 2. if an event refers to tree, then add "Tree"
+	 * 3. add action
+	 */
+	listenTreeEvents: ["afterSetFolder", "afterTreeCreate", "beforeTreeDestroy"],
+	listenNodeFilter: function(elem) { return elem instanceof dojo.widget.Widget},	
+		
+		
+	editor: null,
+
+	
+	initialize: function(args) {
+		if (args.editor) {
+			this.editor = dojo.widget.byId(args.editor);
+			this.editor.controller = this;
+		}
+		
+	},
+		
+	
+	getInfo: function(elem) {
+		return elem.getInfo();
+	},
+
+	onBeforeTreeDestroy: function(message) {
+                this.unlistenTree(message.source);
+	},
+
+	onAfterSetFolder: function(message) {
+		
+		//dojo.profile.start("onTreeChange");
+        
+		if (message.source.expandLevel > 0) {
+			this.expandToLevel(message.source, message.source.expandLevel);				
+		}
+		if (message.source.loadLevel > 0) {
+			this.loadToLevel(message.source, message.source.loadLevel);				
+		}
+			
+		
+		//dojo.profile.end("onTreeChange");
+	},
+	
+
+	// down arrow
+	_focusNextVisible: function(nodeWidget) {
+		
+		// if this is an expanded folder, get the first child
+		if (nodeWidget.isFolder && nodeWidget.isExpanded && nodeWidget.children.length > 0) {
+			returnWidget = nodeWidget.children[0];			
+		} else {
+			// find a parent node with a sibling
+			while (nodeWidget.isTreeNode && nodeWidget.isLastChild()) {
+				nodeWidget = nodeWidget.parent;
+			}
+			
+			if (nodeWidget.isTreeNode) {
+				var returnWidget = nodeWidget.parent.children[nodeWidget.getParentIndex()+1];				
+			}
+			
+		}
+				
+		if (returnWidget && returnWidget.isTreeNode) {
+			this._focusLabel(returnWidget);
+			return returnWidget;
+		}
+		
+	},
+	
+	// up arrow
+	_focusPreviousVisible: function(nodeWidget) {
+		var returnWidget = nodeWidget;
+		
+		// if younger siblings		
+		if (!nodeWidget.isFirstChild()) {
+			var previousSibling = nodeWidget.parent.children[nodeWidget.getParentIndex()-1]
+
+			nodeWidget = previousSibling;
+			// if the previous nodeWidget is expanded, dive in deep
+			while (nodeWidget.isFolder && nodeWidget.isExpanded && nodeWidget.children.length > 0) {
+				returnWidget = nodeWidget;
+				// move to the last child
+				nodeWidget = nodeWidget.children[nodeWidget.children.length-1];
+			}
+		} else {
+			// if this is the first child, return the parent
+			nodeWidget = nodeWidget.parent;
+		}
+		
+		if (nodeWidget && nodeWidget.isTreeNode) {
+			returnWidget = nodeWidget;
+		}
+		
+		if (returnWidget && returnWidget.isTreeNode) {
+			this._focusLabel(returnWidget);
+			return returnWidget;
+		}
+		
+	},
+	
+	// right arrow
+	_focusZoomIn: function(nodeWidget) {
+		var returnWidget = nodeWidget;
+		
+		// if not expanded, expand, else move to 1st child
+		if (nodeWidget.isFolder && !nodeWidget.isExpanded) {
+			this.expand(nodeWidget);
+		}else if (nodeWidget.children.length > 0) {
+			nodeWidget = nodeWidget.children[0];
+		}
+		
+		if (nodeWidget && nodeWidget.isTreeNode) {
+			returnWidget = nodeWidget;
+		}
+		
+		if (returnWidget && returnWidget.isTreeNode) {
+			this._focusLabel(returnWidget);
+			return returnWidget;
+		}
+		
+	},
+	
+	// left arrow
+	_focusZoomOut: function(node) {
+		
+		var returnWidget = node;
+		
+		// if not expanded, expand, else move to 1st child
+		if (node.isFolder && node.isExpanded) {
+			this.collapse(node);
+		} else {
+			node = node.parent;
+		}
+		if (node && node.isTreeNode) {
+			returnWidget = node;
+		}
+		
+		if (returnWidget && returnWidget.isTreeNode) {
+			this._focusLabel(returnWidget);
+			return returnWidget;
+		}
+		
+	},
+	
+	onFocusNode: function(e) {
+		var node = this.domElement2TreeNode(e.target);
+		
+		if (node) {
+			node.viewFocus();			
+			dojo.event.browser.stopEvent(e);
+		}
+	},
+	
+	onBlurNode: function(e) {
+		var node = this.domElement2TreeNode(e.target);
+		
+		if (!node) {
+			return;
+		}
+		
+		var labelNode = node.labelNode;
+		
+		labelNode.setAttribute("tabIndex", "-1");
+		node.viewUnfocus();		
+		dojo.event.browser.stopEvent(e);
+		
+		// this could have been set to -1 by the shift+TAB processing
+		node.tree.domNode.setAttribute("tabIndex", "0");
+		
+	},
+	
+	
+	_focusLabel: function(node) {
+		//dojo.debug((new Error()).stack)		
+		var lastFocused = node.tree.lastFocused;
+		var labelNode;
+		
+		if (lastFocused && lastFocused.labelNode) {
+			labelNode = lastFocused.labelNode;
+			// help Opera out with blur events
+			dojo.event.disconnect(labelNode, "onblur", this, "onBlurNode");
+			labelNode.setAttribute("tabIndex", "-1");
+			dojo.html.removeClass(labelNode, "TreeLabelFocused");
+		}
+		
+		// set tabIndex so that the tab key can find this node
+		labelNode = node.labelNode;
+		labelNode.setAttribute("tabIndex", "0");
+		node.tree.lastFocused = node;
+		
+		// add an outline - this helps opera a lot
+		dojo.html.addClass(labelNode, "TreeLabelFocused");
+		dojo.event.connectOnce(labelNode, "onblur", this, "onBlurNode");
+		// prevent the domNode from seeing the focus event
+		dojo.event.connectOnce(labelNode, "onfocus", this, "onFocusNode");
+		// set focus so that the label wil be voiced using screen readers
+		labelNode.focus();
+			
+	},
+	
+	onKey: function(e) {
+		if (!e.key || e.ctrkKey || e.altKey) { return; }
+		// pretend the key was directed toward the current focused node (helps opera out)
+		
+		var nodeWidget = this.domElement2TreeNode(e.target);
+		if (!nodeWidget) {
+			return;
+		}
+		
+		var treeWidget = nodeWidget.tree;
+		
+		if (treeWidget.lastFocused && treeWidget.lastFocused.labelNode) {
+			nodeWidget = treeWidget.lastFocused;
+		}
+		
+		switch(e.key) {
+			case e.KEY_TAB:
+				if (e.shiftKey) {
+					// we're moving backwards so don't tab to the domNode
+					// it'll be added back in onBlurNode
+					treeWidget.domNode.setAttribute("tabIndex", "-1");
+				}
+				break;
+			case e.KEY_RIGHT_ARROW:
+				this._focusZoomIn(nodeWidget);
+				dojo.event.browser.stopEvent(e);
+				break;
+			case e.KEY_LEFT_ARROW:
+				this._focusZoomOut(nodeWidget);
+				dojo.event.browser.stopEvent(e);
+				break;
+			case e.KEY_UP_ARROW:
+				this._focusPreviousVisible(nodeWidget);
+				dojo.event.browser.stopEvent(e);
+				break;
+			case e.KEY_DOWN_ARROW:
+				this._focusNextVisible(nodeWidget);
+				dojo.event.browser.stopEvent(e);
+				break;
+		}
+	},
+	
+	
+	onFocusTree: function(e) {
+		if (!e.currentTarget) { return; }
+		try {
+			var treeWidget = this.getWidgetByNode(e.currentTarget);
+			if (!treeWidget || !treeWidget.isTree) { return; }
+			// on first focus, choose the root node
+			var nodeWidget = this.getWidgetByNode(treeWidget.domNode.firstChild);
+			if (nodeWidget && nodeWidget.isTreeNode) {
+				if (treeWidget.lastFocused && treeWidget.lastFocused.isTreeNode) { // onClick could have chosen a non-root node
+					nodeWidget = treeWidget.lastFocused;
+				}
+				this._focusLabel(nodeWidget);
+			}
+		}
+		catch(e) {}
+	},
+
+	// perform actions-initializers for tree
+	onAfterTreeCreate: function(message) {
+		var tree = message.source;
+		dojo.event.browser.addListener(tree.domNode, "onKey", dojo.lang.hitch(this, this.onKey));
+		dojo.event.browser.addListener(tree.domNode, "onmousedown", dojo.lang.hitch(this, this.onTreeMouseDown));
+		dojo.event.browser.addListener(tree.domNode, "onclick", dojo.lang.hitch(this, this.onTreeClick));
+		dojo.event.browser.addListener(tree.domNode, "onfocus", dojo.lang.hitch(this, this.onFocusTree));
+		tree.domNode.setAttribute("tabIndex", "0");
+		
+		if (tree.expandLevel) {								
+			this.expandToLevel(tree, tree.expandLevel)
+		}
+		if (tree.loadLevel) {
+			this.loadToLevel(tree, tree.loadLevel);
+		}
+	},
+
+    onTreeMouseDown: function(e) {
+    },
+
+	onTreeClick: function(e){
+		//dojo.profile.start("onTreeClick");
+		
+		var domElement = e.target;
+		//dojo.debug('click')
+		// find node
+        var node = this.domElement2TreeNode(domElement);		
+		if (!node || !node.isTreeNode) {
+			return;
+		}
+		
+		
+		var checkExpandClick = function(el) {
+			return el === node.expandNode;
+		}
+		
+		if (this.checkPathCondition(domElement, checkExpandClick)) {
+			this.processExpandClick(node);			
+		}
+		
+		this._focusLabel(node);
+		
+		//dojo.profile.end("onTreeClick");
+		
+	},
+	
+	processExpandClick: function(node){
+		
+		//dojo.profile.start("processExpandClick");
+		
+		if (node.isExpanded){
+			this.collapse(node);
+		} else {
+			this.expand(node);
+		}
+		
+		//dojo.profile.end("processExpandClick");
+	},
+		
+	
+	
+	/**
+	 * time between expand calls for batch operations
+	 * @see expandToLevel
+	 */
+	batchExpandTimeout: 20,
+	
+	
+	expandAll: function(nodeOrTree) {		
+		return this.expandToLevel(nodeOrTree, Number.POSITIVE_INFINITY);
+		
+	},
+	
+	
+	collapseAll: function(nodeOrTree) {
+		var _this = this;
+		
+		var filter = function(elem) {
+			return (elem instanceof dojo.widget.Widget) && elem.isFolder && elem.isExpanded;
+		}
+		
+		if (nodeOrTree.isTreeNode) {		
+			this.processDescendants(nodeOrTree, filter, this.collapse);
+		} else if (nodeOrTree.isTree) {
+			dojo.lang.forEach(nodeOrTree.children,function(c) { _this.processDescendants(c, filter, _this.collapse) });
+		}
+	},
+	
+	/**
+	 * expand tree to specific node
+	 */
+	expandToNode: function(node, withSelected) {
+		n = withSelected ? node : node.parent
+		s = []
+		while (!n.isExpanded) {
+			s.push(n)
+			n = n.parent
+		}
+				
+		dojo.lang.forEach(s, function(n) { n.expand() })
+	},
+		
+	/**
+	 * walk a node in time, forward order, with pauses between expansions
+	 */
+	expandToLevel: function(nodeOrTree, level) {
+		dojo.require("dojo.widget.TreeTimeoutIterator");
+		
+		var _this = this;
+		var filterFunc = function(elem) {
+			var res = elem.isFolder || elem.children && elem.children.length;
+			//dojo.debug("Filter "+elem+ " result:"+res);
+			return res;
+		};
+		var callFunc = function(node, iterator) {			
+			 _this.expand(node, true);
+			 iterator.forward();
+		}
+			
+		var iterator = new dojo.widget.TreeTimeoutIterator(nodeOrTree, callFunc, this);
+		iterator.setFilter(filterFunc);
+		
+		
+		iterator.timeout = this.batchExpandTimeout;
+		
+		//dojo.debug("here "+nodeOrTree+" level "+level);
+		
+		iterator.setMaxLevel(nodeOrTree.isTreeNode ? level-1 : level);
+		
+		
+		return iterator.start(nodeOrTree.isTreeNode);
+	},
+	
+
+	getWidgetByNode: function(node) {
+		var widgetId;
+		var newNode = node;
+		while (! (widgetId = newNode.widgetId) ) {
+			newNode = newNode.parentNode;
+			if (newNode == null) { break; }
+		}
+		if (widgetId) { return dojo.widget.byId(widgetId); }
+		else if (node == null) { return null; }
+		else{ return dojo.widget.manager.byNode(node); }
+	},
+
+
+
+	/**
+	 * callout activated even if node is expanded already
+	 */
+	expand: function(node) {
+		
+		//dojo.profile.start("expand");
+		
+		//dojo.debug("Expand "+node.isFolder);
+		
+		if (node.isFolder) {			
+			node.expand(); // skip trees or non-folders
+		}		
+		
+		//dojo.profile.end("expand");
+				
+	},
+
+	/**
+	 * safe to call on tree and non-folder
+	 */
+	collapse: function(node) {
+		if (node.isFolder) {
+			node.collapse();
+		}
+	},
+	
+	
+	// -------------------------- TODO: Inline edit node ---------------------
+	canEditLabel: function(node) {
+		if (node.actionIsDisabledNow(node.actions.EDIT)) return false;
+
+		return true;
+	},
+	
+		
+	editLabelStart: function(node) {		
+		if (!this.canEditLabel(node)) {
+			return false;
+		}
+		
+		if (!this.editor.isClosed()) {
+			//dojo.debug("editLabelStart editor open");
+			this.editLabelFinish(this.editor.saveOnBlur);			
+		}
+				
+		this.doEditLabelStart(node);
+		
+	
+	},
+	
+	
+	editLabelFinish: function(save) {
+		this.doEditLabelFinish(save);		
+	},
+	
+	
+	doEditLabelStart: function(node) {
+		if (!this.editor) {
+			dojo.raise(this.widgetType+": no editor specified");
+		}
+		
+		//dojo.debug("editLabelStart editor open "+node);
+		
+		this.editor.open(node);
+	},
+	
+	doEditLabelFinish: function(save, server_data) {
+		//dojo.debug("Finish "+save);
+		//dojo.debug((new Error()).stack)
+		if (!this.editor) {
+			dojo.raise(this.widgetType+": no editor specified");
+		}
+
+		var node = this.editor.node;	
+		var editorTitle = this.editor.getContents();
+		
+		this.editor.close(save);
+
+		if (save) {
+			var data = {title:editorTitle};
+			
+			if (server_data) { // may be undefined
+				dojo.lang.mixin(data, server_data);
+			}
+			
+			
+			if (node.isPhantom) {			
+				// I can't just set node phantom's title, because widgetId/objectId/widgetName...
+				// may be provided by server
+				var parent = node.parent;
+				var index = node.getParentIndex();				
+				node.destroy();
+				// new node was added!
+				dojo.widget.TreeBasicControllerV3.prototype.doCreateChild.call(this, parent, index, data);
+			} else {
+				var title = server_data && server_data.title ? server_data.title : editorTitle;
+				// use special method to make sure everything updated and event sent
+				node.setTitle(title); 
+			}
+		} else {
+			//dojo.debug("Kill phantom on cancel");
+			if (node.isPhantom) {
+				node.destroy();
+			}
+		}
+	},
+	
+	
+		
+	makeDefaultNode: function(parent, index) {
+		var data = {title:parent.tree.defaultChildTitle};
+		return dojo.widget.TreeBasicControllerV3.prototype.doCreateChild.call(this,parent,index,data);
+	},
+	
+	/**
+	 * check that something is possible
+	 * run maker to do it
+	 * run exposer to expose result to visitor immediatelly
+	 *   exposer does not affect result
+	 */
+	runStages: function(check, prepare, make, finalize, expose, args) {
+		
+		if (check && !check.apply(this, args)) {
+			return false;
+		}
+		
+		if (prepare && !prepare.apply(this, args)) {
+			return false;
+		}
+		
+		var result = make.apply(this, args);
+		
+		
+		if (finalize) {
+			finalize.apply(this,args);			
+		}
+			
+		if (!result) {
+			return result;
+		}
+		
+			
+		if (expose) {
+			expose.apply(this, args);
+		}
+		
+		return result;
+	}
+});
+
+
+// create and edit
+dojo.lang.extend(dojo.widget.TreeBasicControllerV3, {
+		
+	createAndEdit: function(parent, index) {
+		var data = {title:parent.tree.defaultChildTitle};
+		
+		if (!this.canCreateChild(parent, index, data)) {
+			return false;
+		}
+		
+		var child = this.doCreateChild(parent, index, data);
+		if (!child) return false;
+		this.exposeCreateChild(parent, index, data);
+		
+		child.isPhantom = true;
+		
+		if (!this.editor.isClosed()) {
+			//dojo.debug("editLabelStart editor open");
+			this.editLabelFinish(this.editor.saveOnBlur);			
+		}
+		
+		
+				
+		this.doEditLabelStart(child);		
+	
+	}
+	
+});
+
+
+// =============================== clone ============================
+dojo.lang.extend(dojo.widget.TreeBasicControllerV3, {
+	
+	canClone: function(child, newParent, index, deep){
+		return true;
+	},
+	
+	
+	clone: function(child, newParent, index, deep) {
+		return this.runStages(
+			this.canClone, this.prepareClone, this.doClone, this.finalizeClone, this.exposeClone, arguments
+		);			
+	},
+
+	exposeClone: function(child, newParent) {
+		if (newParent.isTreeNode) {
+			this.expand(newParent);
+		}
+	},
+
+	doClone: function(child, newParent, index, deep) {
+		//dojo.debug("Clone "+child);
+		var cloned = child.clone(deep);
+		newParent.addChild(cloned, index);
+				
+		return cloned;
+	}
+	
+
+});
+
+// =============================== detach ============================
+
+dojo.lang.extend(dojo.widget.TreeBasicControllerV3, {
+	canDetach: function(child) {
+		if (child.actionIsDisabledNow(child.actions.DETACH)) {
+			return false;
+		}
+
+		return true;
+	},
+
+
+	detach: function(node) {
+		return this.runStages(
+			this.canDetach, this.prepareDetach, this.doDetach, this.finalizeDetach, this.exposeDetach, arguments
+		);			
+	},
+
+
+	doDetach: function(node, callObj, callFunc) {
+		node.detach();
+	}
+	
+});
+
+
+// =============================== destroy ============================
+dojo.lang.extend(dojo.widget.TreeBasicControllerV3, {
+
+	canDestroyChild: function(child) {
+		
+		if (child.parent && !this.canDetach(child)) {
+			return false;
+		}
+		return true;
+	},
+
+
+	destroyChild: function(node) {
+		return this.runStages(
+			this.canDestroyChild, this.prepareDestroyChild, this.doDestroyChild, this.finalizeDestroyChild, this.exposeDestroyChild, arguments
+		);			
+	},
+
+
+	doDestroyChild: function(node) {
+		node.destroy();
+	}
+	
+});
+
+
+
+// =============================== move ============================
+
+dojo.lang.extend(dojo.widget.TreeBasicControllerV3, {
+
+	/**
+	 * check for non-treenodes
+	 */
+	canMoveNotANode: function(child, parent) {
+		if (child.treeCanMove) {
+			return child.treeCanMove(parent);
+		}
+		
+		return true;
+	},
+
+	/**
+	 * Checks whether it is ok to change parent of child to newParent
+	 * May incur type checks etc
+	 *
+	 * It should check only hierarchical possibility w/o index, etc
+	 * because in onDragOver event for Between Dnd mode we can't calculate index at once on onDragOVer.
+	 * index changes as client moves mouse up-down over the node
+	 */
+	canMove: function(child, newParent){
+		if (!child.isTreeNode) {
+			return this.canMoveNotANode(child, newParent);
+		}
+						
+		if (child.actionIsDisabledNow(child.actions.MOVE)) {
+			return false;
+		}
+
+		// if we move under same parent then no matter if ADDCHILD disabled for him
+		// but if we move to NEW parent then check if action is disabled for him
+		// also covers case for newParent being a non-folder in strict mode etc
+		if (child.parent !== newParent && newParent.actionIsDisabledNow(newParent.actions.ADDCHILD)) {
+			return false;
+		}
+
+		// Can't move parent under child. check whether new parent is child of "child".
+		var node = newParent;
+		while(node.isTreeNode) {
+			//dojo.debugShallow(node.title)
+			if (node === child) {
+				// parent of newParent is child
+				return false;
+			}
+			node = node.parent;
+		}
+
+		return true;
+	},
+
+
+	move: function(child, newParent, index/*,...*/) {
+		return this.runStages(this.canMove, this.prepareMove, this.doMove, this.finalizeMove, this.exposeMove, arguments);			
+	},
+
+	doMove: function(child, newParent, index) {
+		//dojo.debug("MOVE "+child);
+		child.tree.move(child, newParent, index);
+
+		return true;
+	},
+	
+	exposeMove: function(child, newParent) {		
+		if (newParent.isTreeNode) {
+			this.expand(newParent);
+		}
+	}
+		
+
+});
+
+dojo.lang.extend(dojo.widget.TreeBasicControllerV3, {
+
+	// -----------------------------------------------------------------------------
+	//                             Create node stuff
+	// -----------------------------------------------------------------------------
+
+
+	canCreateChild: function(parent, index, data) {
+		if (parent.actionIsDisabledNow(parent.actions.ADDCHILD)) {
+			return false;
+		}
+
+		return true;
+	},
+
+
+	/* send data to server and add child from server */
+	/* data may contain an almost ready child, or anything else, suggested to server */
+	/*in Rpc controllers server responds with child data to be inserted */
+	createChild: function(parent, index, data) {
+		if(!data) {
+			data = {title:parent.tree.defaultChildTitle};
+		}
+		return this.runStages(this.canCreateChild, this.prepareCreateChild, this.doCreateChild, this.finalizeCreateChild, this.exposeCreateChild,
+			[parent, index, data]);		
+	},
+
+	prepareCreateChild: function() { return true; },
+	finalizeCreateChild: function() {},
+
+	doCreateChild: function(parent, index, data) {
+		//dojo.debug("doCreateChild parent "+parent+" index "+index+" data "+data);
+		
+		var newChild = parent.tree.createNode(data); 
+		//var newChild = dojo.widget.createWidget(widgetType, data);
+
+		parent.addChild(newChild, index);
+
+		return newChild;
+	},
+	
+	exposeCreateChild: function(parent) {
+		return this.expand(parent);
+	}
+
+
+});

Added: myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/TreeCommon.js
URL: http://svn.apache.org/viewvc/myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/TreeCommon.js?view=auto&rev=495409
==============================================================================
--- myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/TreeCommon.js (added)
+++ myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/TreeCommon.js Thu Jan 11 14:35:53 2007
@@ -0,0 +1,150 @@
+/*
+	Copyright (c) 2004-2006, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.1 or above OR the
+	modified BSD license. For more information on Dojo licensing, see:
+
+		http://dojotoolkit.org/community/licensing.shtml
+*/
+
+
+dojo.provide("dojo.widget.TreeCommon");
+dojo.require("dojo.widget.*"); // for dojo.widget.manager
+
+dojo.declare(
+	"dojo.widget.TreeCommon",
+	null,
+{
+	listenTreeEvents: [],
+	listenedTrees: {},
+	
+	/**
+	 * evaluates to false => skip unlistening nodes
+	 * provided => use it
+	 */	
+	listenNodeFilter: null,
+	
+	listenTree: function(tree) {
+		
+		//dojo.debug("listenTree in "+this+" tree "+tree);
+		
+		var _this = this;
+		
+		if (this.listenedTrees[tree.widgetId]) {
+			return; // already listening
+		}
+		
+		dojo.lang.forEach(this.listenTreeEvents, function(event) {
+			var eventHandler =  "on" + event.charAt(0).toUpperCase() + event.substr(1);
+			//dojo.debug("subscribe: event "+tree.eventNames[event]+" widget "+_this+" handler "+eventHandler);
+			dojo.event.topic.subscribe(tree.eventNames[event], _this, eventHandler);
+		});
+		
+		
+		var filter;
+		
+		if (this.listenNodeFilter) {			
+			this.processDescendants(tree, this.listenNodeFilter, this.listenNode, true);
+		}
+		
+		/**
+		 * remember that I listen to this tree. No unbinding/binding/deselection
+		 * needed when transfer between listened trees
+		 */
+		this.listenedTrees[tree.widgetId] = true;
+		
+	},			
+	
+	// interface functions
+	listenNode: function() {},	
+	unlistenNode: function() {},
+			
+	unlistenTree: function(tree, nodeFilter) {
+		
+		var _this = this;
+	
+		if (!this.listenedTrees[tree.widgetId]) {
+			return; 
+		}
+		
+		dojo.lang.forEach(this.listenTreeEvents, function(event) {
+			var eventHandler =  "on" + event.charAt(0).toUpperCase() + event.substr(1);
+			dojo.event.topic.unsubscribe(tree.eventNames[event], _this, eventHandler);
+		});
+		
+		
+		if (this.listenNodeFilter) {
+			this.processDescendants(tree, this.listenNodeFilter, this.unlistenNode, true);
+		}
+		
+		delete this.listenedTrees[tree.widgetId];
+		
+	},
+	
+	
+	/**
+	 * check condition for node.domNode -> .. -> any node chain
+	 */
+	checkPathCondition: function(domElement, condition) {
+		
+		while (domElement && !domElement.widgetId) {
+			if (condition.call(null, domElement)) {
+				return true;
+			}
+			
+			domElement = domElement.parentNode;
+		}
+		
+		return false;
+	},
+		
+	
+	/**
+	 * get node widget id by its descendant dom node
+	 */
+	domElement2TreeNode: function(domElement) {
+		
+		while (domElement && !domElement.widgetId) {
+			domElement = domElement.parentNode;
+		}
+		
+		if (!domElement) {
+			return null;
+		}
+		
+		var widget = dojo.widget.byId(domElement.widgetId);
+		
+		if (!widget.isTreeNode) {
+			return null;
+		}
+		
+		return widget;
+	},
+	
+	/**
+	 * it is here, not in Widget, because mostly tree needs it
+	 */
+	processDescendants: function(elem, filter, func, skipFirst) {
+		
+		var _this = this;
+		
+		if (!skipFirst) {
+			if (!filter.call(_this,elem)) {
+				return;
+			}
+			func.call(_this,elem);	        
+		}
+		
+		
+		var stack = [elem];
+		while (elem = stack.pop()) {
+			dojo.lang.forEach(elem.children, function(elem) {
+				if (filter.call(_this, elem)) {		
+					func.call(_this, elem);
+					stack.push(elem);
+				}
+			});
+		}
+    }
+});

Added: myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/TreeContextMenu.js
URL: http://svn.apache.org/viewvc/myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/TreeContextMenu.js?view=auto&rev=495409
==============================================================================
--- myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/TreeContextMenu.js (added)
+++ myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/TreeContextMenu.js Thu Jan 11 14:35:53 2007
@@ -0,0 +1,181 @@
+/*
+	Copyright (c) 2004-2006, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.1 or above OR the
+	modified BSD license. For more information on Dojo licensing, see:
+
+		http://dojotoolkit.org/community/licensing.shtml
+*/
+
+
+
+dojo.provide("dojo.widget.TreeContextMenu");
+
+dojo.require("dojo.event.*");
+dojo.require("dojo.io.*");
+dojo.require("dojo.widget.Menu2");
+
+
+dojo.widget.defineWidget("dojo.widget.TreeContextMenu", dojo.widget.PopupMenu2, function() {
+	this.listenedTrees = [];
+},
+{
+	open: function(x, y, parentMenu, explodeSrc){
+
+		var result = dojo.widget.PopupMenu2.prototype.open.apply(this, arguments);
+
+		/* publish many events here about structural changes */
+		dojo.event.topic.publish(this.eventNames.open, { menu:this });
+
+		return result;
+	},
+
+	listenTree: function(tree) {
+		/* add context menu to all nodes that exist already */
+		var nodes = tree.getDescendants();
+
+		for(var i=0; i<nodes.length; i++) {
+			if (!nodes[i].isTreeNode) continue;
+			this.bindDomNode(nodes[i].labelNode);
+		}
+
+
+		/* bind context menu to all nodes that will be created in the future (e.g loaded from server)*/
+		var _this = this;
+		dojo.event.topic.subscribe(tree.eventNames.createDOMNode, this, "onCreateDOMNode");
+		dojo.event.topic.subscribe(tree.eventNames.moveFrom, this, "onMoveFrom");
+		dojo.event.topic.subscribe(tree.eventNames.moveTo, this, "onMoveTo");
+		dojo.event.topic.subscribe(tree.eventNames.removeNode, this, "onRemoveNode");
+		dojo.event.topic.subscribe(tree.eventNames.addChild, this, "onAddChild");
+		dojo.event.topic.subscribe(tree.eventNames.treeDestroy, this, "onTreeDestroy");
+
+		this.listenedTrees.push(tree);
+
+	},
+
+	unlistenTree: function(tree) {
+		/* clear event listeners */
+
+		dojo.event.topic.unsubscribe(tree.eventNames.createDOMNode, this, "onCreateDOMNode");
+		dojo.event.topic.unsubscribe(tree.eventNames.moveFrom, this, "onMoveFrom");
+		dojo.event.topic.unsubscribe(tree.eventNames.moveTo, this, "onMoveTo");
+		dojo.event.topic.unsubscribe(tree.eventNames.removeNode, this, "onRemoveNode");
+		dojo.event.topic.unsubscribe(tree.eventNames.addChild, this, "onAddChild");
+		dojo.event.topic.unsubscribe(tree.eventNames.treeDestroy, this, "onTreeDestroy");
+
+		for(var i=0; i<this.listenedTrees.length; i++){
+           if(this.listenedTrees[i] === tree){
+                   this.listenedTrees.splice(i, 1);
+                   break;
+           }
+		}
+	},
+
+	onTreeDestroy: function(message) {
+		this.unlistenTree(message.source);
+	},
+
+	bindTreeNode: function(node) {
+		var _this = this;
+		//dojo.debug("bind to "+node);
+		dojo.lang.forEach(node.getDescendants(),
+			function(e) {_this.bindDomNode(e.labelNode); }
+		);
+	},
+
+
+	unBindTreeNode: function(node) {
+		var _this = this;
+		//dojo.debug("Unbind from "+node);
+		dojo.lang.forEach(node.getDescendants(),
+			function(e) {_this.unBindDomNode(e.labelNode); }
+		);
+	},
+
+	onCreateDOMNode: function(message) {
+		this.bindTreeNode(message.source);
+	},
+
+
+	onMoveFrom: function(message) {
+		if (!dojo.lang.inArray(this.listenedTrees, message.newTree)) {
+			this.unBindTreeNode(message.child);
+		}
+	},
+
+	onMoveTo: function(message) {
+		if (dojo.lang.inArray(this.listenedTrees, message.newTree)) {
+			this.bindTreeNode(message.child);
+		}
+	},
+
+	onRemoveNode: function(message) {
+		this.unBindTreeNode(message.child);
+	},
+
+	onAddChild: function(message) {
+		if (message.domNodeInitialized) {
+			// dom node was there already => I did not process onNodeDomCreate
+			this.bindTreeNode(message.child);
+		}
+	}
+
+
+});
+
+dojo.widget.defineWidget("dojo.widget.TreeMenuItem", dojo.widget.MenuItem2, {
+	// treeActions menu item performs following actions (to be checked for permissions)
+	treeActions: "",
+
+	initialize: function(args, frag) {
+
+		this.treeActions = this.treeActions.split(",");
+		for(var i=0; i<this.treeActions.length; i++) {
+			this.treeActions[i] = this.treeActions[i].toUpperCase();
+		}
+
+	},
+
+	getTreeNode: function() {
+		var menu = this;
+
+		while (! (menu instanceof dojo.widget.TreeContextMenu) ) {
+			menu = menu.parent;
+		}
+
+		var source = menu.getTopOpenEvent().target;
+
+		while (!source.getAttribute('treeNode') && source.tagName != 'body') {
+			source = source.parentNode;
+		}
+		if (source.tagName == 'body') {
+			dojo.raise("treeNode not detected");
+		}
+		var treeNode = dojo.widget.manager.getWidgetById(source.getAttribute('treeNode'));
+
+		return treeNode;
+	},
+
+
+	menuOpen: function(message) {
+		var treeNode = this.getTreeNode();
+
+		this.setDisabled(false); // enable by default
+
+		var _this = this;
+		dojo.lang.forEach(_this.treeActions,
+			function(action) {
+				_this.setDisabled( treeNode.actionIsDisabled(action) );
+			}
+		);
+
+	},
+
+	toString: function() {
+		return "["+this.widgetType+" node "+this.getTreeNode()+"]";
+	}
+
+});
+
+