Package org.richfaces.component

Source Code of org.richfaces.component.UITree

/**
* 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;

import java.io.IOException;
import java.util.Iterator;
import java.util.Map;

import javax.faces.application.Application;
import javax.faces.component.NamingContainer;
import javax.faces.component.UIComponent;
import javax.faces.component.UIOutput;
import javax.faces.context.FacesContext;
import javax.faces.el.MethodBinding;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.FacesEvent;
import javax.faces.event.FacesListener;
import javax.faces.event.PhaseId;
import javax.faces.model.DataModel;

import org.ajax4jsf.component.AjaxComponent;
import org.ajax4jsf.component.UIDataAdaptor;
import org.ajax4jsf.event.AjaxEvent;
import org.ajax4jsf.model.DataComponentState;
import org.ajax4jsf.model.DataVisitor;
import org.ajax4jsf.model.ExtendedDataModel;
import org.ajax4jsf.model.Range;
import org.ajax4jsf.renderkit.AjaxRendererUtils;
import org.ajax4jsf.renderkit.RendererUtils;
import org.apache.commons.collections.iterators.SingletonIterator;
import org.richfaces.component.events.TreeEvents;
import org.richfaces.component.state.TreeState;
import org.richfaces.component.state.events.CollapseAllCommandEvent;
import org.richfaces.component.state.events.CollapseNodeCommandEvent;
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;
import org.richfaces.event.NodeSelectedEvent;
import org.richfaces.event.NodeSelectedListener;
import org.richfaces.event.TreeListenerEventsProducer;
import org.richfaces.model.AbstractTreeDataModel;
import org.richfaces.model.StackingTreeModel;
import org.richfaces.model.StackingTreeModelProvider;
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
*/

