Author: dmorozov
Date: 2008-06-20 10:18:44 -0400 (Fri, 20 Jun 2008)
New Revision: 9143
Added:
trunk/samples/tree-demo/src/main/java/org/richfaces/TreeContainer.java
trunk/samples/tree-demo/src/main/java/org/richfaces/TreeDndBean.java
trunk/samples/tree-demo/src/main/resources/org/richfaces/simpleTreeData.properties
trunk/samples/tree-demo/src/main/webapp/pages/dnd.jsp
Modified:
trunk/framework/api/src/main/java/org/richfaces/model/AbstractTreeDataModel.java
trunk/framework/api/src/main/java/org/richfaces/model/ListRowKey.java
trunk/framework/api/src/main/java/org/richfaces/model/TreeDataModel.java
trunk/framework/api/src/main/java/org/richfaces/model/TreeDataModelNodeAdaptor.java
trunk/samples/tree-demo/src/main/java/org/richfaces/Bean.java
trunk/samples/tree-demo/src/main/webapp/WEB-INF/faces-config.xml
trunk/ui/drag-drop/src/main/java/org/richfaces/renderkit/DnDEventsExchangeMailer.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
Log:
http://jira.jboss.com/jira/browse/RF-2987
Modified:
trunk/framework/api/src/main/java/org/richfaces/model/AbstractTreeDataModel.java
===================================================================
---
trunk/framework/api/src/main/java/org/richfaces/model/AbstractTreeDataModel.java 2008-06-20
14:15:20 UTC (rev 9142)
+++
trunk/framework/api/src/main/java/org/richfaces/model/AbstractTreeDataModel.java 2008-06-20
14:18:44 UTC (rev 9143)
@@ -125,8 +125,34 @@
}
}
+ /**
+ * Get current tree node.
+ * Note: valid only for classical TreeNode based tree data model implementation
+ *
+ * @return current tree node
+ */
public abstract TreeNode getTreeNode();
public abstract Object convertToKey(FacesContext context, String keyString,
UIComponent component, Converter converter);
+
+ /**
+ * Get row key for certain tree node object
+ *
+ * @param node to get key for
+ * @return node row key
+ */
+ public Object getTreeNodeRowKey(Object node) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Get node local id in it's parent childs collection
+ *
+ * @param childNode node to get identifier for
+ * @return node local identifier
+ */
+ public Object getChildNodeId(Object childNode) {
+ throw new UnsupportedOperationException();
+ }
}
Modified: trunk/framework/api/src/main/java/org/richfaces/model/ListRowKey.java
===================================================================
--- trunk/framework/api/src/main/java/org/richfaces/model/ListRowKey.java 2008-06-20
14:15:20 UTC (rev 9142)
+++ trunk/framework/api/src/main/java/org/richfaces/model/ListRowKey.java 2008-06-20
14:18:44 UTC (rev 9143)
@@ -71,6 +71,7 @@
/**
* Appending constructor
+ *
* @param parentRowKey base row key
* @param pathElement path segment to append to base row key
*/
@@ -79,6 +80,15 @@
this.path.add(pathElement);
}
+ /**
+ * Appending constructor
+ * @param parentRowKey base row key
+ * @param pathElement path segment to append to base row key
+ */
+ public ListRowKey(ListRowKey<T> parentRowKey, ListRowKey<T> childRowKey) {
+ this(parentRowKey);
+ this.path.addAll(childRowKey.path);
+ }
/**
* List constructor
Modified: trunk/framework/api/src/main/java/org/richfaces/model/TreeDataModel.java
===================================================================
--- trunk/framework/api/src/main/java/org/richfaces/model/TreeDataModel.java 2008-06-20
14:15:20 UTC (rev 9142)
+++ trunk/framework/api/src/main/java/org/richfaces/model/TreeDataModel.java 2008-06-20
14:18:44 UTC (rev 9143)
@@ -23,6 +23,8 @@
import java.io.IOException;
import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
import java.util.Map;
import javax.faces.context.FacesContext;
@@ -313,4 +315,46 @@
return null;
}
+ /**
+ * Get row key for certain tree node object
+ *
+ * @param node to get key for
+ * @return node row key
+ */
+ @Override
+ @SuppressWarnings("unchecked")
+ public Object getTreeNodeRowKey(Object node) {
+ if (node == null) {
+ throw new UnsupportedOperationException();
+ }
+
+ T childNode = (T) node;
+ List<Object> path = new LinkedList<Object>();
+ Object id = nodeAdaptor.getChildNodeId(childNode);
+ if (id != null) {
+ path.add(id);
+ }
+
+ T parentNode = childNode;
+ while ((parentNode = nodeAdaptor.getParent(parentNode)) != null) {
+ id = nodeAdaptor.getChildNodeId(parentNode);
+ if (id != null) {
+ path.add(0, id);
+ } else if (nodeAdaptor.getParent(parentNode) != null) {
+ throw new UnsupportedOperationException();
+ }
+ }
+ return new ListRowKey(path);
+ }
+
+ /**
+ * Get node local id in it's parent childs collection
+ *
+ * @param childNode node to get identifier for
+ * @return node local identifier
+ */
+ @Override
+ public Object getChildNodeId(Object childNode) {
+ return getNodeAdaptor().getChildNodeId((T) childNode);
+ }
}
Modified:
trunk/framework/api/src/main/java/org/richfaces/model/TreeDataModelNodeAdaptor.java
===================================================================
---
trunk/framework/api/src/main/java/org/richfaces/model/TreeDataModelNodeAdaptor.java 2008-06-20
14:15:20 UTC (rev 9142)
+++
trunk/framework/api/src/main/java/org/richfaces/model/TreeDataModelNodeAdaptor.java 2008-06-20
14:18:44 UTC (rev 9143)
@@ -48,6 +48,14 @@
public Iterator<Map.Entry<Object, T>> getChildren(T node);
public Object getRowData(T node);
+
+ /**
+ * Get node local id in it's parent childs collection
+ *
+ * @param childNode node to get identifier for
+ * @return node local identifier
+ */
+ public Object getChildNodeId(T childNode);
/**
* Instance of {@link TreeDataModelNodeAdaptor} for {@link org.richfaces.model.TreeNode}
nodes handling
@@ -76,7 +84,26 @@
public boolean isLeaf(org.richfaces.model.TreeNode node) {
return node.isLeaf();
}
-
+
+ /**
+ * Get node local id in it's parent childs collection
+ *
+ * @param childNode node to get identifier for
+ * @return node local identifier
+ */
+ public Object getChildNodeId(org.richfaces.model.TreeNode childNode) {
+ org.richfaces.model.TreeNode parentNode = getParent(childNode);
+ if (childNode != null && parentNode != null) {
+ Iterator<Map.Entry<Object, TreeNode>> iter =
parentNode.getChildren();
+ while (iter != null && iter.hasNext()) {
+ Map.Entry<Object, TreeNode> entry = iter.next();
+ if (entry != null && childNode.equals(entry.getValue())) {
+ return entry.getKey();
+ }
+ }
+ }
+ return null;
+ }
};
/**
@@ -165,5 +192,25 @@
public boolean isLeaf(javax.swing.tree.TreeNode node) {
return !node.getAllowsChildren() || node.isLeaf();
}
+
+ /**
+ * Get node local id in it's parent childs collection
+ *
+ * @param childNode node to get identifier for
+ * @return node local identifier
+ */
+ public Object getChildNodeId(javax.swing.tree.TreeNode childNode) {
+ javax.swing.tree.TreeNode parentNode = getParent(childNode);
+ if (childNode != null && parentNode != null) {
+ Iterator<Map.Entry<Object, TreeNode>> iter =
getChildren(parentNode);
+ while (iter != null && iter.hasNext()) {
+ Map.Entry<Object, TreeNode> entry = iter.next();
+ if (entry != null && childNode.equals(entry.getValue())) {
+ return entry.getKey();
+ }
+ }
+ }
+ return null;
+ }
};
}
Modified: trunk/samples/tree-demo/src/main/java/org/richfaces/Bean.java
===================================================================
--- trunk/samples/tree-demo/src/main/java/org/richfaces/Bean.java 2008-06-20 14:15:20 UTC
(rev 9142)
+++ trunk/samples/tree-demo/src/main/java/org/richfaces/Bean.java 2008-06-20 14:18:44 UTC
(rev 9143)
@@ -34,11 +34,9 @@
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
-import javax.faces.event.FacesEvent;
import org.ajax4jsf.context.AjaxContext;
import org.richfaces.component.UITree;
-import org.richfaces.component.UITreeNode;
import org.richfaces.component.xml.XmlTreeDataBuilder;
import org.richfaces.event.DropEvent;
import org.richfaces.event.NodeExpandedEvent;
@@ -54,7 +52,7 @@
* @author $Autor$
*
*/
-public class Bean {
+public class Bean extends TreeContainer {
private String switchType = "client";
private TreeNode data;
@@ -199,19 +197,6 @@
this.switchType = switchType;
}
- private UITree getTree(FacesEvent event) {
- UIComponent component = event.getComponent();
- if (component instanceof UITree) {
- return ((UITree) component);
- }
-
- if (component instanceof UITreeNode) {
- return ((UITree) component.getParent());
- }
-
- return null;
- }
-
public void up() {
if(selectedNode.getParent()!=null) {
selectedNode = selectedNode.getParent();
Added: trunk/samples/tree-demo/src/main/java/org/richfaces/TreeContainer.java
===================================================================
--- trunk/samples/tree-demo/src/main/java/org/richfaces/TreeContainer.java
(rev 0)
+++ trunk/samples/tree-demo/src/main/java/org/richfaces/TreeContainer.java 2008-06-20
14:18:44 UTC (rev 9143)
@@ -0,0 +1,44 @@
+/**
+ *
+ */
+package org.richfaces;
+
+import javax.faces.component.UIComponent;
+import javax.faces.event.FacesEvent;
+
+import org.richfaces.component.UITree;
+import org.richfaces.component.UITreeNode;
+
+/**
+ * @author dmorozov
+ *
+ */
+public class TreeContainer {
+
+ /**
+ * Get tree component from event
+ *
+ * @param event tree event
+ * @return tree component
+ */
+ protected UITree getTree(FacesEvent event) {
+ return getTree(event.getComponent());
+ }
+
+ /**
+ * Safe getter of tree component
+ * @param component component to process
+ * @return tree component
+ */
+ protected UITree getTree(UIComponent component) {
+ if (component instanceof UITree) {
+ return ((UITree) component);
+ }
+
+ if (component instanceof UITreeNode) {
+ return ((UITree) component.getParent());
+ }
+
+ return null;
+ }
+}
Added: trunk/samples/tree-demo/src/main/java/org/richfaces/TreeDndBean.java
===================================================================
--- trunk/samples/tree-demo/src/main/java/org/richfaces/TreeDndBean.java
(rev 0)
+++ trunk/samples/tree-demo/src/main/java/org/richfaces/TreeDndBean.java 2008-06-20
14:18:44 UTC (rev 9143)
@@ -0,0 +1,333 @@
+/**
+ *
+ */
+package org.richfaces;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.faces.FacesException;
+import javax.faces.context.ExternalContext;
+import javax.faces.context.FacesContext;
+
+import org.ajax4jsf.context.AjaxContext;
+import org.richfaces.component.UITree;
+import org.richfaces.component.UITreeNode;
+import org.richfaces.event.DragEvent;
+import org.richfaces.event.DropEvent;
+import org.richfaces.event.NodeExpandedEvent;
+import org.richfaces.event.NodeSelectedEvent;
+import org.richfaces.model.TreeNode;
+import org.richfaces.model.TreeNodeImpl;
+import org.richfaces.model.TreeRowKey;
+
+/**
+ * @author dmorozov
+ *
+ */
+public class TreeDndBean extends TreeContainer {
+ private static final String DATA_PATH1 =
"org/richfaces/simpleTreeData.properties";
+
+ private TreeNode<String> treeNodeLeft;
+
+ private TreeNode<String> treeNodeRight;
+
+ private String leftSelectedNodeTitle;
+
+ private String rightSelectedNodeTitle;
+
+ private UITree leftTree;
+
+ private UITree rightTree;
+
+ /**
+ * Helper tree model creation method from properties object
+ *
+ * @param path node path
+ * @param node parent node
+ * @param properties properties object
+ */
+ private void addNodes(String path, TreeNode<String> node, Properties
properties) {
+ boolean end = false;
+ int counter = 1;
+ while (!end) {
+ String key = path != null ? path + '.' + counter : String.valueOf(counter);
+ String value = properties.getProperty(key);
+ if (value != null) {
+ TreeNodeImpl<String> nodeImpl = new TreeNodeImpl<String>();
+ nodeImpl.setData(value);
+ node.addChild(new Integer(counter), nodeImpl);
+ addNodes(key, nodeImpl, properties);
+ counter++;
+ } else {
+ end = true;
+ }
+ }
+ }
+
+ /**
+ * Init sample tree model
+ *
+ * @return tree model
+ */
+ private TreeNode<String> initPaneTree() {
+ TreeNode<String> rootNode = null;
+ FacesContext facesContext = FacesContext.getCurrentInstance();
+ ExternalContext externalContext = facesContext.getExternalContext();
+
+ InputStream dataStream =
this.getClass().getClassLoader().getResourceAsStream(DATA_PATH1);
+
+ try {
+ Properties properties = new Properties();
+ properties.load(dataStream);
+ rootNode = new TreeNodeImpl<String>();
+ addNodes(null, rootNode, properties);
+ } catch (IOException e) {
+
+ throw new FacesException(e.getMessage(), e);
+
+ } finally {
+ if (dataStream != null) {
+ try {
+ dataStream.close();
+ } catch (IOException e) {
+ externalContext.log(e.getMessage(), e);
+ }
+ }
+ }
+
+ return rootNode;
+ }
+
+ /**
+ * Left tree demo selection handler.
+ * @param event node selection event
+ */
+ public void processLSelection(NodeSelectedEvent event) {
+ UITree tree = (UITree) event.getComponent();
+ leftSelectedNodeTitle = (String) tree.getRowData();
+ }
+
+ /**
+ * Right tree demo selection handler.
+ * @param event node selection event
+ */
+ public void processRSelection(NodeSelectedEvent event) {
+ UITree tree = (UITree) event.getComponent();
+ if (tree != null) {
+ rightSelectedNodeTitle = (String) tree.getRowData();
+ }
+ }
+
+ /**
+ * Left tree value binding
+ * @return the treeNodeLeft
+ */
+ public TreeNode<String> getTreeNodeLeft() {
+ if (treeNodeLeft == null) {
+ treeNodeLeft = initPaneTree();
+ }
+ return treeNodeLeft;
+ }
+
+ /**
+ * Left tree value binding
+ * @param treeNodeLeft
+ * the treeNodeLeft to set
+ */
+ public void setTreeNodeLeft(TreeNode<String> treeNodeLeft) {
+ this.treeNodeLeft = treeNodeLeft;
+ }
+
+ /**
+ * @return the leftSelectedNodeTitle
+ */
+ public String getLeftSelectedNodeTitle() {
+ return leftSelectedNodeTitle;
+ }
+
+ /**
+ * @param leftSelectedNodeTitle
+ * the leftSelectedNodeTitle to set
+ */
+ public void setLeftSelectedNodeTitle(String leftSelectedNodeTitle) {
+ this.leftSelectedNodeTitle = leftSelectedNodeTitle;
+ }
+
+ /**
+ * @return the rightSelectedNodeTitle
+ */
+ public String getRightSelectedNodeTitle() {
+ return rightSelectedNodeTitle;
+ }
+
+ /**
+ * @param rightSelectedNodeTitle
+ * the rightSelectedNodeTitle to set
+ */
+ public void setRightSelectedNodeTitle(String rightSelectedNodeTitle) {
+ this.rightSelectedNodeTitle = rightSelectedNodeTitle;
+ }
+
+ /**
+ * Right tree value binding
+ * @return the treeNodeRight
+ */
+ public TreeNode<String> getTreeNodeRight() {
+ if (treeNodeRight == null) {
+ treeNodeRight = initPaneTree();
+ }
+ return treeNodeRight;
+ }
+
+ /**
+ * Right tree value binding
+ * @param treeNodeRight
+ * the treeNodeRight to set
+ */
+ public void setTreeNodeRight(TreeNode<String> treeNodeRight) {
+ this.treeNodeRight = treeNodeRight;
+ }
+
+ /**
+ * Left tree binding
+ * @return the leftTree
+ */
+ public UITree getLeftTree() {
+ return leftTree;
+ }
+
+ /**
+ * Left tree binding
+ * @param leftTree
+ * the leftTree to set
+ */
+ public void setLeftTree(UITree leftTree) {
+ this.leftTree = leftTree;
+ }
+
+ /**
+ * Right tree binding
+ * @return the rightTree
+ */
+ public UITree getRightTree() {
+ return rightTree;
+ }
+
+ /**
+ * Right tree binding
+ * @param rightTree
+ * the rightTree to set
+ */
+ public void setRightTree(UITree rightTree) {
+ this.rightTree = rightTree;
+ }
+
+ /**
+ * Expand event handler
+ * @param event expand event
+ */
+ public void onExpand(NodeExpandedEvent event) {
+ UITree tree = getTree(event);
+ System.out.println("Tree ('"+tree.getId()+"') node " +
(tree.isExpanded() ? "expanded" : "collapsed") + " " +
tree.getRowKey());
+ }
+
+ /**
+ * Drag event handler
+ * @param dragEvent event handler
+ */
+ public void onDrag(DragEvent dragEvent) {
+ System.out.println("onDrag occured.");
+ System.out.println("DragValue: " + dragEvent.getDragValue());
+ System.out.println("DropValue: " + dragEvent.getDropValue());
+ }
+
+ /**
+ * Sample unique subnode identifier generation
+ *
+ * @param parentNode parent node
+ * @return unique subnode identifier
+ */
+ private Object getNewId(TreeNode parentNode) {
+ Map<Object, TreeNode> childs = new HashMap<Object, TreeNode>();
+ Iterator<Map.Entry<Object, TreeNode>> iter = parentNode.getChildren();
+ while (iter != null && iter.hasNext()) {
+ Map.Entry<Object, TreeNode> entry = iter.next();
+ childs.put(entry.getKey(), entry.getValue());
+ }
+
+ Integer index = 1;
+ while (childs.containsKey(index)) {
+ index++;
+ }
+ return index;
+ }
+
+ /**
+ * Drop event handler
+ * @param dropEvent Drop event
+ */
+ public void onDrop(DropEvent dropEvent) {
+ System.out.println("onDrop occured.");
+ System.out.println("DragValue: " + dropEvent.getDragValue());
+ System.out.println("DropValue: " + dropEvent.getDropValue());
+
+ // resolve drag source attributes
+ UITreeNode srcNode = (dropEvent.getDraggableSource() instanceof UITreeNode) ?
(UITreeNode) dropEvent.getDraggableSource() : null;
+ UITree srcTree = srcNode != null ? srcNode.getUITree() : null;
+ TreeRowKey dragNodeKey = (dropEvent.getDragValue() instanceof TreeRowKey) ? (TreeRowKey)
dropEvent.getDragValue() : null;
+
+ // resolve drag destination attributes
+ UITreeNode destNode = (dropEvent.getSource() instanceof UITreeNode) ? (UITreeNode)
dropEvent.getSource() : null;
+ UITree destTree = destNode != null ? destNode.getUITree() : getTree(dropEvent);
+ TreeRowKey dropNodeKey = (dropEvent.getDropValue() instanceof TreeRowKey) ? (TreeRowKey)
dropEvent.getDropValue() : null;
+
+ FacesContext context = FacesContext.getCurrentInstance();
+
+ if (dropNodeKey != null) {
+ // add destination node for rerender
+ destTree.addRequestKey(dropNodeKey);
+
+ Object state = null;
+ TreeNode draggedNode = null;
+ if (dragNodeKey != null) { // Drag from this or other tree
+ draggedNode = srcTree.getTreeNode(dragNodeKey);
+
+ TreeNode parentNode = draggedNode.getParent();
+ // 1. remove node from tree
+ state = srcTree.removeNode(dragNodeKey);
+ // 2. add parent for rerender
+ Object rowKey = srcTree.getTreeNodeRowKey(parentNode);
+ srcTree.addRequestKey(rowKey);
+ } else if (dropEvent.getDragValue() != null) { // Drag from some drag source
+ draggedNode = new TreeNodeImpl<String>();
+ draggedNode.setData(dropEvent.getDragValue().toString());
+ }
+
+ // generate new node id
+ Object id = getNewId(destTree.getTreeNode(dropNodeKey));
+ destTree.addNode(dropNodeKey, draggedNode, id, state);
+ }
+
+ AjaxContext ac = AjaxContext.getCurrentInstance();
+ // Add destination tree to reRender
+ try {
+ ac.addComponentToAjaxRender(destTree);
+ } catch (Exception e) {
+ System.err.print(e.getMessage());
+ }
+
+ // Add source tree to reRender
+ try {
+ ac.addComponentToAjaxRender(srcTree);
+ } catch (Exception e) {
+ System.err.print(e.getMessage());
+ }
+
+ System.out.println("+++++");
+ }
+}
Added: trunk/samples/tree-demo/src/main/resources/org/richfaces/simpleTreeData.properties
===================================================================
--- trunk/samples/tree-demo/src/main/resources/org/richfaces/simpleTreeData.properties
(rev 0)
+++
trunk/samples/tree-demo/src/main/resources/org/richfaces/simpleTreeData.properties 2008-06-20
14:18:44 UTC (rev 9143)
@@ -0,0 +1,67 @@
+1=Daniel Defo
+1.1=Robinson Crusoe
+1.1.1=Start In Life
+1.1.2=Slavery And Escape
+1.1.3=Wrecked On A Desert Island
+1.1.4=First Weeks On The Island
+1.1.5=Builds A House - The Journal
+1.1.6=Ill And Conscience-Stricken
+1.1.7=Agricultural Experience
+1.1.8=Surveys His Position
+1.1.9=A Boat
+1.1.10=Tames Goats
+1.1.11=Finds Print Of Man's Foot On The Sand
+1.1.12=A Cave Retreat
+1.1.13=Wreck Of A Spanish Ship
+1.1.14=A Dream Realised
+1.1.15=Friday's Education
+1.1.16=Rescue Of Prisoners From Cannibals
+1.1.17=Visit Of Mutineers
+1.1.18=The Ship Recovered
+1.1.19=Return To England
+1.1.20=Fight Between Friday And A Bear
+2=Edgar Allan Poe
+2.1=Plays
+2.1.1=Politian
+2.2=Short stories
+2.2.1=The Assignation
+2.2.2=Berenice
+2.2.3=The Black Cat
+2.2.4=The Cask of Amontillado
+2.2.5=A Descent into the Maelstrom
+2.3=Poetry
+2.3.1=Alone
+2.3.2=An Enigma
+2.3.3=Annabel Lee
+2.3.4=Bridal Ballad
+3=Henry Wadsworth Longfellow
+3.1=The Song of Hiawatha
+3.1.1=Introduction
+3.1.2=I. The Peace-Pipe
+3.1.3=II. The Four Winds
+3.1.4=III. Hiawatha's Childhood
+3.1.5=IV. Hiawatha and Mudjekeewis
+3.1.6=V. Hiawatha's Fasting
+3.1.7=VI. Hiawatha's Friends
+3.1.8=VII. Hiawatha's Sailing
+3.1.9=VIII. Hiawatha's Fishing
+3.1.10=IX. Hiawatha and the Pearl-Feather
+3.1.11=X. Hiawatha's Wooing
+3.1.12=XI. Hiawatha's Wedding-Feast
+3.1.13=XII. The Son of the Evening Star
+3.1.14=XIII. Blessing the Cornfields
+3.1.15=XIV. Picture-Writing
+3.1.16=XV. Hiawatha's Lamentation
+3.1.17=XVI. Pau-Puk-Keewis
+3.1.18=XVII. The Hunting of Pau-Puk-Keewis
+3.1.19=XVIII. The Death of Kwasind
+3.1.20=XIX. The Ghosts
+3.1.21=XX. The Famine
+3.1.22=XXI. The White Man's Foot
+3.1.23=XXII. Hiawatha's Departure
+3.2=Poetry
+3.2.1=A Psalm Of Life
+3.2.2=Birds Of Passage
+3.2.3=Hiawatha's Childhood
+3.2.4=Hymn To The Night
+
Modified: trunk/samples/tree-demo/src/main/webapp/WEB-INF/faces-config.xml
===================================================================
--- trunk/samples/tree-demo/src/main/webapp/WEB-INF/faces-config.xml 2008-06-20 14:15:20
UTC (rev 9142)
+++ trunk/samples/tree-demo/src/main/webapp/WEB-INF/faces-config.xml 2008-06-20 14:18:44
UTC (rev 9143)
@@ -1,20 +1,27 @@
-<?xml version="1.0"?>
+<?xml version="1.0"?>
<!DOCTYPE faces-config PUBLIC "-//Sun Microsystems, Inc.//DTD JavaServer Faces
Config 1.1//EN"
"http://java.sun.com/dtd/web-facesconfig_1_1.dtd">
<faces-config>
- <managed-bean>
- <managed-bean-name>bean</managed-bean-name>
- <managed-bean-class>org.richfaces.Bean</managed-bean-class>
- <managed-bean-scope>session</managed-bean-scope>
- </managed-bean>
-<managed-bean>
- <managed-bean-name>pathwayBean</managed-bean-name>
- <managed-bean-class>org.richfaces.TreeBean</managed-bean-class>
- <managed-bean-scope>session</managed-bean-scope>
-</managed-bean>
- <managed-bean>
- <managed-bean-name>skinBean</managed-bean-name>
- <managed-bean-class>org.richfaces.SkinBean</managed-bean-class>
- <managed-bean-scope>session</managed-bean-scope>
- </managed-bean>
+ <managed-bean>
+ <managed-bean-name>bean</managed-bean-name>
+ <managed-bean-class>org.richfaces.Bean</managed-bean-class>
+ <managed-bean-scope>session</managed-bean-scope>
+ </managed-bean>
+ <managed-bean>
+ <managed-bean-name>pathwayBean</managed-bean-name>
+ <managed-bean-class>org.richfaces.TreeBean</managed-bean-class>
+ <managed-bean-scope>session</managed-bean-scope>
+ </managed-bean>
+
+ <managed-bean>
+ <managed-bean-name>treeDndBean</managed-bean-name>
+ <managed-bean-class>org.richfaces.TreeDndBean</managed-bean-class>
+ <managed-bean-scope>session</managed-bean-scope>
+ </managed-bean>
+
+ <managed-bean>
+ <managed-bean-name>skinBean</managed-bean-name>
+ <managed-bean-class>org.richfaces.SkinBean</managed-bean-class>
+ <managed-bean-scope>session</managed-bean-scope>
+ </managed-bean>
</faces-config>
Added: trunk/samples/tree-demo/src/main/webapp/pages/dnd.jsp
===================================================================
--- trunk/samples/tree-demo/src/main/webapp/pages/dnd.jsp (rev 0)
+++ trunk/samples/tree-demo/src/main/webapp/pages/dnd.jsp 2008-06-20 14:18:44 UTC (rev
9143)
@@ -0,0 +1,114 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<%@ taglib
uri="http://java.sun.com/jsf/html" prefix="h"%>
+<%@ taglib
uri="http://java.sun.com/jsf/core" prefix="f"%>
+<%@ taglib
uri="http://richfaces.org/a4j" prefix="a4j"%>
+<%@ taglib
uri="http://labs.jboss.com/jbossrichfaces/ui/drag-drop"
prefix="dnd" %>
+<%@ taglib
uri="http://labs.jboss.com/jbossrichfaces/ui/tree"
prefix="rich"%>
+<html>
+<head>
+ <title>Tree Drag & Drop sample</title>
+ <style type="text/css">
+ .LeftTreePane {
+ }
+ .RightTreePane {
+ }
+ .TreeContainer {
+ overflow: auto;
+ height: 400px;
+ border: 3px inset gray;
+ }
+ </style>
+ <script type="text/javascript">
+ // <![CDATA[
+ function blinkElement(elt) {
+ while (elt.tagName.toLowerCase() != 'table') {
+ elt = elt.parentNode;
+ }
+
+ elt.style.borderColor= '#5555FF';
+ elt.style.borderStyle= 'dotted';
+ elt.style.borderWidth = '3px';
+ setTimeout( function() { this.style.borderStyle = 'none'; }.bind(elt), 300);
+ }
+ // ]]>
+ </script>
+</head>
+<body>
+<f:view>
+ <h:form>
+ <dnd:dragIndicator id="treeIndicator">
+ <f:facet name="single">
+ <f:verbatim>{marker} {nodeParam}({treeParam})</f:verbatim>
+ </f:facet>
+ </dnd:dragIndicator>
+
+ <h:panelGrid columns="2"
columnClasses="LeftTreePane,RightTreePane">
+
+ <h:panelGroup id="leftContainer" layout="block"
styleClass="TreeContainer">
+ <h:outputText escape="false"
+ value="Selected Node:
<b>#{treeDndBean.leftSelectedNodeTitle}</b>"
+ id="selectedNodeL" />
+
+ <rich:tree id="leftTree" style="width:300px"
+ nodeSelectListener="#{treeDndBean.processLSelection}"
+ reRender="selectedNodeL" ajaxSubmitSelection="false"
+ switchType="client" value="#{treeDndBean.treeNodeLeft}"
+
+ changeExpandListener="#{treeDndBean.onExpand}"
+ binding="#{treeDndBean.leftTree}"
+ onselected="window.status='selectedNode: '+event.selectedNode;"
+ onexpand="window.status='expandedNode: '+event.expandedNode"
+ oncollapse="window.status='collapsedNode:
'+event.collapsedNode"
+
+ dropListener="#{treeDndBean.onDrop}"
+ dragListener="#{treeDndBean.onDrag}"
+
+ dragIndicator="treeIndicator"
+ acceptedTypes="treeNode"
+ dragType="treeNode"
+ rowKeyVar="key"
+ var="item">
+
+ <dnd:dndParam name="treeParam" value="leftTree" />
+ </rich:tree>
+
+ </h:panelGroup>
+
+ <h:panelGroup id="rightContainer" layout="block"
styleClass="TreeContainer">
+ <h:outputText escape="false"
+ value="Selected Node:
<b>#{treeDndBean.rightSelectedNodeTitle}</b>"
+ id="selectedNodeR" />
+
+ <rich:tree id="rightTree" style="width:300px"
+ nodeSelectListener="#{treeDndBean.processRSelection}"
+ reRender="selectedNodeR" ajaxSubmitSelection="false"
+ switchType="client" value="#{treeDndBean.treeNodeRight}"
+
+ changeExpandListener="#{treeDndBean.onExpand}"
+ binding="#{treeDndBean.rightTree}"
+ onselected="window.status='selectedNode: '+event.selectedNode;"
+ onexpand="window.status='expandedNode: '+event.expandedNode"
+ oncollapse="window.status='collapsedNode:
'+event.collapsedNode"
+ rowKeyVar="key"
+
+ dropListener="#{treeDndBean.onDrop}"
+ dragListener="#{treeDndBean.onDrag}"
+
+ dragIndicator="treeIndicator"
+ acceptedTypes="treeNode"
+ dragType="treeNode"
+
+ var="item">
+
+ <dnd:dndParam name="treeParam" value="rightTree" />
+ </rich:tree>
+ </h:panelGroup>
+
+ </h:panelGrid>
+ </h:form>
+
+ <a4j:log hotkey="O" />
+
+</f:view>
+</body>
+</html>
Modified:
trunk/ui/drag-drop/src/main/java/org/richfaces/renderkit/DnDEventsExchangeMailer.java
===================================================================
---
trunk/ui/drag-drop/src/main/java/org/richfaces/renderkit/DnDEventsExchangeMailer.java 2008-06-20
14:15:20 UTC (rev 9142)
+++
trunk/ui/drag-drop/src/main/java/org/richfaces/renderkit/DnDEventsExchangeMailer.java 2008-06-20
14:18:44 UTC (rev 9143)
@@ -26,6 +26,7 @@
import java.util.List;
import java.util.Map;
+import javax.faces.component.ContextCallback;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
@@ -82,82 +83,98 @@
}
}
- private MultiHashMap queuedMap = new MultiHashMap();
+ private Map<String, EventInfoStructure> queuedMap = new HashMap<String,
EventInfoStructure>();
- private Map components = new HashMap();
+ private Map<String, UIComponent> components = new HashMap<String,
UIComponent>();
private void processEvent(UIComponent source, FacesContext facesContext, DnDEvent
dndEvent, EventCallback callback, Object type, Object value) {
if (callback != null) {
callback.processEvent(dndEvent, source, facesContext, type, value);
}
}
-
- public void mailEvent(String sourceId, UIComponent target, FacesContext facesContext,
DnDEvent dndEvent,
- EventCallback callback, Object type, Object value, boolean isDraggable) {
+
+ /**
+ * Decode drag & drop events. Collect pairs of correspondent drag & drop events
and send them
+ * together where OnDrag becomes always before OnDrop.
+ *
+ * @param sourceId Id of element event come from
+ * @param target component that receive event
+ * @param facesContext Faces context
+ * @param dndEvent drag & drop event descriptor
+ * @param callback call back method
+ * @param type type of dragged/dropped value
+ * @param value dragged/dropped value
+ * @param isDraggable whether the event related draggable component or dropzone one.
+ */
+ public void mailEvent(String sourceId, UIComponent target, FacesContext facesContext,
final DnDEvent dndEvent,
+ final EventCallback callback, final Object type, final Object value, boolean
isDraggable) {
- //we should queue event right now to preserve row key if its generator
- //is nested in UIData...
- dndEvent.queue();
-
- UIComponent component = (UIComponent) components.get(sourceId);
+ final UIComponent component = components.get(sourceId);
String targetId = target.getClientId(facesContext);
if (component == null) {
//component with that sourceId have never mailed anything before - wait
+ if (queuedMap.containsKey(sourceId)) {
+ throw new IllegalStateException("Drag source with id '" + sourceId +
"' already specified.");
+ }
queuedMap.put(sourceId, new EventInfoStructure(dndEvent, callback, type, value));
components.put(targetId, target);
} else {
//check queued mail lists for current component
- List queue = (List) queuedMap.get(targetId);
- if (queue != null) {
- Iterator iterator = queue.iterator();
- if (iterator.hasNext()) {
- EventInfoStructure eventInfo = (EventInfoStructure) iterator.next();
+ final EventInfoStructure eventInfo = (EventInfoStructure) queuedMap.get(targetId);
+ if (eventInfo != null) {
+ Draggable draggable;
+ Dropzone dropzone;
+
+ final EventInfoStructure dragEventInfo = isDraggable ? eventInfo : new
EventInfoStructure(dndEvent, callback, type, value);
+ final EventInfoStructure dropEventInfo = isDraggable ? new
EventInfoStructure(dndEvent, callback, type, value) : eventInfo;
+
+ Object acceptedTypes;
+ Object dragType;
+
+ if (isDraggable) {
+ draggable = (Draggable) target;
+ dropzone = (Dropzone) component;
- Draggable draggable;
- Dropzone dropzone;
+ acceptedTypes = eventInfo.type;
+ dragType = type;
+ } else {
+ draggable = (Draggable) component;
+ dropzone = (Dropzone) target;
- Object acceptedTypes;
- Object dragType;
+ acceptedTypes = type;
+ dragType = eventInfo.type;
+ }
- if (isDraggable) {
- draggable = (Draggable) target;
- dropzone = (Dropzone) component;
-
- acceptedTypes = eventInfo.type;
- dragType = type;
- } else {
- draggable = (Draggable) component;
- dropzone = (Dropzone) target;
-
- acceptedTypes = type;
- dragType = eventInfo.type;
- }
-
- if (DnDValidator.validateAcceptTypes(facesContext,
- draggable, dropzone,
- dragType, acceptedTypes)) {
-
-
- processEvent(target, facesContext, eventInfo.dndEvent, eventInfo.eventCallback,
- type, value);
-
- //we know the component - process event now
- processEvent(component, facesContext, dndEvent, callback,
- eventInfo.type, eventInfo.value);
-
- } else {
- dndEvent.invalidate();
-
- eventInfo.dndEvent.invalidate();
- }
+ if (DnDValidator.validateAcceptTypes(facesContext,
+ draggable, dropzone,
+ dragType, acceptedTypes)) {
- iterator.remove();
+ // Make sure that we will have OnDrag event occur first
+ facesContext.getViewRoot().invokeOnComponent(facesContext, isDraggable ? targetId :
sourceId, new ContextCallback() {
+ public void invokeContextCallback(FacesContext fc,
+ UIComponent targetComponent) {
+
+ processEvent(targetComponent, fc, dragEventInfo.dndEvent,
dragEventInfo.eventCallback,
+ dropEventInfo.type, dropEventInfo.value);
+
+ dropEventInfo.dndEvent.queue();
+ }
+ });
+
+ facesContext.getViewRoot().invokeOnComponent(facesContext, isDraggable ? sourceId :
targetId, new ContextCallback() {
+ public void invokeContextCallback(FacesContext fc,
+ UIComponent targetComponent) {
+
+ processEvent(targetComponent, fc, dropEventInfo.dndEvent,
dropEventInfo.eventCallback,
+ dragEventInfo.type, dragEventInfo.value);
+
+ dragEventInfo.dndEvent.queue();
+ }
+ });
}
-
- if (!iterator.hasNext()) {
- queuedMap.remove(targetId);
- }
+
+ queuedMap.remove(targetId);
}
}
}
Modified: trunk/ui/tree/src/main/java/org/richfaces/component/UITree.java
===================================================================
--- trunk/ui/tree/src/main/java/org/richfaces/component/UITree.java 2008-06-20 14:15:20
UTC (rev 9142)
+++ trunk/ui/tree/src/main/java/org/richfaces/component/UITree.java 2008-06-20 14:18:44
UTC (rev 9143)
@@ -22,10 +22,13 @@
package org.richfaces.component;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
+import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -58,9 +61,7 @@
import org.richfaces.component.state.events.ExpandAllCommandEvent;
import org.richfaces.component.state.events.ExpandNodeCommandEvent;
import org.richfaces.component.state.events.TreeStateCommandEvent;
-import org.richfaces.event.DragEvent;
import org.richfaces.event.DragListener;
-import org.richfaces.event.DropEvent;
import org.richfaces.event.DropListener;
import org.richfaces.event.NodeExpandedEvent;
import org.richfaces.event.NodeExpandedListener;
@@ -234,12 +235,6 @@
} else {
event.setPhaseId(PhaseId.INVOKE_APPLICATION);
}
- } else if (event instanceof DragEvent || event instanceof DropEvent) {
- if (isImmediate()) {
- event.setPhaseId(PhaseId.APPLY_REQUEST_VALUES);
- } else {
- event.setPhaseId(PhaseId.INVOKE_APPLICATION);
- }
}
super.queueEvent(resultEvent);
@@ -1015,6 +1010,202 @@
public void setRowKeyConverter(Converter rowKeyConverter) {
throw new UnsupportedOperationException();
}
+
+ /**
+ * Return row key for certain model's tree node
+ *
+ * @return row key
+ */
+ public Object getTreeNodeRowKey(TreeNode node) {
+ return ((AbstractTreeDataModel) getExtendedDataModel()).getTreeNodeRowKey(node);
+ }
+
+ /**
+ * Collect current tree node state including node selection and expanded nodes list
+ *
+ * @param transferQueuedNodes whether to collect queued expanded nodes states or not
+ * @return tree node state
+ */
+ public Object getTreeNodeState(boolean transferQueuedNodes) {
+ // Check for node were choosed
+ TreeRowKey rowKey = (TreeRowKey) getRowKey();
+ if (rowKey == null) {
+ return null;
+ }
+ TreeState state = (TreeState) getComponentState();
+ if (transferQueuedNodes) {
+ state.transferQueuedNodes();
+ }
+ TreeState subTreeState = (TreeState) createComponentState();
+ if (state.getSelectedNode() != null && rowKey.equals(state.getSelectedNode()))
{
+ subTreeState.setSelected(rowKey);
+ }
+
+ Set subNodes = subTreeState.getExpandedNodes();
+ Set nodes = state.getExpandedNodes();
+ Iterator iter = nodes.iterator();
+ while (iter != null && iter.hasNext()) {
+ ListRowKey key = (ListRowKey) iter.next();
+ if (key != null && (rowKey.isSubKey(key) || rowKey.equals(key))) {
+ subNodes.add(key.getSubKey(rowKey.depth() - 1));
+ }
+ }
+ return subTreeState;
+ }
+
+ /**
+ * Set current tree node state.
+ *
+ * @param state node state to apply.
+ */
+ public void setTreeNodeState(Object state) {
+ // Check for node were choosed
+ ListRowKey rowKey = (ListRowKey) getRowKey();
+ if (rowKey == null) {
+ return;
+ }
+
+ TreeState currentState = (TreeState) getComponentState();
+ Set currentNodes = currentState.getExpandedNodes();
+
+ if (state instanceof TreeState) {
+ Set nodes = ((TreeState) state).getExpandedNodes();
+ Iterator iter = nodes.iterator();
+ while (iter != null && iter.hasNext()) {
+ ListRowKey key = ((ListRowKey) iter.next()).getSubKey(1);
+ if (key.depth() > 0) {
+ currentNodes.add(new ListRowKey(rowKey, key));
+ } else if (!currentNodes.contains(rowKey)) {
+ currentNodes.add(rowKey);
+ }
+ }
+ }
+ }
+
+ /**
+ * Cleanup current tree node state information.
+ */
+ public void clearTreeNodeState() {
+ TreeRowKey rowKey = (TreeRowKey) getRowKey();
+ if (rowKey == null) {
+ return;
+ }
+ TreeState state = (TreeState) getComponentState();
+ state.transferQueuedNodes();
+ Set nodes = state.getExpandedNodes();
+
+ if (rowKey.equals(state.getSelectedNode())) {
+ state.setSelected(null);
+ }
+
+ // collect nodes to clean up
+ List<TreeRowKey> nodesForRemove = new ArrayList<TreeRowKey>();
+ Iterator iter = nodes.iterator();
+ while (iter != null && iter.hasNext()) {
+ TreeRowKey key = (TreeRowKey) iter.next();
+ if (key != null && (rowKey.getPath().equals("null")
+ || rowKey.isSubKey(key)
+ || rowKey.equals(key))) {
+ nodesForRemove.add(key);
+ }
+ }
+
+ // remove states
+ for (TreeRowKey key : nodesForRemove) {
+ nodes.remove(key);
+ }
+ }
+
+ /**
+ * Remove node from tree
+ *
+ * @param context JSF context
+ * @param node Node to remove
+ * @return removed node state description
+ */
+ public Object removeNode(FacesContext context, Object rowKey) {
+ Object nodeState = null;
+ if (rowKey != null) {
+ Object storedKey = getRowKey();
+ try {
+ setRowKey(context, rowKey);
+ TreeNode node = getTreeNode();
+ TreeNode parentNode = node.getParent();
+
+ // 1. remove node from data model
+ Object id = ((AbstractTreeDataModel) getExtendedDataModel()).getChildNodeId(node);
+ parentNode.removeChild(id);
+
+ // 2. clean up node state
+ nodeState = getTreeNodeState(true);
+ clearTreeNodeState();
+ } finally {
+ try {
+ setRowKey(context, storedKey);
+ } catch (Exception e) {
+ context.getExternalContext().log(e.getMessage(), e);
+ nodeState = null;
+ }
+ }
+ }
+
+ return nodeState;
+ }
+
+ /**
+ * Remove node from tree
+ *
+ * @param node Node to remove
+ * @return removed node state
+ */
+ public Object removeNode(Object rowKey) {
+ return removeNode(getFacesContext(), rowKey);
+ }
+
+ /**
+ * Add node to tree
+ *
+ * @param context JSF context
+ * @param parentRowKey parent node row key
+ * @param newNode inserted node
+ * @param id inserted node parent's local identifier
+ * @param state inserted tree node state. Optional
+ */
+ public void addNode(FacesContext context, Object parentRowKey, TreeNode newNode, Object
id, Object state) {
+ if (newNode != null) {
+ Object storedKey = getRowKey();
+ try {
+ setRowKey(context, parentRowKey);
+ TreeNode parentNode = getTreeNode();
+
+ parentNode.addChild(id, newNode);
+
+ // select new node as current
+ setRowKey(getTreeNodeRowKey(newNode));
+ if (state != null) {
+ setTreeNodeState(state);
+ }
+ } finally {
+ try {
+ setRowKey(context, storedKey);
+ } catch (Exception e) {
+ context.getExternalContext().log(e.getMessage(), e);
+ }
+ }
+ }
+ }
+
+ /**
+ * Add node to tree
+ *
+ * @param parentRowKey parent node row key
+ * @param newNode inserted node
+ * @param id inserted node parent's local identifier
+ * @param state inserted tree node state. Optional
+ */
+ public void addNode(Object parentRowKey, TreeNode draggedNode, Object id, Object state)
{
+ addNode(getFacesContext(), parentRowKey, draggedNode, id, state);
+ }
}
Modified: trunk/ui/tree/src/main/java/org/richfaces/component/UITreeNode.java
===================================================================
--- trunk/ui/tree/src/main/java/org/richfaces/component/UITreeNode.java 2008-06-20
14:15:20 UTC (rev 9142)
+++ trunk/ui/tree/src/main/java/org/richfaces/component/UITreeNode.java 2008-06-20
14:18:44 UTC (rev 9143)
@@ -7,10 +7,13 @@
import javax.faces.component.UIComponent;
import javax.faces.component.UIComponentBase;
+import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.faces.el.ValueBinding;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.FacesEvent;
+import javax.faces.event.FacesListener;
+import javax.faces.event.PhaseId;
import org.ajax4jsf.component.AjaxComponent;
import org.ajax4jsf.event.AjaxEvent;
@@ -132,10 +135,11 @@
TreeEvents.invokeListenerBindings(this, event, context);
//TODO quick fix for UITree to invoke listeners
- if (tree != null) {
- if (event instanceof DragEvent || event instanceof DropEvent) {
- tree.broadcast(event);
- }
+
+ if (tree != null && (event instanceof DragEvent || event instanceof DropEvent))
{
+ tree.broadcast(event);
+ } else if (event instanceof DnDEventWrapper) {
+ event.queue();
}
if (event instanceof AjaxEvent) {
@@ -143,6 +147,39 @@
}
}
+ /**
+ * <p>
+ * Queue an event for broadcast at the end of the current request
+ * processing lifecycle phase. The default implementation in
+ * {@link UIComponentBase} must delegate this call to the
+ * <code>queueEvent()</code> method of the parent {@link UIComponent}.
+ * </p>
+ *
+ * @param event {@link FacesEvent} to be queued
+ *
+ * @throws IllegalStateException if this component is not a descendant of a {@link
UIViewRoot}
+ * @throws NullPointerException if <code>event</code> is
<code>null</code>
+ */
+ @Override
+ public void queueEvent(FacesEvent event) {
+ FacesEvent resultEvent = event;
+
+ UITree tree = getUITree();
+ if (tree != null && (event instanceof DragEvent || event instanceof DropEvent))
{
+ if (tree.isImmediate()) {
+ event.setPhaseId(PhaseId.APPLY_REQUEST_VALUES);
+ } else {
+ event.setPhaseId(PhaseId.INVOKE_APPLICATION);
+ }
+
+ resultEvent = new DnDEventWrapper(this, event, tree.getRowKey());
+ } else if (event instanceof DnDEventWrapper) {
+ resultEvent = ((DnDEventWrapper) event).getTarget();
+ }
+
+ super.queueEvent(resultEvent);
+ }
+
public void addChangeExpandListener(NodeExpandedListener listener) {
addFacesListener(listener);
}
@@ -879,4 +916,97 @@
return (this.timeout);
}
}
+
+ /**
+ * Helper inner class used to wrap drag and drop events to suspend them to ensure
+ * that events will processed last.
+ *
+ * Note: We should ensure that all drag & drop events will be processed after all
other events
+ * to avoid problems with removed while drop operation tree nodes and their event
handlers.
+ *
+ * @author dmorozov
+ */
+ protected static final class DnDEventWrapper extends FacesEvent {
+
+ private static final long serialVersionUID = -5479811879939203868L;
+
+ private final FacesEvent target;
+
+ private Object key;
+
+ /**
+ * Construct a new event object that wrap original event and store target node row key
+ * to be processed in future.
+ *
+ * @param owner event owner component
+ * @param target wrapped event
+ * @param key target tree node row key
+ */
+ public DnDEventWrapper(UIComponent owner, FacesEvent target, Object key) {
+ super(owner);
+ this.target = target;
+ this.key = key;
+ if (this.target == null) {
+ throw new NullPointerException();
+ }
+ }
+
+ /**
+ * <p>
+ * Return the identifier of the request processing phase during which
+ * this event should be delivered.
+ * </p>
+ */
+ public PhaseId getPhaseId() {
+ return target.getPhaseId();
+ }
+
+ /**
+ * <p> Set the {@link PhaseId} during which this event will be
delivered.</p>
+ * @throws IllegalArgumentException phaseId is null.
+ */
+ public void setPhaseId(PhaseId phaseId) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Get wrapped event
+ * @return wrapped event
+ */
+ public FacesEvent getTarget() {
+ return target;
+ }
+
+ /* (non-Javadoc)
+ * @see
javax.faces.event.FacesEvent#isAppropriateListener(javax.faces.event.FacesListener)
+ */
+ @Override
+ public boolean isAppropriateListener(FacesListener listener) {
+ return false;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.faces.event.FacesEvent#processListener(javax.faces.event.FacesListener)
+ */
+ @Override
+ public void processListener(FacesListener listener) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Get target component row key
+ * @return the row key
+ */
+ public Object getKey() {
+ return key;
+ }
+
+ /**
+ * Set target component row key
+ * @param key the row key to set
+ */
+ public void setKey(Object key) {
+ this.key = key;
+ }
+ }
}
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 2008-06-20
14:15:20 UTC (rev 9142)
+++ trunk/ui/tree/src/main/java/org/richfaces/component/state/TreeState.java 2008-06-20
14:18:44 UTC (rev 9143)
@@ -24,6 +24,7 @@
import java.io.IOException;
import java.io.Serializable;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.Set;
import javax.faces.application.FacesMessage;
@@ -280,5 +281,13 @@
expandedNodes.removeAll(queuedCollapsedNodes);
queuedCollapsedNodes.clear();
}
+
+ /**
+ * Get list of expanded tree nodes
+ * @return list of expanded tree nodes
+ */
+ public Set getExpandedNodes() {
+ return expandedNodes;
+ }
}
Modified: trunk/ui/tree/src/main/java/org/richfaces/renderkit/NodeRendererBase.java
===================================================================
--- trunk/ui/tree/src/main/java/org/richfaces/renderkit/NodeRendererBase.java 2008-06-20
14:15:20 UTC (rev 9142)
+++ trunk/ui/tree/src/main/java/org/richfaces/renderkit/NodeRendererBase.java 2008-06-20
14:18:44 UTC (rev 9143)
@@ -224,8 +224,6 @@
}
protected void doDecode(FacesContext context, UIComponent component) {
- super.doDecode(context, component);
-
UITreeNode node = (UITreeNode) component;
UITree tree = node.getUITree();
TreeRowKey key = (TreeRowKey) tree.getRowKey();
@@ -271,6 +269,8 @@
tree.getAttributes().remove(UITree.SELECTION_INPUT_ATTRIBUTE);
}
+
+ super.doDecode(context, component);
}
public String getAjaxSelectedListenerFlag(FacesContext context,