Author: dmorozov
Date: 2008-07-16 11:48:07 -0400 (Wed, 16 Jul 2008)
New Revision: 9640
Modified:
trunk/framework/api/src/main/java/org/richfaces/model/AbstractTreeDataModel.java
trunk/framework/api/src/main/java/org/richfaces/model/CacheableTreeDataModel.java
trunk/framework/api/src/main/java/org/richfaces/model/ClassicCacheableTreeDataModel.java
trunk/framework/api/src/main/java/org/richfaces/model/ClassicTreeDataModel.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/TreeRowKey.java
trunk/test-applications/jsp/src/main/java/tree/TreeDndBean.java
trunk/ui/tree/src/main/java/org/richfaces/component/UITree.java
trunk/ui/tree/src/main/java/org/richfaces/component/state/TreeState.java
Log:
https://jira.jboss.com/jira/browse/RF-3838
Modified:
trunk/framework/api/src/main/java/org/richfaces/model/AbstractTreeDataModel.java
===================================================================
---
trunk/framework/api/src/main/java/org/richfaces/model/AbstractTreeDataModel.java 2008-07-16
14:04:27 UTC (rev 9639)
+++
trunk/framework/api/src/main/java/org/richfaces/model/AbstractTreeDataModel.java 2008-07-16
15:48:07 UTC (rev 9640)
@@ -124,6 +124,16 @@
* @return current tree node
*/
public abstract TreeNode getTreeNode();
+
+ /**
+ * Get model node recursively with all sub nodes.
+ * Note: valid only for classical TreeNode based tree data model implementation
+ *
+ * @return current tree node
+ */
+ public TreeNode getModelTreeNode() {
+ return getTreeNode();
+ }
public abstract Object convertToKey(FacesContext context, String keyString,
UIComponent component, Converter converter);
@@ -151,4 +161,12 @@
public Object getParentRowKey(Object key) {
return ((TreeRowKey) key).getParentKey();
}
+
+ public void addNode(Object parentRowKey, TreeNode newNode, Object id) {
+ throw new UnsupportedOperationException();
+ }
+
+ public void removeNode(Object rowKey) {
+ throw new UnsupportedOperationException();
+ }
}
Modified:
trunk/framework/api/src/main/java/org/richfaces/model/CacheableTreeDataModel.java
===================================================================
---
trunk/framework/api/src/main/java/org/richfaces/model/CacheableTreeDataModel.java 2008-07-16
14:04:27 UTC (rev 9639)
+++
trunk/framework/api/src/main/java/org/richfaces/model/CacheableTreeDataModel.java 2008-07-16
15:48:07 UTC (rev 9640)
@@ -29,6 +29,8 @@
import org.ajax4jsf.model.DataVisitor;
import org.ajax4jsf.model.Range;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
/**
* Extension of {@link TreeDataModel} supporting lazy data fetching for caching
@@ -38,7 +40,9 @@
* @author Nick - mailto:nbelaevski@exadel.com
*/
public abstract class CacheableTreeDataModel<T> extends TreeDataModel<T> {
-
+
+ private Log log = LogFactory.getLog(CacheableTreeDataModel.class);
+
private final class Visitor implements DataVisitor, LastElementAware {
private final DataVisitor visitor;
@@ -177,4 +181,65 @@
public T locateTreeNode(TreeRowKey rowKey) {
return locateTreeNode(rowKey, true);
}
+
+ @Override
+ public void addNode(Object parentRowKey, TreeNode newNode, Object id) {
+ super.addNode(parentRowKey, newNode, id);
+
+ if (treeDataModel != null) {
+ Object savedRowKey = treeDataModel.getRowKey();
+
+ try {
+ treeDataModel.setRowKey(getRowKey());
+ treeDataModel.addNode(parentRowKey, newNode, id);
+ } finally {
+ try {
+ treeDataModel.setRowKey(savedRowKey);
+ } catch (Exception e) {
+ log.error(e.getMessage(), e);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void removeNode(Object rowKey) {
+ super.removeNode(rowKey);
+
+ if (treeDataModel != null) {
+ Object savedRowKey = treeDataModel.getRowKey();
+
+ try {
+ treeDataModel.setRowKey(getRowKey());
+ treeDataModel.removeNode(rowKey);
+ } finally {
+ try {
+ treeDataModel.setRowKey(savedRowKey);
+ } catch (Exception e) {
+ log.error(e.getMessage(), e);
+ }
+ }
+ }
+ }
+
+ @Override
+ public TreeNode getModelTreeNode() {
+ TreeNode node = null;
+ if (treeDataModel != null) {
+ Object savedRowKey = treeDataModel.getRowKey();
+
+ try {
+ treeDataModel.setRowKey(getRowKey());
+ node = treeDataModel.getModelTreeNode();
+ } finally {
+ try {
+ treeDataModel.setRowKey(savedRowKey);
+ } catch (Exception e) {
+ log.error(e.getMessage(), e);
+ }
+ }
+ }
+
+ return node;
+ }
}
Modified:
trunk/framework/api/src/main/java/org/richfaces/model/ClassicCacheableTreeDataModel.java
===================================================================
---
trunk/framework/api/src/main/java/org/richfaces/model/ClassicCacheableTreeDataModel.java 2008-07-16
14:04:27 UTC (rev 9639)
+++
trunk/framework/api/src/main/java/org/richfaces/model/ClassicCacheableTreeDataModel.java 2008-07-16
15:48:07 UTC (rev 9640)
@@ -59,4 +59,13 @@
}
}
+ @Override
+ public TreeNode getTreeNode() {
+ if (isRowAvailable()) {
+ return locateTreeNode((TreeRowKey) getRowKey());
+ }
+
+ throw new IllegalStateException(
+ "No tree element available or row key not set!");
+ }
}
Modified: trunk/framework/api/src/main/java/org/richfaces/model/ClassicTreeDataModel.java
===================================================================
---
trunk/framework/api/src/main/java/org/richfaces/model/ClassicTreeDataModel.java 2008-07-16
14:04:27 UTC (rev 9639)
+++
trunk/framework/api/src/main/java/org/richfaces/model/ClassicTreeDataModel.java 2008-07-16
15:48:07 UTC (rev 9640)
@@ -45,6 +45,7 @@
super(TreeNode.class, TreeDataModelNodeAdaptor.classicTreeNodeAdaptor, null);
}
+ @Override
public TreeNode getTreeNode() {
if (isRowAvailable()) {
return locateTreeNode((TreeRowKey) getRowKey());
Modified: trunk/framework/api/src/main/java/org/richfaces/model/ListRowKey.java
===================================================================
--- trunk/framework/api/src/main/java/org/richfaces/model/ListRowKey.java 2008-07-16
14:04:27 UTC (rev 9639)
+++ trunk/framework/api/src/main/java/org/richfaces/model/ListRowKey.java 2008-07-16
15:48:07 UTC (rev 9640)
@@ -151,7 +151,8 @@
return path.listIterator(fromIndex);
}
- public ListRowKey<T> getSubKey(int fromIndex) {
+ @Override
+ public TreeRowKey<T> getSubKey(int fromIndex) {
return new ListRowKey<T>(path.subList(fromIndex, path.size()));
}
Modified: trunk/framework/api/src/main/java/org/richfaces/model/TreeDataModel.java
===================================================================
--- trunk/framework/api/src/main/java/org/richfaces/model/TreeDataModel.java 2008-07-16
14:04:27 UTC (rev 9639)
+++ trunk/framework/api/src/main/java/org/richfaces/model/TreeDataModel.java 2008-07-16
15:48:07 UTC (rev 9640)
@@ -366,4 +366,25 @@
public Object getChildNodeId(Object childNode) {
return getNodeAdaptor().getChildNodeId((T) childNode);
}
+
+ @Override
+ public void addNode(Object parentRowKey, TreeNode newNode, Object id) {
+ TreeNode parentNode = (parentRowKey != null) ? getTreeNode() : (TreeNode)
getWrappedData();
+ if (parentNode == null) {
+ throw new IllegalArgumentException("Parent node required!");
+ }
+
+ parentNode.addChild(id, newNode);
+ }
+
+ @Override
+ public void removeNode(Object rowKey) {
+ TreeNode node = getTreeNode();
+ TreeNode parentNode = node.getParent();
+
+ // 1. remove node from data model
+ Object id = getChildNodeId(node);
+ parentNode.removeChild(id);
+ }
+
}
Modified: trunk/framework/api/src/main/java/org/richfaces/model/TreeRowKey.java
===================================================================
--- trunk/framework/api/src/main/java/org/richfaces/model/TreeRowKey.java 2008-07-16
14:04:27 UTC (rev 9639)
+++ trunk/framework/api/src/main/java/org/richfaces/model/TreeRowKey.java 2008-07-16
15:48:07 UTC (rev 9640)
@@ -89,4 +89,7 @@
public abstract TreeRowKey<T> getParentKey();
+ public TreeRowKey<T> getSubKey(int fromIndex) {
+ throw new UnsupportedOperationException();
+ }
}
Modified: trunk/test-applications/jsp/src/main/java/tree/TreeDndBean.java
===================================================================
--- trunk/test-applications/jsp/src/main/java/tree/TreeDndBean.java 2008-07-16 14:04:27
UTC (rev 9639)
+++ trunk/test-applications/jsp/src/main/java/tree/TreeDndBean.java 2008-07-16 15:48:07
UTC (rev 9640)
@@ -295,7 +295,7 @@
Object state = null;
TreeNode draggedNode = null;
if (dragNodeKey != null) { // Drag from this or other tree
- draggedNode = srcTree.getTreeNode(dragNodeKey);
+ draggedNode = srcTree.getModelTreeNode(dragNodeKey);
TreeNode parentNode = draggedNode.getParent();
// 1. remove node from tree
Modified: trunk/ui/tree/src/main/java/org/richfaces/component/UITree.java
===================================================================
--- trunk/ui/tree/src/main/java/org/richfaces/component/UITree.java 2008-07-16 14:04:27
UTC (rev 9639)
+++ trunk/ui/tree/src/main/java/org/richfaces/component/UITree.java 2008-07-16 15:48:07
UTC (rev 9640)
@@ -22,13 +22,10 @@
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;
@@ -192,6 +189,25 @@
return ((AbstractTreeDataModel) getExtendedDataModel()).getTreeNode();
}
+ public TreeNode getModelTreeNode() {
+ return ((AbstractTreeDataModel) getExtendedDataModel()).getModelTreeNode();
+ }
+
+ public TreeNode getModelTreeNode(Object rowKey) {
+ FacesContext context = this.getFacesContext();
+ Object storedKey = getRowKey();
+ try {
+ setRowKey(context, rowKey);
+ return getModelTreeNode();
+ } finally {
+ try {
+ setRowKey(context, storedKey);
+ } catch (Exception e) {
+ context.getExternalContext().log(e.getMessage(), e);
+ }
+ }
+ }
+
public abstract boolean isImmediate();
public abstract void setImmediate(boolean immediate);
@@ -861,11 +877,10 @@
* @return {@link TreeNode} instance corresponding to the current row key
*/
public TreeNode getTreeNode(Object rowKey) {
- FacesContext context = FacesContext.getCurrentInstance();
+ FacesContext context = this.getFacesContext();
Object storedKey = getRowKey();
try {
setRowKey(context, rowKey);
-
return getTreeNode();
} finally {
try {
@@ -1025,31 +1040,14 @@
* @param transferQueuedNodes whether to collect queued expanded nodes states or not
* @return tree node state
*/
- public Object getTreeNodeState(boolean transferQueuedNodes) {
+ public Object getTreeNodeState() {
// 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;
+ return state.getSubState(rowKey);
}
/**
@@ -1059,25 +1057,14 @@
*/
public void setTreeNodeState(Object state) {
// Check for node were choosed
- ListRowKey rowKey = (ListRowKey) getRowKey();
+ TreeRowKey rowKey = (TreeRowKey) 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);
- }
- }
+ TreeState currentState = (TreeState) getComponentState();
+ currentState.mergeSubState(rowKey, (TreeState) state);
}
}
@@ -1089,30 +1076,9 @@
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);
- }
+ TreeState state = (TreeState) getComponentState();
+ state.clearSubState(rowKey);
}
/**
@@ -1128,15 +1094,12 @@
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);
+ // remove node from data model
+ ((AbstractTreeDataModel) getExtendedDataModel()).removeNode(rowKey);
- // 2. clean up node state
- nodeState = getTreeNodeState(true);
+ // clean up node state
+ nodeState = getTreeNodeState();
clearTreeNodeState();
setRowKey(null);
} finally {
@@ -1176,20 +1139,17 @@
Object storedKey = getRowKey();
try {
setRowKey(context, parentRowKey);
- TreeNode parentNode = (parentRowKey != null) ?
- getTreeNode() : (TreeNode) getExtendedDataModel().getWrappedData();
- if (parentNode == null) {
- throw new IllegalArgumentException("Parent node required!");
- }
-
- parentNode.addChild(id, newNode);
-
+ // add node in data model
+ ((AbstractTreeDataModel) getExtendedDataModel()).addNode(parentRowKey, newNode, id);
+
// select new node as current
- setRowKey(getTreeNodeRowKey(newNode));
+ setRowKey(getTreeNodeRowKey(newNode));
+
+ // set node state if specified
if (state != null) {
setTreeNodeState(state);
- }
+ }
} finally {
try {
setRowKey(context, storedKey);
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-07-16
14:04:27 UTC (rev 9639)
+++ trunk/ui/tree/src/main/java/org/richfaces/component/state/TreeState.java 2008-07-16
15:48:07 UTC (rev 9640)
@@ -23,8 +23,10 @@
import java.io.IOException;
import java.io.Serializable;
+import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.List;
import java.util.Set;
import javax.faces.application.FacesMessage;
@@ -36,6 +38,7 @@
import org.ajax4jsf.model.Range;
import org.richfaces.component.UITree;
import org.richfaces.component.state.events.TreeStateCommandsListener;
+import org.richfaces.model.ListRowKey;
import org.richfaces.model.TreeRange;
import org.richfaces.model.TreeRowKey;
@@ -281,13 +284,107 @@
expandedNodes.removeAll(queuedCollapsedNodes);
queuedCollapsedNodes.clear();
}
+
+ private List<TreeRowKey> getAllSubKeys(Set nodes, TreeRowKey parent) {
+ List<TreeRowKey> keys = new ArrayList<TreeRowKey>();
+ Iterator<TreeRowKey> iter = nodes.iterator();
+ while (iter != null && iter.hasNext()) {
+ TreeRowKey key = iter.next();
+ if (key != null && (parent.isSubKey(key) || parent.equals(key))) {
+ keys.add(key);
+ }
+ }
+
+ return keys;
+ }
- /**
- * Get list of expanded tree nodes
- * @return list of expanded tree nodes
- */
- public Set getExpandedNodes() {
- return expandedNodes;
+ public TreeState getSubState(TreeRowKey rowKey) {
+ TreeState subTreeState = new TreeState(this.stopInCollapsed);
+ if (getSelectedNode() != null && rowKey.equals(getSelectedNode())) {
+ subTreeState.setSelected(rowKey);
+ }
+ // FIXME: whether it is needed?
+ subTreeState._transient = _transient;
+
+ List<TreeRowKey> nodes = getAllSubKeys(this.expandedNodes, rowKey);
+ Iterator<TreeRowKey> iter = nodes != null ? nodes.iterator() : null;
+ while (iter != null && iter.hasNext()) {
+ subTreeState.expandedNodes.add(iter.next().getSubKey(rowKey.depth() - 1));
+ }
+
+ nodes = getAllSubKeys(this.queuedExpandedNodes, rowKey);
+ iter = nodes != null ? nodes.iterator() : null;
+ while (iter != null && iter.hasNext()) {
+ subTreeState.queuedExpandedNodes.add(iter.next().getSubKey(rowKey.depth() - 1));
+ }
+
+ nodes = getAllSubKeys(this.queuedCollapsedNodes, rowKey);
+ iter = nodes != null ? nodes.iterator() : null;
+ while (iter != null && iter.hasNext()) {
+ subTreeState.queuedCollapsedNodes.add(iter.next().getSubKey(rowKey.depth() - 1));
+ }
+
+ return subTreeState;
}
+
+ public void clearSubState(TreeRowKey rowKey) {
+ if (rowKey.equals(getSelectedNode())) {
+ setSelected(null);
+ }
+ if (rowKey.getPath().equals("null")) { // root node
+ this.expandedNodes.clear();
+ this.queuedCollapsedNodes.clear();
+ this.queuedExpandedNodes.clear();
+ } else {
+ // collect nodes to clean up
+ List<TreeRowKey> nodes = getAllSubKeys(this.expandedNodes,
rowKey);
+ Iterator<TreeRowKey> iter = nodes != null ?
nodes.iterator() : null;
+ while (iter != null && iter.hasNext()) {
+ this.expandedNodes.remove(iter.next());
+ }
+
+ nodes = getAllSubKeys(this.queuedExpandedNodes, rowKey);
+ iter = nodes != null ? nodes.iterator() : null;
+ while (iter != null && iter.hasNext()) {
+ this.queuedExpandedNodes.remove(iter.next());
+ }
+
+ nodes = getAllSubKeys(this.queuedCollapsedNodes, rowKey);
+ iter = nodes != null ? nodes.iterator() : null;
+ while (iter != null && iter.hasNext()) {
+ this.queuedCollapsedNodes.remove(iter.next());
+ }
+ }
+ }
+
+ public void mergeSubState(TreeRowKey rowKey, TreeState subState) {
+ Iterator<TreeRowKey> iter = subState.expandedNodes.iterator();
+ while (iter != null && iter.hasNext()) {
+ TreeRowKey key = iter.next().getSubKey(1);
+ if (key.depth() > 0) {
+ expandedNodes.add(new ListRowKey((ListRowKey)rowKey, (ListRowKey)key));
+ } else if (!expandedNodes.contains(rowKey)) {
+ expandedNodes.add(rowKey);
+ }
+ }
+ iter = subState.queuedExpandedNodes.iterator();
+ while (iter != null && iter.hasNext()) {
+ TreeRowKey key = iter.next().getSubKey(1);
+ if (key.depth() > 0) {
+ queuedExpandedNodes.add(new ListRowKey((ListRowKey)rowKey, (ListRowKey)key));
+ } else if (!queuedExpandedNodes.contains(rowKey)) {
+ queuedExpandedNodes.add(rowKey);
+ }
+ }
+ iter = subState.queuedCollapsedNodes.iterator();
+ while (iter != null && iter.hasNext()) {
+ TreeRowKey key = iter.next().getSubKey(1);
+ if (key.depth() > 0) {
+ queuedCollapsedNodes.add(new ListRowKey((ListRowKey)rowKey, (ListRowKey)key));
+ } else if (!queuedCollapsedNodes.contains(rowKey)) {
+ queuedCollapsedNodes.add(rowKey);
+ }
+ }
+ }
}