[richfaces-svn-commits] JBoss Rich Faces SVN: r2284 - in trunk: framework/api/src/main/java/org/richfaces/model and 13 other directories.

richfaces-svn-commits at lists.jboss.org richfaces-svn-commits at lists.jboss.org
Wed Aug 15 20:55:58 EDT 2007


Author: nbelaevski
Date: 2007-08-15 20:55:58 -0400 (Wed, 15 Aug 2007)
New Revision: 2284

Added:
   trunk/framework/api/src/main/java/org/richfaces/model/TreeModelVisualComponentProvider.java
   trunk/framework/api/src/main/java/org/richfaces/model/VisualStackingTreeModel.java
   trunk/ui/treeModel/src/test/java/org/richfaces/component/TreeModelComponentTest.java
   trunk/ui/treeModel/src/test/resources/
   trunk/ui/treeModel/src/test/resources/org/
   trunk/ui/treeModel/src/test/resources/org/richfaces/
   trunk/ui/treeModel/src/test/resources/org/richfaces/component/
   trunk/ui/treeModel/src/test/resources/org/richfaces/component/tree-model-data.xml
Removed:
   trunk/framework/api/src/main/java/org/richfaces/model/TreeComponentModel.java
   trunk/framework/api/src/main/java/org/richfaces/model/TreeComponentModelListener.java
   trunk/ui/treeModel/src/main/templates/
   trunk/ui/treeModel/src/test/java/org/richfaces/component/JSFComponentTest.java
Modified:
   trunk/framework/api/src/main/java/org/richfaces/event/AjaxSelectedEvent.java
   trunk/framework/api/src/main/java/org/richfaces/event/NodeSelectedEvent.java
   trunk/framework/api/src/main/java/org/richfaces/model/MapDataModel.java
   trunk/framework/api/src/main/java/org/richfaces/model/SequenceDataModel.java
   trunk/framework/api/src/main/java/org/richfaces/model/StackingTreeModel.java
   trunk/framework/api/src/main/java/org/richfaces/model/TreeDataModel.java
   trunk/framework/test/src/test/java/org/richfaces/model/StackingTreeDataModelTest.java
   trunk/ui/tree/src/main/java/org/richfaces/component/UITree.java
   trunk/ui/tree/src/main/java/org/richfaces/component/UITreeNode.java
   trunk/ui/tree/src/main/java/org/richfaces/component/state/TreeState.java
   trunk/ui/tree/src/main/java/org/richfaces/renderkit/NodeRendererBase.java
   trunk/ui/tree/src/main/resources/org/richfaces/renderkit/html/scripts/tree.js
   trunk/ui/treeModel/src/main/java/org/richfaces/component/UIRecursiveTreeNodes.java
   trunk/ui/treeModel/src/main/java/org/richfaces/component/UITreeNodes.java
Log:
Fixes and updates:
- tree: node selection obeys validation
- tree: data models work with NodeList & NamedNodeMap
- StackingTreeModel.java: isRowAvailable() handling added, code slightly optimized
- TreeState.java API aligned
- tree.js: fixed selection restoration error when previous selection was null
- TreeModelComponentTest.java added
- VisualStackingTreeModel.java and handling added

Modified: trunk/framework/api/src/main/java/org/richfaces/event/AjaxSelectedEvent.java
===================================================================
--- trunk/framework/api/src/main/java/org/richfaces/event/AjaxSelectedEvent.java	2007-08-16 00:05:26 UTC (rev 2283)
+++ trunk/framework/api/src/main/java/org/richfaces/event/AjaxSelectedEvent.java	2007-08-16 00:55:58 UTC (rev 2284)
@@ -38,4 +38,8 @@
 		super(component);
 	}
 
+	public AjaxSelectedEvent(UIComponent component, boolean duplicate) {
+		super(component, duplicate);
+	}
+
 }

Modified: trunk/framework/api/src/main/java/org/richfaces/event/NodeSelectedEvent.java
===================================================================
--- trunk/framework/api/src/main/java/org/richfaces/event/NodeSelectedEvent.java	2007-08-16 00:05:26 UTC (rev 2283)
+++ trunk/framework/api/src/main/java/org/richfaces/event/NodeSelectedEvent.java	2007-08-16 00:55:58 UTC (rev 2284)
@@ -32,10 +32,18 @@
  */
 public class NodeSelectedEvent extends FacesEvent {
 
+	private boolean duplicate = false; 
+	
 	public NodeSelectedEvent(UIComponent component) {
 		super(component);
 	}
 
+	public NodeSelectedEvent(UIComponent component, boolean duplicate) {
+		super(component);
+		
+		this.duplicate = duplicate;
+	}
+
 	/**
 	 * 
 	 */
@@ -57,4 +65,7 @@
 		((NodeSelectedListener) listener).processSelection(this);
 	}
 
+	public boolean isDuplicate() {
+		return duplicate;
+	}
 }

Modified: trunk/framework/api/src/main/java/org/richfaces/model/MapDataModel.java
===================================================================
--- trunk/framework/api/src/main/java/org/richfaces/model/MapDataModel.java	2007-08-16 00:05:26 UTC (rev 2283)
+++ trunk/framework/api/src/main/java/org/richfaces/model/MapDataModel.java	2007-08-16 00:55:58 UTC (rev 2284)
@@ -4,14 +4,20 @@
 package org.richfaces.model;
 
 import java.io.IOException;
+import java.util.AbstractMap;
+import java.util.AbstractSet;
 import java.util.Iterator;
 import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
 
 import javax.faces.context.FacesContext;
 
 import org.ajax4jsf.model.DataVisitor;
 import org.ajax4jsf.model.ExtendedDataModel;
 import org.ajax4jsf.model.Range;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
 
 /**
  * @author Nick Belaevski mailto:nbelaevski at exadel.com created 30.07.2007
@@ -21,7 +27,8 @@
 
 	private Map map;
 	private Object rowKey;
-
+	private Object wrappedData;
+	
 	/*
 	 * (non-Javadoc)
 	 * 
@@ -96,7 +103,7 @@
 	 * @see javax.faces.model.DataModel#getWrappedData()
 	 */
 	public Object getWrappedData() {
-		return map;
+		return wrappedData;
 	}
 
 	/*
@@ -122,7 +129,73 @@
 	 * @see javax.faces.model.DataModel#setWrappedData(java.lang.Object)
 	 */
 	public void setWrappedData(Object data) {
-		this.map = (Map) data;
+		this.wrappedData = data;
+		if (data instanceof NamedNodeMap) {
+			this.map = new AbstractMap() {
+
+				private Set entrySet = new AbstractSet() {
+
+					public Iterator iterator() {
+						return new Iterator() {
+							private int index = 0;
+
+							public boolean hasNext() {
+								return index < ((NamedNodeMap) getWrappedData()).getLength();
+							}
+
+							public Object next() {
+								final Node node = ((NamedNodeMap) getWrappedData()).item(index++);
+								if (node == null) {
+									throw new NoSuchElementException();
+								} else {
+									return new Map.Entry() {
+
+										public Object getKey() {
+											return node.getNodeName();
+										}
+
+										public Object getValue() {
+											return node;
+										}
+
+										public Object setValue(Object arg0) {
+											throw new UnsupportedOperationException();
+										}
+										
+									};
+								}
+							}
+
+							public void remove() {
+								throw new UnsupportedOperationException();
+							}
+						};
+					}
+
+					public int size() {
+						return ((NamedNodeMap) getWrappedData()).getLength();
+					}
+					
+				};
+				
+				public boolean containsKey(Object key) {
+					return ((NamedNodeMap) getWrappedData()).getNamedItem((String) key) != null;
+				}
+				
+				public Object get(Object key) {
+					return ((NamedNodeMap) getWrappedData()).getNamedItem((String) key);
+				}
+				
+				public Set entrySet() {
+					return entrySet;
+				}
+				
+			};
+		} else if (data != null) {
+			this.map = (Map) data;
+		} else {
+			this.map = null;
+		}
 	}
 
 }

