FileDocCategorySizeDatePackage
UITree.javaAPI DocExample20650Tue Jun 08 11:26:42 BST 2004com.mycompany.jsf.component

UITree

public class UITree extends javax.faces.component.UIComponentBase implements javax.faces.component.NamingContainer
This class is a JSF component that represents a tree control. Facets named "openNode", "closedNode" and "leafNode" represent the components resposible for processing nodes of a TreeModel in all request processing lifecycle phases, and may be either input or output components. The class implements the NamingContainer interface to adjust the client IDs for the facets, so that a unique client ID is used for each node even though all nodes are in fact processed by one set of components.

The value of this component must be either a TreeModel or a TreeNode representing the root node of a tree.

The component is rendered by the "com.mycompany.Tree" renderer type by default.

author
Hans Bergsten, Gefion Software
version
1.0

Fields Summary
public static final String
COMPONENT_TYPE
public static final String
COMPONENT_FAMILY
private Object
value
The component's value, either a TreeModel or a TreeNode instance.
private com.mycompany.jsf.model.TreeModel
model
The TreeModel used by this component, either set explicitly as the value of created as a wrapper around a TreeNode value.
private String
nodeId
The current node ID.
private Map
saved
This map contains SavedState instances for each node in the tree, keyed by the client identifier of the component representing node, which contains the nodeId value for uniqueness.
private String
var
The name of the request scope variable through which the data object for the current node is exposed.
private String
varNodeToggler
The name of the request scope variable through which the node toggler object is exposed.
private NodeToggler
nodeToggler
The NodeToggler instance.
Constructors Summary
public UITree()
Creates an instance and sets the renderer type to "com.mycompany.Tree".


                   
      
        super();
        setRendererType("com.mycompany.Tree");
    
Methods Summary
public voidbroadcast(javax.faces.event.FacesEvent event)
If the event is a ChildEvent, unwraps the real event, calls setNodeId() with the node ID in the ChildEvent and delegates the processing to the real event source.


	if (!(event instanceof ChildEvent)) {
	    super.broadcast(event);
	    return;
	}

	// Set up the correct context and fire our wrapped event
	ChildEvent childEvent = (ChildEvent) event;
        String currNodeId = getNodeId();
	setNodeId(childEvent.getNodeId());
	FacesEvent nodeEvent = childEvent.getFacesEvent();
	nodeEvent.getComponent().broadcast(nodeEvent);
        setNodeId(currNodeId);
	return;
    
public voidencodeBegin(javax.faces.context.FacesContext context)
Before delegating to the superclass, resets the saved per-node state for facet input components unless it is needed to rerender the current page with errors, as determined by the keepSaved() method.

        model = null; // Re-evaluate even with server-side state saving
        if (!keepSaved(context)) {
            saved = new HashMap();
        }
        super.encodeBegin(context);
    
public java.lang.StringgetClientId(javax.faces.context.FacesContext context)
Returns a client ID composed from the regular client ID (returned by the superclass getClientId() method) and the current node ID (if any) separated by a colon.

	String ownClientId = super.getClientId(context);
        if (nodeId != null) {
            return ownClientId + NamingContainer.SEPARATOR_CHAR + nodeId;
        } else {
            return ownClientId;
        }
    
public javax.faces.component.UIComponentgetClosedNode()
Returns the "closedNode" facet.

        return getFacet("closedNode");
    
private com.mycompany.jsf.model.TreeModelgetDataModel()
Returns the cached model, if any, or the components value, as-is if it's a TreeModel or wrapped in a new TreeModel if it's a TreeNode, saving a reference in the "model" variable.


        if (model != null) {
            return model;
        }

        Object value = getValue();
        if (value != null) {
	    if (value instanceof TreeModel) {
		model = (TreeModel) value;
	    } else if (value instanceof TreeNode) {
		model = new TreeModel((TreeNode) value);
	    }
	}
	return model;
    
public java.lang.StringgetFamily()
Returns the COMPONENT_TYPE value.

        return (COMPONENT_FAMILY);
    
public javax.faces.component.UIComponentgetLeafNode()
Returns the "leafNode" facet.

        return getFacet("leafNode");
    
public com.mycompany.jsf.model.TreeNodegetNode()
Returns the current node from the TreeModel, or "null" if no node is currently processed.

	if (getDataModel() == null) {
	    return null;
	}
        return (getDataModel().getNode());
    
public java.lang.StringgetNodeId()
Returns the current node ID, or "null" if no node is currently processed.

        return nodeId;
    
private com.mycompany.jsf.component.UITree$NodeTogglergetNodeToggler()
Returns the single instance of the NodeToggler, creating it if needed.

	if (nodeToggler == null) {
	    nodeToggler = new NodeToggler(this);
	}
	return nodeToggler;
    
public javax.faces.component.UIComponentgetOpenNode()
Returns the "openNode" facet.

        return getFacet("openNode");
    