public abstract class UITree extends UIDataAdaptor implements
TreeListenerEventsProducer, Draggable, Dropzone, AjaxComponent {

  public static final String COMPONENT_TYPE = "org.richfaces.Tree";

  public static final String COMPONENT_FAMILY = "org.richfaces.Tree";

  public final static String PRESERVE_MODEL_STATE = "state";

  public final static String PRESERVE_MODEL_REQUEST = "request";

  public final static String PRESERVE_MODEL_NONE = "none";

  public final static String SWITCH_SERVER = "server";

  public final static String SWITCH_CLIENT = "client";

  public final static String SWITCH_AJAX = "ajax";

  public final static String SELECTED_NODE_PARAMETER_NAME = NamingContainer.SEPARATOR_CHAR
  + "selectedNode";

  public static final String SELECTION_INPUT_ATTRIBUTE = "_selectionInput";

  public final static String DEFAULT_SELECTED_CSS_CLASS = "dr-tree-i-sel";

  public final static String DEFAULT_HIGHLIGHTED_CSS_CLASS = "dr-tree-i-hl";

  private UITreeNode defaultFacet;
 
  /**
   * Name of EL variable for the tree node. This reference is needed to
   * let this parent class know about the attributes defined in the
   * subclass
   */
  private String _treeNodeVar;
 
  /**
   * Stored state of "treeNodeVar" attribute
   */
  private Object treeNodeVarOrigValue = null;

  public UITree() {
    super();

    DecodesPhaseNotifiyingListener
    .registerListenerInstance(getFacesContext());
  }

  public boolean getRendersChildren() {
    return true;
  }
 
  /**
   * Get name of EL variable for the tree node.
   *
   * @return the varState
   */
  public String getTreeNodeVar() {
      return _treeNodeVar;
  }

  /**
   * Set the name of EL variable
   *
   * @param treeNodeVar the varStatus to set
   */
  public void setTreeNodeVar(String treeNodeVar) {
      this._treeNodeVar = treeNodeVar;
  }

  /**
   * Lazily creates default node representation that is used if there is
   * no {@link UITreeNode} child for that nodeFace
   *
   * @return created or existing node representation component
   */
  protected UITreeNode getOrCreateDefaultFacet() {
    if (defaultFacet == null) {
      FacesContext facesContext = FacesContext.getCurrentInstance();
      Application application = facesContext.getApplication();
      defaultFacet = (UITreeNode) application
      .createComponent(UITreeNode.COMPONENT_TYPE);
      defaultFacet.setId("_defaultNodeFace");
      defaultFacet.setParent(this);
      defaultFacet.getAttributes().put(
          UITreeNode.DEFAULT_NODE_FACE_ATTRIBUTE_NAME, Boolean.TRUE);
      defaultFacet.getChildren().add(
          createDefaultNodeFaceOutput(facesContext));
    }

    return defaultFacet;
  }

  /**
   * Return the data object representing the node for the currently
   * selected row key, if any
   *
   * @return {@link TreeNode} instance corresponding to the current row key
   */
  public TreeNode getTreeNode() {
    return ((AbstractTreeDataModel) getExtendedDataModel()).getTreeNode();
  }

  public abstract boolean isImmediate();

  public abstract void setImmediate(boolean immediate);

  private FacesEvent wrapTreeEvent(FacesEvent facesEvent) {
    if (facesEvent.getSource() == this) {
      return new IndexedEvent(this, facesEvent, getRowKey());
    }

    return facesEvent;
  }

  public void queueEvent(FacesEvent event) {
    FacesEvent resultEvent = event;
    if (event instanceof NodeExpandedEvent) {
      if (isImmediate()) {
        event.setPhaseId(PhaseId.APPLY_REQUEST_VALUES);
      } else {
        event.setPhaseId(PhaseId.INVOKE_APPLICATION);
      }

      resultEvent = wrapTreeEvent(event);
    } else if (event instanceof NodeSelectedEvent) {
      if (isImmediate()) {
        event.setPhaseId(PhaseId.APPLY_REQUEST_VALUES);
      } else {
        event.setPhaseId(PhaseId.UPDATE_MODEL_VALUES);
      }

      resultEvent = wrapTreeEvent(event);
    } else if (event instanceof TreeStateCommandEvent) {
      FacesContext context = FacesContext.getCurrentInstance();
      boolean afterDecodesPhase = null != context
      .getExternalContext()
      .getRequestMap()
      .get(
          DecodesPhaseNotifiyingListener.DECODE_PHASE_NOTICE_NAME);

      if (isImmediate() && !afterDecodesPhase) {
        event.setPhaseId(PhaseId.APPLY_REQUEST_VALUES);
      } 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);
  }

  /**
   * Locates {@link UITreeNode} instance that has type equal to current
   * nodeFace. Default nodeFace is declared as #{var.type} by default where
   * var is "var" attribute value Calls <code>getOrCreateDefaultFacet()</code>
   * if none found.
   *
   * @see UITree#getOrCreateDefaultFacet()
   * @return {@link UITreeNode} representing current nodeFace
   */
  public UITreeNode getNodeFacet() {
    String facetName = this.getNodeFace();
    if (facetName != null) {
      if (getChildCount() > 0) {
        Iterator iterator = getChildren().iterator();
        while (iterator.hasNext()) {
          Object object = iterator.next();
          if (object instanceof UITreeNode) {
            UITreeNode treeNode = (UITreeNode) object;

            if (!treeNode.isRendered()) {
              continue;
            }
           
            if (facetName.equals(treeNode.getType())) {
              return treeNode;
            }
          }
        }
      }
    } else {
      UIComponent component = null;
     
      ExtendedDataModel dataModel = getExtendedDataModel();
      if (dataModel instanceof TreeModelVisualComponentProvider) {
        TreeModelVisualComponentProvider componentProvider = (TreeModelVisualComponentProvider) dataModel;
        component = componentProvider.getComponent();
      }

      if (component == null) {
        component = this;
      }
     
      if (component.isRendered() && component.getChildCount() > 0) {
        Iterator iterator = component.getChildren().iterator();
        while (iterator.hasNext()) {
          UIComponent child = (UIComponent) iterator.next();
         
          if (child instanceof UITreeNode) {
            UITreeNode treeNode = (UITreeNode) child;
           
            if (!treeNode.isRendered()) {
              continue;
            }
           
            if (treeNode.getType() != null) {
              continue;
            }

            return treeNode;
          }
        }
      }
    }

    return getOrCreateDefaultFacet();
  }

  /**
   * Setup EL variable for different iteration. Value of row tree node is
   * put into request scope attributes with name "treeNodeVar" bean
   * property. All other attributes are processed in parent
   * <code>UIDataAdaptor</code> class
   *
   * @param faces - current faces context
   * @param localModel - reference to data model
   * @param rowSelected - boolean flag indicating whether the row is selected
   */
  protected void setupVariable(FacesContext faces, DataModel localModel, boolean rowSelected) {
      super.setupVariable(faces, localModel, rowSelected);
      // get the map storing the request scope
      // attributes
      Map attrs = faces.getExternalContext().getRequestMap();

      String treeNodeVar = getTreeNodeVar();
      if (rowSelected) {
    // Current row tree node.
    if (treeNodeVar != null) {
        attrs.put(treeNodeVar, getTreeNode());
    }
      } else {
    if (treeNodeVar != null) {
        attrs.remove(treeNodeVar);
    }
      }
  }
 
  /*
   * (non-Javadoc)
   *
   * @see org.ajax4jsf.ajax.repeat.UIDataAdaptor#resetDataModel()
   */

  public void resetDataModel() {
    super.resetDataModel();

    TreeState state = (TreeState) getComponentState();
    // transfer nodes delayed to open to rendering queue
    state.transferQueuedNodes();
    // re-set stopInCollapsed to handle AJAX switch type change
    state.setStopInCollapsed(isStopInCollapsed());

    setExtendedDataModel(createDataModel(false));
  }

  public void walk(FacesContext faces, DataVisitor visitor)
  throws IOException {

    walk(faces, visitor, null);
  }

  /**
   * Walks through model or some subset of it if rowKey is not null
   *
   * @param faces
   *            {@link FacesContext} instance
   * @param visitor
   *            {@link UIDataAdaptor.ComponentVisitor} instance
   * @param range
   *         {@link Range} range instance
   * @param rowKey
   *            row key to start from or null to start
   *            from root
   * @param argument
   *            implementation-specific visitor argument
   * @throws IOException
   */
  public void walk(FacesContext faces, DataVisitor visitor, Range range,
      Object rowKey, Object argument) throws IOException {

    Object savedRowKey = getRowKey();

    try {
      AbstractTreeDataModel dataModel = (AbstractTreeDataModel) getExtendedDataModel();
      dataModel.walk(faces, visitor, range, rowKey,
          argument,
          false/*faces.getExternalContext().getRequestParameterMap().get(
              getBaseClientId(faces) + LAST_ELEMENT_FLAG) != null*/);
    } finally {
      try {
        setRowKey(faces, savedRowKey);
      } catch (Exception e) {
        faces.getExternalContext().log(e.getMessage(), e);
      }
    }
  }

  /**
   * Walks through backing data model if current data model has one. Cached
   * data models usually have one. This method is typically used for acquiring
   * new data when some nodes has changed their state
   *
   * @param faces
   *            {@link FacesContext} instance
   * @param visitor
   *            {@link UIDataAdaptor.ComponentVisitor} instance
   * @param range
   *         {@link Range} range instance
   * @param rowKey
   *            row key to start from or null to start
   *            from root
   * @param argument
   *            implementation-specific visitor argument
   * @throws IOException
   */
  public void walkModel(FacesContext faces, DataVisitor visitor, Range range,
      Object key, Object argument) throws IOException {
    AbstractTreeDataModel extendedDataModel = (AbstractTreeDataModel) getExtendedDataModel();
    extendedDataModel.walkModel(faces, visitor,
        (TreeRange) range, key, argument,
        false);
  }

  public String getSelectionStateInputName(FacesContext context) {
    return getBaseClientId(context) + NamingContainer.SEPARATOR_CHAR
    + "input";
  }

  /*
   * (non-Javadoc)
   *
   * @see org.ajax4jsf.ajax.repeat.UIDataAdaptor#processDecodes(javax.faces.context.FacesContext)
   */

  public void processDecodes(FacesContext faces) {
    if (!this.isRendered())
      return;

    Map requestParameterMap = faces.getExternalContext().getRequestParameterMap();
    if (requestParameterMap.get(getBaseClientId(faces)
        + SELECTED_NODE_PARAMETER_NAME) != null) {
      getAttributes().put(
          SELECTED_NODE_PARAMETER_NAME,
          requestParameterMap.get(getBaseClientId(faces)
              + SELECTED_NODE_PARAMETER_NAME));
    }
    Object selectionInputValue = requestParameterMap
    .get(getSelectionStateInputName(faces));
    if (selectionInputValue instanceof String) {
      getAttributes().put(SELECTION_INPUT_ATTRIBUTE, selectionInputValue);
    }

    try {
      super.processDecodes(faces, null);

      if (null != getAttributes().get(SELECTION_INPUT_ATTRIBUTE)) {
        TreeState state = (TreeState) getComponentState();

        if (!state.isSelected(null)) {
          new NodeSelectedEvent(this, state.getSelectedNode()).queue();
        }
      }

    } finally {
      getAttributes().remove(SELECTION_INPUT_ATTRIBUTE);
      getAttributes().remove(SELECTED_NODE_PARAMETER_NAME);
    }

    // if (treePersister != null) {
    // RequestUtils.setStoredPersister(this
    // .getBaseClientId(getFacesContext()),
    // this.getFacesContext(), treePersister);
    // setExtendedDataModel(new PersistedDataModel(treePersister,
    // (AbstractTreeDataModel) getExtendedDataModel()));
    // }
  }


  protected Iterator dataChildren() {
    return new SingletonIterator(getNodeFacet());
  }

  /**
   * Returns whether current node is leaf ie. has no children
   *
   * @return <code>true</code> if current node is leaf else
   *         <code>false</code>
   */
  public boolean isLeaf() {
    AbstractTreeDataModel dataModel = (AbstractTreeDataModel) getExtendedDataModel();
    return dataModel.isLeaf();
  }

  /**
   * Returns whether current node is expanded
   *
   * @return <code>true</code> if node is expanded else <code>false</code>
   */
  public boolean isExpanded() {
    TreeState treeState = (TreeState) getComponentState();
    return treeState.isExpanded((TreeRowKey) this.getRowKey());
  }

  /**
   * Returns whether current node is selected
   *
   * @return <code>true</code> if node is selected else <code>false</code>
   */
  public boolean isSelected() {
    TreeState treeState = (TreeState) getComponentState();
    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();
  }


  protected DataComponentState createComponentState() {
    return new TreeState(isStopInCollapsed());
  }

  /**
   * Returns whether switch type is set to "server"
   *
   * @return <code>true</code> if switch type is "server" else
   *         <code>false</code>
   */
  protected boolean isStopInCollapsed() {
    return !SWITCH_CLIENT.equals(getSwitchType());
  }

 
  public void broadcast(FacesEvent event) throws AbortProcessingException {
    super.broadcast(event);
   
    DataComponentState componentState = getComponentState();
    if (componentState instanceof FacesListener) {
      FacesListener facesListener = (FacesListener) componentState;

      if (event.isAppropriateListener(facesListener)) {
        // we can safely open/close nodes here
        event.processListener(facesListener);
      }
    }

    if (event instanceof NodeSelectedEvent) {
      NodeSelectedEvent selectedEvent = (NodeSelectedEvent) event;
      setSelected();
    }

    // fire node events
    TreeEvents.invokeListenerBindings(this, event, getFacesContext());

    if (event instanceof AjaxEvent) {
      FacesContext facesContext = getFacesContext();
      AjaxRendererUtils.addRegionsFromComponent(this, facesContext);
    }
  }

  public boolean hasAjaxSubmitSelection() {
    return isAjaxSubmitSelection();
  }
 
  /**
   * Save current state of data variable. Overrides the implementation in
   * the base class for the case the base implementation will be changed.
   */
  public void captureOrigValue() {
      this.captureOrigValue(FacesContext.getCurrentInstance());
  }

  /**
   * Save current state of data variable.
   *
   * @param faces current faces context
   */
  public void captureOrigValue(FacesContext faces) {
      super.captureOrigValue(faces);
      String treeNodeVar = getTreeNodeVar();
      if (treeNodeVar != null) {
    Map attrs = faces.getExternalContext().getRequestMap();
    this.treeNodeVarOrigValue = attrs.get(treeNodeVar);
      }
  }

  /**
   * Restore value of data variable after processing phase. Overrides the
   * implementation in the base class for the case the base implementation
   * will be changed.
   */
  public void restoreOrigValue() {
      this.restoreOrigValue(FacesContext.getCurrentInstance());
  }

  /**
   * Restore value of data variable after processing phase.
   *
   * @param faces current faces context
   */
  public void restoreOrigValue(FacesContext faces) {
      super.restoreOrigValue(faces);
      String treeNodeVar = getTreeNodeVar();
      if (treeNodeVar != null) {
    Map attrs = faces.getExternalContext().getRequestMap();
    if (this.treeNodeVarOrigValue != null) {
        attrs.put(treeNodeVar, this.treeNodeVarOrigValue);
    } else {
        attrs.remove(treeNodeVar);
    }
      }
  }

  private ExtendedDataModel createDataModel(boolean allowCached) {
    Object value = this.getValue();
    if (value != null) {
      TreeDataModel treeDataModel = new TreeDataModel();
      treeDataModel.setWrappedData(this.getValue());
     
      if (allowCached && PRESERVE_MODEL_REQUEST.equals(getPreserveModel())) {
        treeDataModel = new CacheableTreeDataModel(treeDataModel);
      }

      return treeDataModel;
    } else {
      // TODO implement request caching
      StackingTreeModel stackingTreeModel = new VisualStackingTreeModel(null);
      if (getChildCount() > 0) {
        Iterator children = getChildren().iterator();
        while (children.hasNext()) {
          UIComponent component = (UIComponent) children.next();
          if (component instanceof StackingTreeModelProvider) {
            StackingTreeModelProvider provider = (StackingTreeModelProvider) component;
            stackingTreeModel.addStackingModel(provider.getStackingModel());
          }
        }
      }
     
      return stackingTreeModel;
    }
  }

  public void processUpdates(FacesContext faces) {
    super.processUpdates(faces);
    if (getExtendedDataModel() instanceof CacheableTreeDataModel) {
      setExtendedDataModel(createDataModel(false));
    }
  }

  protected ExtendedDataModel createDataModel() {
    return createDataModel(true);
  }

  /**
   * Queues expansion command for node whose row key is equal to rowKey
   * parameter
   *
   * @param rowKey
   *            of the node to expand
   * @throws IOException
   */
  public void queueNodeExpand(TreeRowKey rowKey) throws IOException {
    new ExpandNodeCommandEvent(this, rowKey).queue();
  }

  /**
   * Queues collapsion command for node whose row key is equal to rowKey
   * parameter
   *
   * @param rowKey
   *            of the node to expand
   * @throws IOException
   */
  public void queueNodeCollapse(TreeRowKey rowKey) throws IOException {
    new CollapseNodeCommandEvent(this, rowKey).queue();
  }

  /**
   * Queues all node expansion command
   *
   * @throws IOException
   */
  public void queueExpandAll() throws IOException {
    new ExpandAllCommandEvent(this).queue();
  }

  /**
   * Queues all node collapsion command
   *
   * @throws IOException
   */
  public void queueCollapseAll() throws IOException {
    new CollapseAllCommandEvent(this).queue();
  }

  public abstract String getSwitchType();

  public abstract void setSwitchType(String switchType);

  public abstract String getIcon();

  public abstract void setIcon(String icon);

  public abstract String getIconExpanded();

  public abstract void setIconExpanded(String icon);

  public abstract String getIconCollapsed();

  public abstract void setIconCollapsed(String icon);

  public abstract String getIconLeaf();

  public abstract void setIconLeaf(String icon);

  public abstract void setShowConnectingLines(boolean showConnectingLines);

  public abstract boolean isShowConnectingLines();

  public abstract void setAjaxSubmitSelection(boolean ajaxSubmitSelection);

  public abstract boolean isAjaxSubmitSelection();

  public abstract String getPreserveModel();

  public abstract void setPreserveModel(String preserveModel);

  public abstract void setHighlightedClass(String selectedClass);

  public abstract String getHighlightedClass();

  public abstract void setSelectedClass(String selectedClass);

  public abstract String getSelectedClass();

  public abstract void setNodeFace(String nodeFace);

  public abstract String getNodeFace()

  public abstract void setToggleOnClick(boolean toggleOnClick);

  public abstract boolean isToggleOnClick();

  public abstract void setStateAdvisor(Object nodeFace);

  public abstract Object getStateAdvisor();

  public abstract MethodBinding getAdviseNodeOpened();

  public abstract void setAdviseNodeOpened(MethodBinding adviseNodeOpened);

  public abstract MethodBinding getAdviseNodeSelected();

  public abstract void setAdviseNodeSelected(MethodBinding adviseNodeSelected);

  public void addChangeExpandListener(NodeExpandedListener listener) {
    addFacesListener(listener);
  }

  public void addNodeSelectListener(NodeSelectedListener listener) {
    addFacesListener(listener);
  }

  public void removeChangeExpandListener(NodeExpandedListener listener) {
    removeFacesListener(listener);
  }

  public void removeNodeSelectListener(NodeSelectedListener listener) {
    removeFacesListener(listener);
  }

  public NodeExpandedListener[] getChangeExpandListeners() {
    return (NodeExpandedListener[]) getFacesListeners(NodeExpandedListener.class);
  }

  public NodeSelectedListener[] getNodeSelectListeners() {
    return (NodeSelectedListener[]) getFacesListeners(NodeSelectedListener.class);
  }

  public void addDropListener(DropListener listener) {
    addFacesListener(listener);
  }

  public DropListener[] getDropListeners() {
    return (DropListener[]) getFacesListeners(DropListener.class);
  }

  public void removeDropListener(DropListener listener) {
    removeFacesListener(listener);
  }

  public void addDragListener(DragListener listener) {
    addFacesListener(listener);
  }

  public DragListener[] getDragListeners() {
    return (DragListener[]) getFacesListeners(DragListener.class);
  }

  public void removeDragListener(DragListener listener) {
    removeFacesListener(listener);
  }

  /**
   * Return the data object representing the node data for the contextual row key
   *
   * @param rowKey contextual row key
   * @return data corresponding to the current row key
   */
  public Object getRowData(Object rowKey) {
    Object storedKey = getRowKey();
    FacesContext context = FacesContext.getCurrentInstance();

    try {
      setRowKey(context, rowKey);

      return getRowData();
    } finally {
      try {
        setRowKey(context, storedKey);
      } catch (Exception e) {
        context.getExternalContext().log(e.getMessage(), e);
      }
    }
  }

  /**
   * Return the data object representing the node for the contextual row key
   *
   * @param rowKey contextual row key
   * @return {@link TreeNode} instance corresponding to the current row key
   */
  public TreeNode getTreeNode(Object rowKey) {
    FacesContext context = FacesContext.getCurrentInstance();
    Object storedKey = getRowKey();
    try {
      setRowKey(context, rowKey);

      return getTreeNode();
    } finally {
      try {
        setRowKey(context, storedKey);
      } catch (Exception e) {
        context.getExternalContext().log(e.getMessage(), e);
      }
    }
  }

  private UIOutput createDefaultNodeFaceOutput(FacesContext facesContext) {
    UIOutput component = new UIOutput() {

      public Object getValue() {
        return getRowData();
      }


      public String getId() {
        String id = super.getId();

        if (id == null) {
          //set fixed id to prevent duplicate id exception
          id = "_defaultNodeFaceOutput";//FacesContext.getCurrentInstance().getViewRoot()
          //.createUniqueId();

          setId(id);
        }

        return id;
      }


      public void setTransient(boolean transientFlag) {
        if (!transientFlag) {
          throw new IllegalArgumentException(
          "Default representation for node face cannot be set non-persistent!");
        }
      }


      public boolean isTransient() {
        return true;
      }
    };

    return component;
  }


  public Object saveState(FacesContext faces) {
    Object[] state = new Object[3];
    state[0] = super.saveState(faces);
    state[1] = saveAttachedState(faces, defaultFacet);
    state[2] = getTreeNodeVar();

    return state;
  }


  public void restoreState(FacesContext faces, Object object) {
    Object[] state = (Object[]) object;
    super.restoreState(faces, state[0]);

    defaultFacet = (UITreeNode) restoreAttachedState(faces, state[1]);
    if (defaultFacet != null) {
      defaultFacet.getChildren().add(createDefaultNodeFaceOutput(faces));
      defaultFacet.setParent(this);
    }
    setTreeNodeVar((String) state[2]);
  }
 
  public String getResolvedDragIndicator(FacesContext facesContext) {
    String dragIndicator = getDragIndicator();
    if (dragIndicator != null) {
      UIComponent indicator = RendererUtils.getInstance().
        findComponentFor(this, dragIndicator);
      if (indicator != null) {
        return indicator.getClientId(facesContext);
      }
    }
   
    return null;
  }
}


TOP

Related Classes of org.richfaces.component.UITree

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.