Modified: trunk/framework/api/src/main/java/org/richfaces/model/SequenceDataModel.java
===================================================================
--- trunk/framework/api/src/main/java/org/richfaces/model/SequenceDataModel.java	2007-08-16 00:05:26 UTC (rev 2283)
+++ trunk/framework/api/src/main/java/org/richfaces/model/SequenceDataModel.java	2007-08-16 00:55:58 UTC (rev 2284)
@@ -4,6 +4,7 @@
 package org.richfaces.model;
 
 import java.io.IOException;
+import java.util.AbstractList;
 import java.util.Arrays;
 import java.util.Iterator;
 import java.util.List;
@@ -13,6 +14,7 @@
 import org.ajax4jsf.model.DataVisitor;
 import org.ajax4jsf.model.ExtendedDataModel;
 import org.ajax4jsf.model.Range;
+import org.w3c.dom.NodeList;
 
 /**
  * @author Nick Belaevski
@@ -106,6 +108,18 @@
 		this.wrappedData = data;
 		if (data instanceof List) {
 			this.list = (List) data;
+		} else if (data instanceof NodeList) {
+			this.list = new AbstractList() {
+
+				public Object get(int index) {
+					return ((NodeList) getWrappedData()).item(index);
+				}
+
+				public int size() {
+					return ((NodeList) getWrappedData()).getLength();
+				}
+				
+			};
 		} else if (data != null) {
 			this.list = Arrays.asList((Object[]) data); 
 		} else {

Modified: trunk/framework/api/src/main/java/org/richfaces/model/StackingTreeModel.java
===================================================================
--- trunk/framework/api/src/main/java/org/richfaces/model/StackingTreeModel.java	2007-08-16 00:05:26 UTC (rev 2283)
+++ trunk/framework/api/src/main/java/org/richfaces/model/StackingTreeModel.java	2007-08-16 00:55:58 UTC (rev 2284)
@@ -5,14 +5,11 @@
 
 import java.io.IOException;
 import java.io.Serializable;
-import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.LinkedList;
-import java.util.List;
 import java.util.Map;
 
-import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 
 import org.ajax4jsf.model.DataVisitor;
@@ -20,12 +17,13 @@
 import org.ajax4jsf.model.Range;
 import org.apache.commons.collections.Predicate;
 import org.apache.commons.collections.iterators.FilterIterator;
+import org.w3c.dom.NamedNodeMap;
 
 /**
  * @author Nick Belaevski mailto:nbelaevski at exadel.com created 25.07.2007
  * 
  */