public java.lang.ObjectgetValue()
Returns the component value, set explicitly or through a ValueBinding, or null if the value isn't set.

	if (value != null) {
	    return value;
	}
	ValueBinding vb = getValueBinding("value");
	if (vb != null) {
	    return (vb.getValue(getFacesContext()));
	} else {
	    return null;
	}
    
public java.lang.StringgetVar()
Returns the name of the request scope through which the data object for the current node is exposed.

        return var;
    
public java.lang.StringgetVarNodeToggler()
Returns the name of the request scope through which the NodeToggler is exposed.

        return varNodeToggler;
    
private booleankeepSaved(javax.faces.context.FacesContext context)
Returns "true" if there's at least one error message queued for a client ID matching one of the nodes.


        Iterator clientIds = saved.keySet().iterator();
        while (clientIds.hasNext()) {
            String clientId = (String) clientIds.next();
            Iterator messages = context.getMessages(clientId);
            while (messages.hasNext()) {
                FacesMessage message = (FacesMessage) messages.next();
                if (message.getSeverity().compareTo(FacesMessage.SEVERITY_ERROR)
                    >= 0) {
                    return true;
                }
            }
        }
        return false;
    
public voidprocessDecodes(javax.faces.context.FacesContext context)
If "rendered" is true, resets the cached model and saved per-node state, calls processNodes() with a PhaseId for this phase, resets the node ID, and calls the decode() method.

        if (!isRendered()) {
            return;
        }

        model = null; // Re-evaluate even with server-side state saving
        saved = new HashMap(); // We don't need saved state here

	processNodes(context, PhaseId.APPLY_REQUEST_VALUES, null, 0);
	setNodeId(null);
	decode(context);
    
private voidprocessNodes(javax.faces.context.FacesContext context, javax.faces.event.PhaseId phaseId, java.lang.String parentId, int childLevel)
Recursively process all nodes at the root of the tree and all nodes under an open node for the provided phase, i.e., by calling processDecodes(), processValidators() or processUpdates() on the facet representing the node type.


	// Iterate over all expanded nodes in the model and process the
	// appropriate facet for each node.
	UIComponent facet = null;
	setNodeId(parentId != null ? 
		  parentId + NamingContainer.SEPARATOR_CHAR + childLevel :
		  "0");
	TreeNode node = getNode();
	if (node.isLeafNode()) {
	    facet = getLeafNode();
	} 
	else if (node.isExpanded()) {
	    facet = getOpenNode();
	}
	else {
	    facet = getClosedNode();
	}
	if (phaseId == PhaseId.APPLY_REQUEST_VALUES) {
	    facet.processDecodes(context);
	} else if (phaseId == PhaseId.PROCESS_VALIDATIONS) {
	    facet.processValidators(context);
	} else {
	    facet.processUpdates(context);
	}
	
	if (node.isExpanded()) {
	    int kidId = 0;
	    String currId = getNodeId();
	    Iterator i = node.getChildren().iterator();
	    while (i.hasNext()) {
		TreeNode kid = (TreeNode) i.next();
		processNodes(context, phaseId, currId, kidId++);
	    }
	}
    
public voidprocessUpdates(javax.faces.context.FacesContext context)
If "rendered" is true, calls processNodes() with a PhaseId for this phase, resets the node ID, and calls the decode() method.

        if (!isRendered()) {
            return;
        }

	processNodes(context, PhaseId.UPDATE_MODEL_VALUES, null, 0);
	setNodeId(null);
    
public voidprocessValidators(javax.faces.context.FacesContext context)
If "rendered" is true, calls processNodes() with a PhaseId for this phase, resets the node ID, and calls the decode() method.

        if (!isRendered()) {
            return;
        }

	processNodes(context, PhaseId.PROCESS_VALIDATIONS, null, 0);
	setNodeId(null);
    
public voidqueueEvent(javax.faces.event.FacesEvent event)
Wraps the event in a ChildEvent and calls the superclass method add it to the queue with this component as the event source.

        super.queueEvent(new ChildEvent(this, event, getNodeId()));
    
private voidrestoreDescendantState()
Restores state information for all facets by calling the restoreDescendantState(UIComponent, FacesContext) method on each facet.

        FacesContext context = getFacesContext();
        Iterator i = getFacets().values().iterator();
        while (i.hasNext()) {
            UIComponent facet = (UIComponent) i.next();
	    restoreDescendantState(facet, context);
        }
    
