/**
* License Agreement.
*
* JBoss RichFaces - Ajax4jsf Component Library
*
* 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.state;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import javax.faces.application.FacesMessage;
import javax.faces.component.StateHolder;
import javax.faces.context.FacesContext;
import org.ajax4jsf.model.DataComponentState;
import org.ajax4jsf.model.DataVisitor;
import org.ajax4jsf.model.Range;
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@exadel.com created 23.11.2006
*
*/
public class TreeState implements DataComponentState, TreeStateCommandsListener, StateHolder {
private final class Visitor implements DataVisitor {
private TreeRowKey key;
private UITree tree;
public Visitor(TreeRowKey key, UITree tree) {
super();
this.key = key;
this.tree = tree;
}
public void process(FacesContext context, Object rowKey, Object argument)
throws IOException {
tree.setRowKey(context, rowKey);
if (tree.isRowAvailable()) {
TreeRowKey nextKey = (TreeRowKey) rowKey;
if (!tree.isLeaf() && nextKey != null) {
if (key == null || nextKey.isSubKey(key)
|| nextKey.equals(key)) {
if (tree.isImmediate()) {
queuedExpandedNodes.add(nextKey);
} else {
expandedNodes.add(nextKey);
}
queuedCollapsedNodes.remove(nextKey);
}
}
} else {
FacesMessage message = new FacesMessage("Row key: " + rowKey
+ " isn't available!");
message.setSeverity(FacesMessage.SEVERITY_ERROR);
context.addMessage(tree.getBaseClientId(context), message);
}
}
}
private final static TreeRange RANGE_UNCONSTRAINED = new TreeRange() {
public boolean processChildren(TreeRowKey rowKey) {
return true;
}
public boolean processNode(TreeRowKey rowKey) {
return true;
}
};
private boolean stopInCollapsed = false;
private TreeRowKey selectedNode = null;
private Set expandedNodes = new HashSet();
private Set queuedExpandedNodes = new HashSet();
private Set queuedCollapsedNodes = new HashSet();
public TreeState(boolean stopInCollapsed) {
super();
this.stopInCollapsed = stopInCollapsed;
}
public boolean isExpanded(TreeRowKey rowKey) {
if (rowKey == null) {
return true;
}
return expandedNodes.contains(rowKey)
|| queuedExpandedNodes.contains(rowKey);
}
public boolean isSelected(TreeRowKey rowKey) {
return (rowKey == null && selectedNode == null) || (selectedNode != null && selectedNode.equals(rowKey));
}
public TreeRowKey getSelectedNode() {
return selectedNode;
}
public void setSelected(TreeRowKey rowKey) {
selectedNode = rowKey;
}
private boolean _transient;
private transient TreeRange treeRange = null;
public Range getRange() {
if (treeRange != null) {
return treeRange;
}
if (stopInCollapsed) {
return new TreeRange() {
public boolean processChildren(TreeRowKey rowKey) {
if (rowKey == null) {
return true;
}
return expandedNodes.contains(rowKey);
}
public boolean processNode(TreeRowKey rowKey) {
return true;
}
};
} else {
return RANGE_UNCONSTRAINED;
}
}
public boolean isTransient() {
return _transient;
}
public void restoreState(FacesContext context, Object state) {
Object[] _state = (Object[]) state;
expandedNodes = (Set) _state[0];
_transient = ((Boolean) _state[1]).booleanValue();
stopInCollapsed = ((Boolean) _state[2]).booleanValue();
selectedNode = (TreeRowKey) _state[3];
queuedExpandedNodes = (Set) _state[4];
queuedCollapsedNodes = (Set) _state[5];
}
public Object saveState(FacesContext context) {
Object[] state = new Object[6];
state[0] = expandedNodes;
state[1] = new Boolean(_transient);
state[2] = new Boolean(stopInCollapsed);
state[3] = selectedNode;
state[4] = queuedExpandedNodes;
state[5] = queuedCollapsedNodes;
return state;
}
public void setTransient(boolean newTransientValue) {
this._transient = newTransientValue;
}
public boolean isStopInCollapsed() {
return stopInCollapsed;
}
public void setStopInCollapsed(boolean stopInCollapsed) {
this.stopInCollapsed = stopInCollapsed;
}
private void visitNodes(UITree tree, TreeRange treeRange, TreeRowKey rootKey)
throws IOException {
try {
this.treeRange = treeRange;
Object oldKey = tree.getRowKey();
tree.walkModel(FacesContext.getCurrentInstance(), new Visitor(
rootKey, tree), treeRange, rootKey, null);
tree.setRowKey(oldKey);
} finally {
this.treeRange = null;
}
}
public void expandAll(UITree tree) throws IOException {
queuedCollapsedNodes.clear();
// SubTreeChildrenAppender infoAppender = null;
//
// if (storedPersister != null) {
// storedPersister.reset();
// infoAppender = storedPersister.getAppender(null);
// }
visitNodes(tree, RANGE_UNCONSTRAINED, null);
}
public void collapseAll(UITree tree) throws IOException {
expandedNodes.clear();
queuedExpandedNodes.clear();
// RequestUtils.setStoredPersister(tree.getBaseClientId(context),
// context, null);
}
public void collapseNode(UITree tree, TreeRowKey rowKey) throws IOException {
expandedNodes.remove(rowKey);
queuedExpandedNodes.remove(rowKey);
queuedCollapsedNodes.add(rowKey);
// TreePersister storedPersister =
// RequestUtils.getStoredPersister(tree.getBaseClientId(context),
// context);
// if (storedPersister != null) {
// storedPersister.removeNode(rowKey);
// }
}
public void expandNode(UITree tree, final TreeRowKey rowKey) throws IOException {
// SubTreeChildrenAppender infoAppender;
// if (storedPersister != null) {
// infoAppender = storedPersister.getAppender(rowKey);
// } else {
// infoAppender = null;
// }
TreeRange range;
// it's enough to traverse only subkeys of the node
// we're opening
range = new TreeRange() {
public boolean processChildren(TreeRowKey nextKey) {
return true;
}
public boolean processNode(TreeRowKey nextKey) {
return (rowKey == null && nextKey == null)
|| nextKey.equals(rowKey)
|| nextKey.isSubKey(rowKey);
}
};
visitNodes(tree, range, rowKey);
}
public void transferQueuedNodes() {
expandedNodes.addAll(queuedExpandedNodes);
queuedExpandedNodes.clear();
expandedNodes.removeAll(queuedCollapsedNodes);
queuedCollapsedNodes.clear();
}
}