-public class StackingTreeModel extends AbstractTreeDataModel implements TreeComponentModel {
+public class StackingTreeModel extends AbstractTreeDataModel {
 
 	//ctor arguments
 	private String id;
@@ -36,9 +34,6 @@
 	private StackingTreeModel parent;
 	private Map models = new LinkedHashMap();
 
-	//listeners
-	private List treeComponentModelListeners = new ArrayList();
-
 	private Object rowKey;
 
 	private class StackEntry {
@@ -60,7 +55,7 @@
 	public ExtendedDataModel getDataModel() {
 		Object data = dataProvider.getData();
 		ExtendedDataModel dataModel;
-		if (data instanceof Map) {
+		if (data instanceof Map || data instanceof NamedNodeMap) {
 			dataModel = new MapDataModel();
 		} else {
 			dataModel = new SequenceDataModel();
@@ -70,6 +65,18 @@
 		return dataModel;
 	}
 
+	protected StackingTreeModel getCurrentModel() {
+		if (this.rowKey == null) {
+			return this;
+		}
+		
+		if (isRowAvailable()) {
+			return ((StackEntry) stackEntries.getLast()).model;
+		}
+
+		return null;
+	}
+	
 	public boolean isEmpty() {
 		//TODO optimize that
 		return getDataModel().getRowCount() == 0;
@@ -105,32 +112,41 @@
 		}
 	}
 
-	protected StackingTreeModel doSetupKey(Iterator keyIterator, Iterator entriesIterator, FacesContext context) {
-		if (keyIterator == null || !keyIterator.hasNext()) {
-			leaveModel(entriesIterator, null, context);
-			return this;
-		} else {
+	protected StackingTreeModel doSetupKey(Iterator keyIterator, Iterator entriesIterator, FacesContext context, Object modelKey) {
+		if (modelKey != null) {
+			if (!setupModel(modelKey, context)) {
+				//no key is available
+				leaveModel(getRoot().stackEntries.iterator(), null, context);
+				return null;
+			}
+		}
+		
+		if (keyIterator != null && keyIterator.hasNext()) {
 			Key key = (Key) keyIterator.next();
 			StackingTreeModel stackingTreeModel = this.getInternalModelById(key.modelId);
+			Iterator nextEntriesIterator = null;
+			Object nextModelKey = key.modelKey;
+			
 			if (entriesIterator != null && entriesIterator.hasNext()) {
 				StackEntry entry = (StackEntry) entriesIterator.next();
-				if (entry.model != stackingTreeModel || entry.modelKey != key.modelKey) {
-					//entry.model.restoreVariable(entry.varObject);
+				if (!entry.model.equals(stackingTreeModel) || !entry.modelKey.equals(nextModelKey)) {
 					leaveModel(entriesIterator, entry, context);
-
-					stackingTreeModel.setupModel(key.modelKey, context);
-					entriesIterator = null;
+				} else {
+					//continue iterating entries, they still lead us by key path
+					nextEntriesIterator = entriesIterator;
+					nextModelKey = null;
 				}
-			} else {
-				stackingTreeModel.setupModel(key.modelKey, context);
-				entriesIterator = null;
 			}
 
-			return stackingTreeModel.doSetupKey(keyIterator, entriesIterator, context);
+			//should not be called when nextEntriesIterator & nextModelKey are both valid
+			return stackingTreeModel.doSetupKey(keyIterator, nextEntriesIterator, context, nextModelKey);
+		
+		} else {
+			leaveModel(entriesIterator, null, context);
+			return this;
 		}
 	}
 	
-	
 	protected StackingTreeModel setupKey(Object key, FacesContext context) {
 		if (key == this.rowKey) {
 			if (stackEntries.isEmpty()) {
@@ -144,7 +160,7 @@
 				keyIterator = ((ListRowKey) key).iterator();
 			}
 			
-			StackingTreeModel model = doSetupKey(keyIterator, stackEntries.iterator(), context);
+			StackingTreeModel model = doSetupKey(keyIterator, stackEntries.iterator(), context, null);
 			this.rowKey = key;
 
 			return model;
@@ -171,16 +187,22 @@
 		return null;
 	}
 
-	public void setupModel(Object key, FacesContext facesContext) {
+	public boolean setupModel(Object key, FacesContext facesContext) {
 		ExtendedDataModel dataModel = getDataModel();
 		dataModel.setRowKey(key);
 
-		Object rowData = dataModel.getRowData();
-		//System.out.println("StackingTreeModel.setupModel() " + rowData);
-		Object varObject = setupVariable(rowData, facesContext);
+		if (dataModel.isRowAvailable()) {
+			Object rowData = dataModel.getRowData();
+			//System.out.println("StackingTreeModel.setupModel() " + rowData);
+			Object varObject = setupVariable(rowData, facesContext);
 
-		this.rowData = rowData;
-		getRoot().stackEntries.add(new StackEntry(varObject, key, this));
+			this.rowData = rowData;
+			getRoot().stackEntries.add(new StackEntry(varObject, key, this));
+
+			return true;
+		}
+		
+		return false;
 	}
 
 	public void setParent(StackingTreeModel parent) {
@@ -193,7 +215,12 @@
 	 * @see org.richfaces.model.AbstractTreeDataModel#getTreeNode()
 	 */
 	public TreeNode getTreeNode() {
-		return null;
+		if (this.rowKey == null || isRowAvailable()) {
+			return null;
+		}
+
+		throw new IllegalStateException(
+				"No tree element available or row key not set!");
 	}
 
 	/*
@@ -202,20 +229,25 @@
 	 * @see org.richfaces.model.AbstractTreeDataModel#isLeaf()
 	 */
 	public boolean isLeaf() {
-		if (stackEntries.isEmpty()) {
-			return false;
-		}
+		if (isRowAvailable()) {
+			if (stackEntries.isEmpty()) {
+				return false;
+			}
 
-		StackEntry lastEntry = (StackEntry) stackEntries.getLast();
-		for (Iterator iterator = lastEntry.model.getInternalModelsIterator(); iterator.hasNext();) {
-			StackingTreeModel stackingTreeModel = (StackingTreeModel) iterator.next();
+			StackEntry lastEntry = (StackEntry) stackEntries.getLast();
+			for (Iterator iterator = lastEntry.model.getInternalModelsIterator(); iterator.hasNext();) {
+				StackingTreeModel stackingTreeModel = (StackingTreeModel) iterator.next();
 
-			if (!stackingTreeModel.isEmpty()) {
-				return false;
+				if (!stackingTreeModel.isEmpty()) {
+					return false;
+				}
 			}
+
+			return true;
 		}
-
-		return true;
+		
+		throw new IllegalStateException(
+				"No tree element available or row key not set!");
 	}
 
 	protected StackingTreeModel getRoot() {
@@ -444,12 +476,17 @@
 	 * @see javax.faces.model.DataModel#getRowData()
 	 */
 	public Object getRowData() {
-		if (stackEntries.isEmpty()) {
-			return null;
+		if (isRowAvailable()) {
+			if (stackEntries.isEmpty()) {
+				return null;
+			}
+
+			StackEntry lastEntry = (StackEntry) stackEntries.getLast();
+			return lastEntry.model.rowData;
 		}
-
-		StackEntry lastEntry = (StackEntry) stackEntries.getLast();
-		return lastEntry.model.rowData;
+		
+		throw new IllegalStateException(
+				"No tree element available or row key not set!");
 	}
 
 	/*
@@ -458,8 +495,7 @@
 	 * @see javax.faces.model.DataModel#isRowAvailable()
 	 */
 	public boolean isRowAvailable() {
-		// TODO Auto-generated method stub
-		return true;
+		return !stackEntries.isEmpty();
 	}
 
 	public StackingTreeModel getParent() {
@@ -516,28 +552,6 @@
 		}
 	}
 
-	public void addTreeComponentModelListener(
-			TreeComponentModelListener listener) {
-		this.treeComponentModelListeners.add(listener);
-	}
-
-	public void removeTreeComponentModelListener(
-			TreeComponentModelListener listener) {
-		this.treeComponentModelListeners.remove(listener);
-	}
-
-	protected void componentSelected(UIComponent component) {
-		for (Iterator iterator = this.treeComponentModelListeners.iterator(); iterator.hasNext();) {
-			TreeComponentModelListener listener = (TreeComponentModelListener) iterator.next();
-
-			listener.componentSelected(component);
-		}
-
-		if (parent != null) {
-			parent.componentSelected(component);
-		}
-	}
-	
 	protected boolean isActiveData() {
 		return true;
 	}

Deleted: trunk/framework/api/src/main/java/org/richfaces/model/TreeComponentModel.java
===================================================================
--- trunk/framework/api/src/main/java/org/richfaces/model/TreeComponentModel.java	2007-08-16 00:05:26 UTC (rev 2283)
+++ trunk/framework/api/src/main/java/org/richfaces/model/TreeComponentModel.java	2007-08-16 00:55:58 UTC (rev 2284)
@@ -1,15 +0,0 @@
-/**
- * 
- */
-package org.richfaces.model;
-
-/**
- * @author Nick Belaevski
- *         mailto:nbelaevski at exadel.com
- *         created 24.07.2007
- *
- */
-public interface TreeComponentModel {
-	public void addTreeComponentModelListener(TreeComponentModelListener listener);
-	public void removeTreeComponentModelListener(TreeComponentModelListener listener);
-}

Deleted: trunk/framework/api/src/main/java/org/richfaces/model/TreeComponentModelListener.java
===================================================================
--- trunk/framework/api/src/main/java/org/richfaces/model/TreeComponentModelListener.java	2007-08-16 00:05:26 UTC (rev 2283)
+++ trunk/framework/api/src/main/java/org/richfaces/model/TreeComponentModelListener.java	2007-08-16 00:55:58 UTC (rev 2284)
@@ -1,16 +0,0 @@
-/**
- * 
- */
-package org.richfaces.model;
-
-import javax.faces.component.UIComponent;
-
-/**
- * @author Nick Belaevski
- *         mailto:nbelaevski at exadel.com
- *         created 29.07.2007
- *
- */
-public interface TreeComponentModelListener {
-	public void componentSelected(UIComponent component);
-}

Modified: trunk/framework/api/src/main/java/org/richfaces/model/TreeDataModel.java
===================================================================
--- trunk/framework/api/src/main/java/org/richfaces/model/TreeDataModel.java	2007-08-16 00:05:26 UTC (rev 2283)
+++ trunk/framework/api/src/main/java/org/richfaces/model/TreeDataModel.java	2007-08-16 00:55:58 UTC (rev 2284)
@@ -56,10 +56,8 @@
 		}
 	}
 
-	
-	public void walk(FacesContext context, DataVisitor dataVisitor,
+	protected void doWalk(FacesContext context, DataVisitor dataVisitor,
 			Range range, Object rowKey, Object argument, boolean last) throws IOException {
-
 		ListRowKey listRowKey = (ListRowKey) rowKey;
 
 		TreeNode node = locateTreeNode(listRowKey);
@@ -113,7 +111,7 @@
 									newRowKey = new ListRowKey(identifier);						
 								}
 
-								this.walk(context, dataVisitor, range, newRowKey, argument, isLast);
+								this.doWalk(context, dataVisitor, range, newRowKey, argument, isLast);
 							}
 
 							identifier = nextIdentifier;
@@ -124,7 +122,21 @@
 			}
 		}
 	}
+	
+	public void walk(FacesContext context, DataVisitor dataVisitor,
+			Range range, Object rowKey, Object argument, boolean last) throws IOException {
 
+		if (rowKey != null) {
+			setRowKey(rowKey);
+			if (!isRowAvailable()) {
+				throw new IllegalStateException(
+						"No tree element available or row key not set!");
+			}
+		}
+		
+		doWalk(context, dataVisitor, range, rowKey, argument, last);
+	}
+
 	public TreeNode locateTreeNode(TreeRowKey rowKey) {
 		return locateTreeNode(rowKey, false);
 	}
@@ -194,18 +206,26 @@
 	}
 
 	public Object getRowData() {
-		TreeNode treeNode = locateTreeNode(this.currentRowKey);
-		if (treeNode != null) {
-			return treeNode.getData();
+		if (isRowAvailable()) {
+			TreeNode treeNode = locateTreeNode(this.currentRowKey);
+			if (treeNode != null) {
+				return treeNode.getData();
+			}
+
+			return null;
 		}
+		
 
-		return null;
+		throw new IllegalStateException(
+				"No tree element available or row key not set!");
 	}
 
 	public boolean isLeaf() {
-		TreeNode treeNode = locateTreeNode(this.currentRowKey);
-		if (treeNode != null) {
-			return treeNode.isLeaf();
+		if (isRowAvailable()) {
+			TreeNode treeNode = locateTreeNode(this.currentRowKey);
+			if (treeNode != null) {
+				return treeNode.isLeaf();
+			}
 		}
 
 		throw new IllegalStateException(
@@ -217,6 +237,11 @@
 	}
 
 	public TreeNode getTreeNode() {
-		return locateTreeNode(this.currentRowKey);
+		if (isRowAvailable()) {
+			return locateTreeNode(this.currentRowKey);
+		}
+
+		throw new IllegalStateException(
+				"No tree element available or row key not set!");
 	}
 }

Copied: trunk/framework/api/src/main/java/org/richfaces/model/TreeModelVisualComponentProvider.java (from rev 2250, trunk/framework/api/src/main/java/org/richfaces/model/TreeComponentModelListener.java)
===================================================================
--- trunk/framework/api/src/main/java/org/richfaces/model/TreeModelVisualComponentProvider.java	                        (rev 0)
+++ trunk/framework/api/src/main/java/org/richfaces/model/TreeModelVisualComponentProvider.java	2007-08-16 00:55:58 UTC (rev 2284)
@@ -0,0 +1,16 @@
+/**
+ * 
+ */
+package org.richfaces.model;
+
+import javax.faces.component.UIComponent;
+
+/**
+ * @author Nick Belaevski
+ *         mailto:nbelaevski at exadel.com
+ *         created 29.07.2007
+ *
+ */
+public interface TreeModelVisualComponentProvider {
+	public UIComponent getComponent();
+}

Added: trunk/framework/api/src/main/java/org/richfaces/model/VisualStackingTreeModel.java
===================================================================
--- trunk/framework/api/src/main/java/org/richfaces/model/VisualStackingTreeModel.java	                        (rev 0)
+++ trunk/framework/api/src/main/java/org/richfaces/model/VisualStackingTreeModel.java	2007-08-16 00:55:58 UTC (rev 2284)
@@ -0,0 +1,42 @@
+/**
+ * 
+ */
+package org.richfaces.model;
+
+import javax.faces.component.UIComponent;
+
+/**
+ * @author Nick Belaevski
+ *         mailto:nbelaevski at exadel.com
+ *         created 15.08.2007
+ *
+ */
+public class VisualStackingTreeModel extends StackingTreeModel implements TreeModelVisualComponentProvider {
+	private UIComponent component;
+
+	public VisualStackingTreeModel(UIComponent component) {
+		super();
+
+		this.component = component;
+	}
+
+	public VisualStackingTreeModel(String id, String var,
+			StackingTreeModelDataProvider dataProvider, UIComponent component) {
+		super(id, var, dataProvider);
+
+		this.component = component;
+	}
+	
+	public UIComponent getComponent() {
+		if (this.component != null) {
+			return this.component;
+		}
+
+		StackingTreeModel currentModel = getCurrentModel();
+		if (currentModel != null && currentModel != this) {
+			return ((TreeModelVisualComponentProvider) currentModel).getComponent();
+		}
+
+		return null;
+	}
+}

Modified: trunk/framework/test/src/test/java/org/richfaces/model/StackingTreeDataModelTest.java
===================================================================
--- trunk/framework/test/src/test/java/org/richfaces/model/StackingTreeDataModelTest.java	2007-08-16 00:05:26 UTC (rev 2283)
+++ trunk/framework/test/src/test/java/org/richfaces/model/StackingTreeDataModelTest.java	2007-08-16 00:55:58 UTC (rev 2284)
@@ -7,8 +7,6 @@
 import java.util.LinkedHashMap;
 import java.util.Map;
 
-import javax.faces.component.UIComponent;
-import javax.faces.component.UIOutput;
 import javax.faces.context.FacesContext;
 import javax.faces.el.ValueBinding;
 
@@ -130,30 +128,31 @@
 		this.stackingTreeModel.walk(facesContext, visitor1, null, null);
 		assertEquals(9, visitor1.getCounter());
 		this.stackingTreeModel.setRowKey(null);
-		assertNull(this.stackingTreeModel.getRowData());
-		assertFalse(this.stackingTreeModel.isLeaf());
-		
+		assertFalse(this.stackingTreeModel.isRowAvailable());
+
 		Map requestParameterMap = facesContext.getExternalContext().getRequestParameterMap();
 		assertSame(this.projectRequestObject, requestParameterMap.get("project"));
 		assertSame(this.directoryRequestObject, requestParameterMap.get("directory"));
 		assertSame(this.fileRequestObject, requestParameterMap.get("file"));
 	}
 
-	public void testComponentsListener() throws Exception {
-		UIOutput output = new UIOutput();
-		TreeComponentModelListenerImpl listener = new TreeComponentModelListenerImpl();
-		stackingTreeModel.addTreeComponentModelListener(listener);
-		assertNull(listener.getComponent());
-		filesModel.componentSelected(output);
-		assertSame(output, listener.getComponent());
+	public void testBadKey() throws Exception {
+		StackingTreeDataModelTestVisitor1 visitor1 = new StackingTreeDataModelTestVisitor1();
+		this.stackingTreeModel.walk(facesContext, visitor1, null, null);
+		this.stackingTreeModel.setRowKey(new ListRowKey(new StackingTreeModel.Key("project", "projectA")));
+		assertTrue(this.stackingTreeModel.isRowAvailable());
+		assertNotNull(this.stackingTreeModel.getRowData());
+		
+		this.stackingTreeModel.setRowKey(new ListRowKey(new StackingTreeModel.Key("project", "projectAAAAA")));
+		assertFalse(this.stackingTreeModel.isRowAvailable());
+		try {
+			this.stackingTreeModel.getRowData();
+			fail();
+		} catch (Exception e) {
 
-		listener.reset();
-		assertNull(listener.getComponent());
-		stackingTreeModel.removeTreeComponentModelListener(listener);
-		filesModel.componentSelected(output);
-		assertNull(listener.getComponent());
+		}
 	}
-
+	
 	public void testActiveData() throws Exception {
 		final ValueBinding fileVB = application.createValueBinding("#{directory.files}");
 		StackingTreeModel localFilesModel = new StackingTreeModel("file", "file", new StackingTreeModelDataProvider() {
@@ -251,23 +250,6 @@
 		assertFalse(new Key("aaa", null).hashCode() == new Key("aaa", new Integer(10)).hashCode());
 	}
 	
-	class TreeComponentModelListenerImpl implements TreeComponentModelListener {
-
-		private UIComponent component;
-
-		public void componentSelected(UIComponent component) {
-			this.component = component;
-		}
-
-		public UIComponent getComponent() {
-			return component;
-		}
-
-		public void reset() {
-			this.component = null;
-		}
-	};
-
 	class StackingTreeDataModelTestVisitor1 implements DataVisitor, LastElementAware {
 
 		private boolean last;
@@ -361,7 +343,11 @@
 			assertTrue(currentTag > tag);
 			this.tag = currentTag;
 
-			assertFalse(this.tag % 10 == 1 ^ last);
+			if (this.tag % 10 == 1) {
+				assertTrue(last);
+			} else {
+				assertFalse(last);
+			}
 
 			if (named instanceof Directory) {
 				if ("ADir1".equals(named.getName())) {

Modified: trunk/ui/tree/src/main/java/org/richfaces/component/UITree.java
===================================================================
--- trunk/ui/tree/src/main/java/org/richfaces/component/UITree.java	2007-08-16 00:05:26 UTC (rev 2283)
+++ trunk/ui/tree/src/main/java/org/richfaces/component/UITree.java	2007-08-16 00:55:58 UTC (rev 2284)
@@ -23,7 +23,6 @@
 
 import java.io.IOException;
 import java.util.Iterator;
-import java.util.LinkedHashMap;
 import java.util.Map;
 
 import javax.faces.application.Application;
@@ -64,11 +63,12 @@
 import org.richfaces.model.AbstractTreeDataModel;
 import org.richfaces.model.StackingTreeModel;
 import org.richfaces.model.StackingTreeModelProvider;
-import org.richfaces.model.TreeComponentModelListener;
 import org.richfaces.model.TreeDataModel;
+import org.richfaces.model.TreeModelVisualComponentProvider;
 import org.richfaces.model.TreeNode;
 import org.richfaces.model.TreeRange;
 import org.richfaces.model.TreeRowKey;
+import org.richfaces.model.VisualStackingTreeModel;
 
 /**
  * @author igels Component class providing tree ADT behaviuor
@@ -235,18 +235,20 @@
 				}
 			}
 		} else {
-			Iterator iterator = null;
-			if (visualModelComponent != null && visualModelComponent.isRendered()) {
-				if (visualModelComponent.getChildCount() > 0) {
-					iterator = visualModelComponent.getChildren().iterator();
-				}
-			} else {
-				if (getChildCount() > 0) {
-					iterator = getChildren().iterator();
-				}
+			UIComponent component = null;
+			
+			ExtendedDataModel dataModel = getExtendedDataModel();
+			if (dataModel instanceof TreeModelVisualComponentProvider) {
+				TreeModelVisualComponentProvider componentProvider = (TreeModelVisualComponentProvider) dataModel;
+				component = componentProvider.getComponent();
 			}
+
+			if (component == null) {
+				component = this;
+			}
 			
-			if (iterator != null) {
+			if (component.isRendered() && component.getChildCount() > 0) {
+				Iterator iterator = component.getChildren().iterator();
 				while (iterator.hasNext()) {
 					UIComponent child = (UIComponent) iterator.next();
 					
@@ -392,7 +394,7 @@
 			if (null != getAttributes().get(SELECTION_INPUT_ATTRIBUTE)) {
 				TreeState state = (TreeState) getComponentState();
 
-				if (state.setSelected(null)) {
+				if (!state.isSelected(null)) {
 					new NodeSelectedEvent(this).queue();
 				}
 			}
@@ -447,6 +449,13 @@
 		return treeState.isSelected((TreeRowKey) this.getRowKey());
 	}
 
+	/**
+	 * Sets current node as selected
+	 */
+	public void setSelected() {
+		TreeState treeState = (TreeState) getComponentState();
+		treeState.setSelected((TreeRowKey) this.getRowKey());
+	}
 
 	protected Iterator fixedChildren() {
 		return getFacets().values().iterator();
@@ -481,6 +490,13 @@
 			}
 		}
 
+		if (event instanceof NodeSelectedEvent) {
+			NodeSelectedEvent selectedEvent = (NodeSelectedEvent) event;
+			if (!selectedEvent.isDuplicate()) {
+				setSelected();
+			}
+		}
+
 		// fire node events
 		TreeEvents.invokeListenerBindings(this, event, getFacesContext());
 
@@ -493,8 +509,6 @@
 		return isAjaxSubmitSelection();
 	}
 
-	private transient UIComponent visualModelComponent;
-	
 	private ExtendedDataModel createDataModel(boolean allowCached) {
 		Object value = this.getValue();
 		if (value != null) {
@@ -508,7 +522,7 @@
 			return treeDataModel;
 		} else {
 			//TODO implement request caching
-			StackingTreeModel stackingTreeModel = new StackingTreeModel();
+			StackingTreeModel stackingTreeModel = new VisualStackingTreeModel(null);
 			if (getChildCount() > 0) {
 				Iterator children = getChildren().iterator();
 				while (children.hasNext()) {
@@ -520,13 +534,6 @@
 				}
 			}
 			
-			stackingTreeModel.addTreeComponentModelListener(new TreeComponentModelListener() {
-
-				public void componentSelected(UIComponent component) {
-					visualModelComponent = component;
-				}
-			});
-			
 			return stackingTreeModel;
 		}
 	}

Modified: trunk/ui/tree/src/main/java/org/richfaces/component/UITreeNode.java
===================================================================
--- trunk/ui/tree/src/main/java/org/richfaces/component/UITreeNode.java	2007-08-16 00:05:26 UTC (rev 2283)
+++ trunk/ui/tree/src/main/java/org/richfaces/component/UITreeNode.java	2007-08-16 00:55:58 UTC (rev 2284)
@@ -20,6 +20,7 @@
 import org.richfaces.event.DropEvent;
 import org.richfaces.event.DropListener;
 import org.richfaces.event.NodeExpandedListener;
+import org.richfaces.event.NodeSelectedEvent;
 import org.richfaces.event.NodeSelectedListener;
 import org.richfaces.event.TreeListenerEventsProducer;
 
@@ -104,10 +105,18 @@
 		super.broadcast(event);
 
 		FacesContext context = getFacesContext();
+		UITree tree = getUITree();
+
+		if (event instanceof NodeSelectedEvent) {
+			NodeSelectedEvent selectedEvent = (NodeSelectedEvent) event;
+			if (!selectedEvent.isDuplicate()) {
+				tree.setSelected();
+			}
+		}
+		
 		TreeEvents.invokeListenerBindings(this, event, context);
 
 		//TODO quick fix for UITree to invoke listeners
-		UITree tree = getUITree();
 		if (tree != null) {
 			if (event instanceof DragEvent || event instanceof DropEvent) {
 				tree.broadcast(event);

Modified: trunk/ui/tree/src/main/java/org/richfaces/component/state/TreeState.java
===================================================================
--- trunk/ui/tree/src/main/java/org/richfaces/component/state/TreeState.java	2007-08-16 00:05:26 UTC (rev 2283)
+++ trunk/ui/tree/src/main/java/org/richfaces/component/state/TreeState.java	2007-08-16 00:55:58 UTC (rev 2284)
@@ -32,10 +32,10 @@
 import org.ajax4jsf.model.DataComponentState;
 import org.ajax4jsf.model.DataVisitor;
 import org.ajax4jsf.model.Range;
-import org.richfaces.model.TreeRange;
-import org.richfaces.model.TreeRowKey;
 import org.richfaces.component.UITree;
 import org.richfaces.component.state.events.TreeStateCommandsListener;
+import org.richfaces.model.TreeRange;
+import org.richfaces.model.TreeRowKey;
 
 /**
  * @author Nick Belaevski - nbelaevski at exadel.com created 23.11.2006
@@ -114,37 +114,15 @@
 	}
 
 	public boolean isSelected(TreeRowKey rowKey) {
-		return (selectedNode != null && selectedNode.equals(rowKey));
+		return (rowKey == null && selectedNode == null) || (selectedNode != null && selectedNode.equals(rowKey));
 	}
 
 	public TreeRowKey getSelectedNode() {
 		return selectedNode;
 	}
 	
-	public boolean setSelected(TreeRowKey rowKey) {
-		if (selectedNode == null) {
-			if (rowKey != null) {
-				selectedNode = rowKey;
-
-				return true;
-			}
-
-			return false;
-		} else {
-			if (rowKey != null) {
-				if (!selectedNode.equals(rowKey)) {
-					selectedNode = rowKey;
-
-					return true;
-				}
-
-				return false;
-			} else {
-				selectedNode = null;
-
-				return true;
-			}
-		}
+	public void setSelected(TreeRowKey rowKey) {
+		selectedNode = rowKey;
 	}
 
 	private boolean _transient;
@@ -291,4 +269,5 @@
 		expandedNodes.removeAll(queuedCollapsedNodes);
 		queuedCollapsedNodes.clear();
 	}
+
 }

Modified: trunk/ui/tree/src/main/java/org/richfaces/renderkit/NodeRendererBase.java
===================================================================
--- trunk/ui/tree/src/main/java/org/richfaces/renderkit/NodeRendererBase.java	2007-08-16 00:05:26 UTC (rev 2283)
+++ trunk/ui/tree/src/main/java/org/richfaces/renderkit/NodeRendererBase.java	2007-08-16 00:55:58 UTC (rev 2284)
@@ -282,16 +282,16 @@
 
 		if (id.equals(tree.getAttributes()
 				.get(UITree.SELECTION_INPUT_ATTRIBUTE))) {
-			if (componentState.setSelected(key)) {
+			if (!componentState.isSelected(key)) {
 
 				if (tree.getAttributes().get(
 						UITree.SELECTED_NODE_PARAMETER_NAME) == null) {
 
 					new NodeSelectedEvent(node).queue();
-					new NodeSelectedEvent(tree).queue();
+					new NodeSelectedEvent(tree, true).queue();
 				} else {
 					new AjaxSelectedEvent(node).queue();
-					new AjaxSelectedEvent(tree).queue();
+					new AjaxSelectedEvent(tree, true).queue();
 				}
 			}
 

Modified: trunk/ui/tree/src/main/resources/org/richfaces/renderkit/html/scripts/tree.js
===================================================================
--- trunk/ui/tree/src/main/resources/org/richfaces/renderkit/html/scripts/tree.js	2007-08-16 00:05:26 UTC (rev 2283)
+++ trunk/ui/tree/src/main/resources/org/richfaces/renderkit/html/scripts/tree.js	2007-08-16 00:55:58 UTC (rev 2284)
@@ -65,7 +65,9 @@
 					if (!selectResult) {
 						event["cancelSelection"] = true;
 						event["treeItem"] = prevSelection;
-						prevSelection.toggleSelection(event);
+						if (prevSelection) {
+							prevSelection.toggleSelection(event);
+						}
 						return ;
 					}
 
@@ -73,7 +75,9 @@
 					if (!selectResult) {
 						event["cancelSelection"] = true;
 						event["treeItem"] = prevSelection;
-						prevSelection.toggleSelection(event);
+						if (prevSelection) {
+							prevSelection.toggleSelection(event);
+						}
 						return ;
 					}
 

Modified: trunk/ui/treeModel/src/main/java/org/richfaces/component/UIRecursiveTreeNodes.java
===================================================================
--- trunk/ui/treeModel/src/main/java/org/richfaces/component/UIRecursiveTreeNodes.java	2007-08-16 00:05:26 UTC (rev 2283)
+++ trunk/ui/treeModel/src/main/java/org/richfaces/component/UIRecursiveTreeNodes.java	2007-08-16 00:55:58 UTC (rev 2284)
@@ -6,13 +6,12 @@
 
 import java.util.Iterator;
 
-import javax.faces.context.FacesContext;
-import javax.faces.el.PropertyNotFoundException;
 import javax.faces.el.ValueBinding;
 
 import org.apache.commons.collections.iterators.IteratorChain;
 import org.richfaces.model.StackingTreeModel;
 import org.richfaces.model.StackingTreeModelDataProvider;
+import org.richfaces.model.VisualStackingTreeModel;
 
 
 /**
@@ -21,9 +20,9 @@
  */
 public abstract class UIRecursiveTreeNodes extends UITreeNodes {
 
-	private static final String COMPONENT_TYPE = "org.richfaces.RecursiveTreeNodes";
+	public static final String COMPONENT_TYPE = "org.richfaces.RecursiveTreeNodes";
 
-	private static final String COMPONENT_FAMILY = "org.richfaces.RecursiveTreeNodes";
+	public static final String COMPONENT_FAMILY = "org.richfaces.RecursiveTreeNodes";
 
 	public abstract Object getRoot();
 	public abstract void setRoot(Object root);
@@ -63,19 +62,14 @@
 	public StackingTreeModel getStackingModel() {
 		StackingTreeModel stackingModel = super.getStackingModel();
 		
-		StackingTreeModel recursiveModel = new StackingTreeModel(getId(), getVar(), new StackingTreeModelDataProvider() {
+		StackingTreeModel recursiveModel = new VisualStackingTreeModel(getId(), getVar(), new StackingTreeModelDataProvider() {
 
 			public Object getData() {
 				return UIRecursiveTreeNodes.this.getNodes();
 			}
 			
-		}) {
+		}, UIRecursiveTreeNodes.this) {
 
-			public void setupModel(Object object, FacesContext facesContext) {
-				super.setupModel(object, facesContext);
-				componentSelected(UIRecursiveTreeNodes.this);
-			}
-
 			public StackingTreeModel getModelById(String id) {
 				StackingTreeModel model = super.getModelById(id);
 				if (model == null) {

Modified: trunk/ui/treeModel/src/main/java/org/richfaces/component/UITreeNodes.java
===================================================================
--- trunk/ui/treeModel/src/main/java/org/richfaces/component/UITreeNodes.java	2007-08-16 00:05:26 UTC (rev 2283)
+++ trunk/ui/treeModel/src/main/java/org/richfaces/component/UITreeNodes.java	2007-08-16 00:55:58 UTC (rev 2284)
@@ -4,11 +4,10 @@
 
 package org.richfaces.component;
 
-import javax.faces.context.FacesContext;
-
 import org.richfaces.model.StackingTreeModel;
 import org.richfaces.model.StackingTreeModelDataProvider;
 import org.richfaces.model.StackingTreeModelProvider;
+import org.richfaces.model.VisualStackingTreeModel;
 
 
 /**
@@ -17,9 +16,9 @@
  */
 public abstract class UITreeNodes extends StackingTreeModelProvider {
 	
-	private static final String COMPONENT_TYPE = "org.richfaces.TreeNodes";
+	public static final String COMPONENT_TYPE = "org.richfaces.TreeNodes";
 	
-	private static final String COMPONENT_FAMILY = "org.richfaces.TreeNodes";
+	public static final String COMPONENT_FAMILY = "org.richfaces.TreeNodes";
 	
 	public abstract String getVar();
 	public abstract void setVar(String var);
@@ -28,18 +27,13 @@
 	public abstract void setActive(boolean active);
 	
 	protected StackingTreeModel createStackingTreeModel() {
-		StackingTreeModel treeModel = new StackingTreeModel(getId(), getVar(), new StackingTreeModelDataProvider() {
+		StackingTreeModel treeModel = new VisualStackingTreeModel(getId(), getVar(), new StackingTreeModelDataProvider() {
 
 			public Object getData() {
 				return UITreeNodes.this.getData();
 			}
 			
-		}) {
-			public void setupModel(Object object, FacesContext facesContext) {
-				super.setupModel(object, facesContext);
-				componentSelected(UITreeNodes.this);
-			}
-		
+		}, UITreeNodes.this) {
 			protected boolean isActive() {
 				return UITreeNodes.this.isRendered();
 			}

Deleted: trunk/ui/treeModel/src/test/java/org/richfaces/component/JSFComponentTest.java
===================================================================
--- trunk/ui/treeModel/src/test/java/org/richfaces/component/JSFComponentTest.java	2007-08-16 00:05:26 UTC (rev 2283)
+++ trunk/ui/treeModel/src/test/java/org/richfaces/component/JSFComponentTest.java	2007-08-16 00:55:58 UTC (rev 2284)
@@ -1,53 +0,0 @@
-/**
- * License Agreement.
- *
- * Rich Faces - Natural Ajax for Java Server Faces (JSF)
- *
- * Copyright (C) 2007 Exadel, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
- */
-
-package org.richfaces.component;
-
-import junit.framework.Test;
-import junit.framework.TestCase;
-import junit.framework.TestSuite;
-import javax.faces.component.UIComponent;
-
-/**
- * Unit test for simple Component.
- */
-public class JSFComponentTest 
-    extends TestCase
-{
-    /**
-     * Create the test case
-     *
-     * @param testName name of the test case
-     */
-    public JSFComponentTest( String testName )
-    {
-        super( testName );
-    }
-
-
-    /**
-     * Rigourous Test :-)
-     */
-    public void testComponent()
-    {
-        assertTrue( true );
-    }
-}

Copied: trunk/ui/treeModel/src/test/java/org/richfaces/component/TreeModelComponentTest.java (from rev 2262, trunk/ui/treeModel/src/test/java/org/richfaces/component/JSFComponentTest.java)
===================================================================
--- trunk/ui/treeModel/src/test/java/org/richfaces/component/TreeModelComponentTest.java	                        (rev 0)
+++ trunk/ui/treeModel/src/test/java/org/richfaces/component/TreeModelComponentTest.java	2007-08-16 00:55:58 UTC (rev 2284)
@@ -0,0 +1,261 @@
+/**
+ * License Agreement.
+ *
+ * Rich Faces - Natural Ajax for Java Server Faces (JSF)
+ *
+ * Copyright (C) 2007 Exadel, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ */
+
+package org.richfaces.component;
+
+import java.io.InputStream;
+import java.util.AbstractMap;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import javax.faces.component.UIComponent;
+import javax.faces.component.UIForm;
+import javax.faces.component.UIOutput;
+import javax.faces.component.UIViewRoot;
+import javax.faces.context.FacesContext;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import org.ajax4jsf.tests.AbstractAjax4JsfTestCase;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import com.gargoylesoftware.htmlunit.html.HtmlElement;
+import com.gargoylesoftware.htmlunit.html.HtmlPage;
+import com.gargoylesoftware.htmlunit.html.HtmlTable;
+import com.gargoylesoftware.htmlunit.html.HtmlTableCell;
+
+/**
+ * Unit test for simple Component.
+ */
+public class TreeModelComponentTest 
+    extends AbstractAjax4JsfTestCase
+{
+    /**
+     * Create the test case
+     *
+     * @param testName name of the test case
+     */
+    public TreeModelComponentTest( String testName )
+    {
+        super( testName );
+    }
+
+    private UIComponent createOutput(String vb) {
+    	UIComponent component = application.createComponent(UITreeNode.COMPONENT_TYPE);
+    	UIOutput output = (UIOutput) application.createComponent(UIOutput.COMPONENT_TYPE);
+    	output.setValueBinding("value", application.createValueBinding(vb));
+    	
+    	component.getChildren().add(output);
+    	return component;
+    }
+    
+    private Document document;
+    
+    private void clearDocument(Node node) {
+    	Node child = node.getFirstChild();
+    	while (child != null) {
+    		Node sibling = child.getNextSibling();
+    		if (child.getNodeType() == Node.TEXT_NODE && child.getNodeValue().trim().length() == 0) {
+    			child.getParentNode().removeChild(child);
+    		} else {
+    			clearDocument(child);
+    		}
+    		
+    		child = sibling;
+    	}
+    }
+
+    private Node findNode(String id, Node node) {
+    	Node n = node.getFirstChild();
+    	while (n != null) {
+    		NamedNodeMap attributes = n.getAttributes();
+    		if (attributes != null) {
+    			if (id.equals(attributes.getNamedItem("id").getNodeValue())) {
+    				return n;
+    			}
+    		}
+    		
+			Node result = findNode(id, n);
+			if (result != null) {
+				return result;
+			}
+
+			n = n.getNextSibling();
+    	}
+    	
+    	return null;
+    }
+    
+    public void setUp() throws Exception {
+    	super.setUp();
+
+    	facesContext.getExternalContext().getApplicationMap().put("XPathMap", new TreeModelComponentTestMap());
+    	facesContext.getExternalContext().getApplicationMap().put("XPathStringMap", new TreeModelComponentTestMap());
+    	InputStream stream = TreeModelComponentTest.class.getResourceAsStream("tree-model-data.xml");
+    	DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+    	document = factory.newDocumentBuilder().parse(stream);
+		clearDocument(document);
+		facesContext.getExternalContext().getApplicationMap().put("nodes", document.getDocumentElement());
+    
+		UIViewRoot viewRoot = facesContext.getViewRoot();
+		UIComponent form = application.createComponent(UIForm.COMPONENT_TYPE);
+		viewRoot.getChildren().add(form);
+		UITree tree = (UITree) application.createComponent(UITree.COMPONENT_TYPE);
+		tree.setSwitchType("client");
+		tree.setId("tree");
+		form.getChildren().add(tree);
+		
+		UITreeNodes project = (UITreeNodes) application.createComponent(UITreeNodes.COMPONENT_TYPE);
+		project.setVar("project");
+		project.setValueBinding("nodes", application.createValueBinding("#{nodes}"));
+		project.getChildren().add(createOutput("#{XPathStringMap['$project/@id']}"));
+		project.setId("project");
+		
+		tree.getChildren().add(project);
+    
+		UIRecursiveTreeNodes directories = (UIRecursiveTreeNodes) application.createComponent(UIRecursiveTreeNodes.COMPONENT_TYPE);
+		directories.setVar("dir");
+		directories.setValueBinding("root", application.createValueBinding("#{XPathMap['$project/directory']}"));
+		directories.setValueBinding("nodes", application.createValueBinding("#{XPathMap['$dir/directory']}"));
+		directories.getChildren().add(createOutput("#{XPathStringMap['$dir/@id']}"));
+		directories.setId("dir");
+		
+		project.getChildren().add(directories);
+
+		UITreeNodes files = (UITreeNodes) application.createComponent(UITreeNodes.COMPONENT_TYPE);
+		files.setVar("file");
+		files.setValueBinding("nodes", application.createValueBinding("#{XPathMap['$dir/file']}"));
+		files.getChildren().add(createOutput("#{XPathStringMap['$file/@id']}"));
+		files.setId("files");
+		
+		directories.getChildren().add(files);
+		
+		UIRecursiveTreeNodes archives = (UIRecursiveTreeNodes) application.createComponent(UIRecursiveTreeNodes.COMPONENT_TYPE);
+		archives.setVar("archiveEntry");
+		archives.setValueBinding("root", application.createValueBinding("#{XPathMap['$dir/archive']}"));
+		archives.setValueBinding("nodes", application.createValueBinding("#{XPathMap['$archiveEntry/archiveEntry']}"));
+		archives.getChildren().add(createOutput("#{XPathStringMap['$archiveEntry/@id']}"));
+		archives.setId("archives");
+		
+		directories.getChildren().add(archives);
+    }
+
+    public void tearDown() throws Exception {
+    	facesContext.getExternalContext().getApplicationMap().remove("XPathMap");
+    	facesContext.getExternalContext().getApplicationMap().remove("XPathStringMap");
+    	facesContext.getExternalContext().getApplicationMap().remove("nodes");
+
+    	super.tearDown();
+
+    	this.document = null;
+    }
+    
+    public void testRender() throws Exception {
+		HtmlPage renderedView = renderView();
+		List htmlElementsByTagName = renderedView.getDocumentElement().getHtmlElementsByTagName("table");
+		
+		Iterator allHtmlChildElements = htmlElementsByTagName.iterator();
+		int counter = 0;
+		
+		while (allHtmlChildElements.hasNext()) {
+			HtmlTable table = (HtmlTable) allHtmlChildElements.next();
+			HtmlTableCell handleCell = (HtmlTableCell) table.getCellAt(0, 0);
+			HtmlTableCell iconCell = (HtmlTableCell) table.getCellAt(0, 1);
+			HtmlTableCell textCell = (HtmlTableCell) table.getCellAt(0, 2);
+			
+			Element element = (Element) findNode(textCell.asText(), document);
+			//skip text siblings
+			Node nextSibling = element.getNextSibling();
+			
+			System.out.println(table);
+			System.out.println(handleCell);
+			System.out.println(textCell.asText() + " " + textCell);
+			System.out.println(element);
+
+			if (nextSibling == null) {
+				assertTrue(handleCell.getAttributeValue("class").contains("dr-tree-h-ic-line-last"));
+			} else {
+				assertTrue(handleCell.getAttributeValue("class").contains("dr-tree-h-ic-line-node"));
+			}
+			
+			HtmlElement handleElement = (HtmlElement) handleCell.getFirstChild().getFirstChild().getNextSibling();
+			String handleId = handleElement.getAttributeValue("id");
+			
+			if (element.getChildNodes().getLength() == 0) {
+				assertTrue(handleId.endsWith(":handle:img"));
+			} else {
+				assertTrue(handleId.endsWith(":handle"));
+			}
+			
+			counter++;
+		}
+		
+		assertEquals(30, counter);
+    }
+}
+
+class TreeModelComponentTestMap extends AbstractMap {
+
+	public Object get(Object key) {
+		String s = (String) key;
+		int idx = s.indexOf('/');
+		String varName = s.substring(1, idx);
+		String path = s.substring(idx + 1);
+		
+		FacesContext facesContext = FacesContext.getCurrentInstance();
+		Object var = facesContext.getApplication().getVariableResolver().resolveVariable(facesContext, varName);
+		
+		if (path.startsWith("@")) {
+			return ((Node) var).getAttributes().getNamedItem(path.substring(1)).getNodeValue();
+		} else {
+			NodeList nodeList = (NodeList) var;
+			final ArrayList nodes = new ArrayList();
+			for (int i = 0; i < nodeList.getLength(); i++) {
+				Node node = nodeList.item(i);
+				if (path.equals(node.getNodeName())) {
+					nodes.add(node);
+				}
+			}
+			
+			return new NodeList() {
+
+				public int getLength() {
+					return nodes.size();
+				}
+
+				public Node item(int index) {
+					return (Node) nodes.get(index);
+				}
+				
+			};
+		}
+	}
+	
+	public Set entrySet() {
+		return null;
+	}
+	
+}
\ No newline at end of file

Added: trunk/ui/treeModel/src/test/resources/org/richfaces/component/tree-model-data.xml
===================================================================
--- trunk/ui/treeModel/src/test/resources/org/richfaces/component/tree-model-data.xml	                        (rev 0)
+++ trunk/ui/treeModel/src/test/resources/org/richfaces/component/tree-model-data.xml	2007-08-16 00:55:58 UTC (rev 2284)
@@ -0,0 +1,49 @@
+<?xml version="1.0"?>
+
+<root id="0">
+	<project name="richfaces" id="1">
+		<directory name="design" id="2">
+			<directory name="funcspec" id="3">
+				<file name="FunctionalSpecification-1.0.doc" id="4"/>
+				<file name="Requirements-1.0.doc" id="5"/>
+			</directory>			
+		</directory>
+		<directory name="src" id="6">
+			<directory name="main" id="7">
+				<directory name="config" id="8">
+					<directory name="org" id="9">
+						<directory name="richfaces" id="10">
+							<directory name="component" id="11">
+								<file name="tree.config.xml" id="12"/>
+								<file name="treeNode.config.xml" id="13"/>
+							</directory>
+						</directory>
+					</directory>
+				</directory>
+				<directory name="templates" id="14"></directory>
+			</directory>
+			<directory name="test" id="15"></directory>
+		</directory>
+		<directory name="target" id="16">
+			<file name="richfaces-3.1.0-snapshot" id="21"/>
+			<file name="richfaces-3.1.0-javadoc" id="30"/>
+			<archive name="richfaces-3.1.0-sources" id="22">
+				<archiveEntry name="org" id="23">
+					<archiveEntry name="richfaces" id="24">
+						<archiveEntry name="component" id="25">
+							<archiveEntry name="UITree" id="26"/>
+							<archiveEntry name="UITreeNode" id="27"/>
+							<archiveEntry name="UICalendar" id="28"/>
+							<archiveEntry name="UIRangedNumberInput" id="29"/>
+						</archiveEntry>
+					</archiveEntry>
+				</archiveEntry>
+			</archive>
+			<directory name="generated-component" id="17" />
+			<directory name="surefire-reports" id="18">
+				<file name="org.richfaces.JSFComponentTest.txt" id="19"/>
+				<file name="TEST-ComponentTest.xml" id="20"/>
+			</directory>
+		</directory>
+	</project>
+</root>
\ No newline at end of file




More information about the richfaces-svn-commits mailing list