private voidrestoreDescendantState(javax.faces.component.UIComponent component, javax.faces.context.FacesContext context)
Restore state information for the specified component and its children from the previously saved state, if any.


        // Reset the client identifier for this component
        String id = component.getId();
        component.setId(id); // Forces client id to be reset

        if (component instanceof EditableValueHolder) {
            EditableValueHolder input = (EditableValueHolder) component;
            String clientId = component.getClientId(context);
            SavedState state = (SavedState) saved.get(clientId);
            if (state == null) {
                state = new SavedState();
            }
            input.setValue(state.getValue());
            input.setValid(state.isValid());
            input.setSubmittedValue(state.getSubmittedValue());
            // This *must* be set after the call to setValue(), since
            // calling setValue() always resets "localValueSet" to true.
            input.setLocalValueSet(state.isLocalValueSet());
        }

        Iterator kids = component.getChildren().iterator();
        while (kids.hasNext()) {
            restoreDescendantState((UIComponent) kids.next(), context);
        }
    
public voidrestoreState(javax.faces.context.FacesContext context, java.lang.Object state)
Restores the component to the provided state, previously returned by the saveState() method.

        Object values[] = (Object[]) state;
        super.restoreState(context, values[0]);
        value = values[1];
        var = (String) values[2];
        varNodeToggler = (String) values[3];
    
private voidsaveDescendantState()
Saves state information for all facets by calling the saveDescendantState(UIComponent, FacesContext) method on each facet.

        FacesContext context = getFacesContext();
        Iterator i = getFacets().values().iterator();
        while (i.hasNext()) {
            UIComponent facet = (UIComponent) i.next();
	    saveDescendantState(facet, context);
        }
    
private voidsaveDescendantState(javax.faces.component.UIComponent component, javax.faces.context.FacesContext context)
Saves state information for the specified component, if it implements the EditableValueHolder interface, and its children.


        if (component instanceof EditableValueHolder) {
            EditableValueHolder input = (EditableValueHolder) component;
            String clientId = component.getClientId(context);
            SavedState state = (SavedState) saved.get(clientId);
            if (state == null) {
                state = new SavedState();
                saved.put(clientId, state);
            }
            state.setValue(input.getLocalValue());
            state.setValid(input.isValid());
            state.setSubmittedValue(input.getSubmittedValue());
            state.setLocalValueSet(input.isLocalValueSet());
        }

        Iterator kids = component.getChildren().iterator();
        while (kids.hasNext()) {
            saveDescendantState((UIComponent) kids.next(), context);
        }
    
public java.lang.ObjectsaveState(javax.faces.context.FacesContext context)
Returns the component state to be saved as part of the view state.

        Object values[] = new Object[4];
        values[0] = super.saveState(context);
        values[1] = value;
        values[2] = var;
        values[3] = varNodeToggler;
        return (values);
    
public voidsetClosedNode(javax.faces.component.UIComponent closedNode)
Sets the "openNode" facet.

        getFacets().put("closedNode", closedNode);
    
public voidsetLeafNode(javax.faces.component.UIComponent closedNode)
Sets the "leafNode" facet.

        getFacets().put("leafNode", closedNode);
    
public voidsetNodeId(java.lang.String nodeId)
Sets the node ID, saving the state of all facet components for the previous node ID and restoring it for the new if it was saved for the new node ID previously, and exposes the node for the new node ID and the NodeToggler through their request scope variables.

        // Save current state for the previous node
        saveDescendantState();

        this.nodeId = nodeId;
	TreeModel model = getDataModel();
	if (model == null) {
	    return;
	}
	model.setNodeId(nodeId);

        // Reset current state information for the new row index
        restoreDescendantState();

        // Clear or expose the current row data as a request scope attribute
	Map requestMap =
	    getFacesContext().getExternalContext().getRequestMap();
        if (var != null) {
            if (nodeId == null) {
                requestMap.remove(var);
            } else {
		requestMap.put(var, getNode());
            }
        }
        if (varNodeToggler != null) {
            if (nodeId == null) {
                requestMap.remove(varNodeToggler);
            } else {
		requestMap.put(varNodeToggler, getNodeToggler());
            }
        }
    
public voidsetOpenNode(javax.faces.component.UIComponent openNode)
Sets the "openNode" facet.

        getFacets().put("openNode", openNode);
    
public voidsetValue(java.lang.Object value)
Sets the component value, either a TreeModel or a TreeNode, and resets the previously cached model, if any.

        this.model = null;
        this.value = value;
    
public voidsetValueBinding(java.lang.String name, javax.faces.el.ValueBinding binding)
Throws an IllegalArgumentException if the name is "var", "varToggler" or "nodeId" (these properties must be set to explicit values); otherwise, delegates to the superclass.

        if ("value".equals(name)) {
            model = null;
        } else if ("var".equals(name) || "nodeId".equals(name) ||
		   "varNodeToggler".equals(name)) {
            throw new IllegalArgumentException();
        }
        super.setValueBinding(name, binding);
    
public voidsetVar(java.lang.String var)
Sets the name of the request-scope variable through which the data object for the current node is exposed.

        this.var = var;
    
public voidsetVarNodeToggler(java.lang.String varNodeToggler)
Sets the name of the request scope through which the NodeToggler is exposed.

        this.varNodeToggler = varNodeToggler;