Package org.apache.myfaces.trinidad.component

Source Code of org.apache.myfaces.trinidad.component.UIXTreeTable

// WARNING: This file was automatically generated. Do not edit it directly,
//          or you will lose your changes.

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.myfaces.trinidad.component;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import javax.el.MethodExpression;
import javax.faces.component.UIComponent;
import javax.faces.component.visit.VisitCallback;
import javax.faces.component.visit.VisitContext;
import javax.faces.context.FacesContext;
import javax.faces.el.MethodBinding;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.FacesEvent;
import javax.faces.event.PhaseId;
import org.apache.myfaces.trinidad.bean.FacesBean;
import org.apache.myfaces.trinidad.bean.PropertyKey;
import org.apache.myfaces.trinidad.event.FocusEvent;
import org.apache.myfaces.trinidad.event.RangeChangeEvent;
import org.apache.myfaces.trinidad.event.RangeChangeListener;
import org.apache.myfaces.trinidad.model.RowKeySet;
import org.apache.myfaces.trinidad.util.ComponentUtils;

/**
*
* <html:p>
*           The Apache Trinidad TreeTable is used to display data that is structured in a hierarchical format.
*           This component displays a hierarchy
*           in a UI similar to a Trinidad Table, and is more elaborate than the Tree component.
*           TreeTable supports displaying columns of data per element in the hierarchy.
*           Unlike the Tree component, TreeTable
*           only supports single rooted hierarchies. The features of the TreeTable
*           component include mechanisms for focusing in on subtrees (within the main
*           tree), as well as expanding and collapsing elements in the hierarchy.
*         </html:p>
*
*         <html:p>
*           Like the Table, the TreeTable's children must be Trinidad
*           Column components. Like the Tree, the TreeTable has a &quot;nodeStamp&quot;
*           facet which renders the &quot;Object Name&quot; Column.
*
*           The &quot;Object Name&quot; Column contains the primary identifier of an element
*           in the hierarchy. For example, in an organization chart of employees, the &quot;Object Name&quot;
*           Column might be the employee name.
*         </html:p>
*
* <h4>Events:</h4>
* <table border="1" width="100%" cellpadding="3" summary="">
* <tr bgcolor="#CCCCFF" class="TableHeadingColor">
* <th align="left">Type</th>
* <th align="left">Phases</th>
* <th align="left">Description</th>
* </tr>
* <tr class="TableRowColor">
* <td valign="top"><code>org.apache.myfaces.trinidad.event.RowDisclosureEvent</code></td>
* <td valign="top" nowrap>Apply<br>Request<br>Values<br>Invoke<br>Application</td>
* <td valign="top">The expansion event is generated for a table when the detail facet of a row is expanded or collapsed. For tree or a treeTable, the expansion
                       event is generated when tree nodes are expanded or collapsed.</td>
* </tr>
* <tr class="TableRowColor">
* <td valign="top"><code>org.apache.myfaces.trinidad.event.SelectionEvent</code></td>
* <td valign="top" nowrap>Apply<br>Request<br>Values<br>Invoke<br>Application</td>
* <td valign="top">The selection event is delivered when the table selection
                       changes.</td>
* </tr>
* <tr class="TableRowColor">
* <td valign="top"><code>org.apache.myfaces.trinidad.event.FocusEvent</code></td>
* <td valign="top" nowrap>Apply<br>Request<br>Values<br>Invoke<br>Application</td>
* <td valign="top">Event delivered when user clicks to focus on (or zoom into) a particular element's subtree of children.
                The TreeTable responds to this event by modifying the "focusPath" property appropriately.
                Subsequently, any registered FocusListener instances are called.</td>
* </tr>
* <tr class="TableRowColor">
* <td valign="top"><code>org.apache.myfaces.trinidad.event.AttributeChangeEvent</code></td>
* <td valign="top" nowrap>Invoke<br>Application<br>Apply<br>Request<br>Values</td>
* <td valign="top">Event delivered to describe an attribute change.  Attribute change events are not delivered for any programmatic change to a property.  They are only delivered when a renderer changes a property without the application's specific request.  An example of an attribute change event might include the width of a column that supported client-side resizing.</td>
* </tr>
* </table>
*/
public class UIXTreeTable extends UIXTree
{
  static public final FacesBean.Type TYPE = new FacesBean.Type(
    UIXTree.TYPE);
  static public final PropertyKey ROOT_NODE_RENDERED_KEY =
    TYPE.registerKey("rootNodeRendered", Boolean.class, Boolean.TRUE);
  static public final PropertyKey ROWS_BY_DEPTH_KEY =
    TYPE.registerKey("rowsByDepth", int[].class, null, 0, PropertyKey.Mutable.SOMETIMES);
  static public final PropertyKey RANGE_CHANGE_LISTENER_KEY =
    TYPE.registerKey("rangeChangeListener", MethodExpression.class);

  static public final String COMPONENT_FAMILY =
    "org.apache.myfaces.trinidad.TreeTable";
  static public final String COMPONENT_TYPE =
    "org.apache.myfaces.trinidad.TreeTable";

  /**
   * Construct an instance of the UIXTreeTable.
   */
  public UIXTreeTable()
  {
    super("org.apache.myfaces.trinidad.BaseTreeTable");
  }
 
  /**
   * Override to update the container client id cache before decode
   */
  @Override
  public void decode(FacesContext context)
  {
    _resetContainerClientIdCache();
    super.decode(context);   
  }
 
  /**
   * Override to update the container client id cache before validations
   */
  @Override
  public void processValidators(FacesContext context)
  {
    _resetContainerClientIdCache();
    super.processValidators(context);
  }
 
  /**
   * Override to update the container client id cache before updates
   */ 
  @Override
  public void processUpdates(FacesContext context)
  {
    _resetContainerClientIdCache();
    super.processUpdates(context);
 

  /**
   * Override to update the container client id cache before encode
   */
  @Override
  protected void __encodeBegin(FacesContext context) throws IOException
  {
    _resetContainerClientIdCache();
    super.__encodeBegin(context);
  }


  /**
   * Override to return clientd ids with no currency for items in header/footer facets
   */
  @Override
  public String getContainerClientId(FacesContext context, UIComponent child)
  {
    String id;
    if (_containerClientIdCache == null || _isStampedChild(child))
    {  
      // call the UIXCollection getContainerClientId, which attaches currency string to the client id
      id = getContainerClientId(context);
    }
    else
    {
      // The target is not a stamped child, so return a client id with no currency string
      id = getClientId(context);
    }

    return id;
  }

  @Deprecated
  public void setRangeChangeListener(MethodBinding binding)
  {
    setRangeChangeListener(adaptMethodBinding(binding));
  }

  /**
   * Gets the maximum number of rows to show.
   * This changes depending on the depth of the current row in the tree
   * hierarchy.
   * The rows per depth is obtained from
   * {@link #getRowsByDepth}.
   * @return 0 if all rows must be shown at this level.
   */
  @Override
  public final int getRows()
  {
    int depth = getTreeModel().getDepth();
    assert depth >= 0;

    // the root element is selected when depth is zero:
    if (depth==0)
      return 1; // the treeTable only shows the first root node.

    int[] rows = getRowsByDepth();
    if ((rows == null) || (rows.length == 0))
      return 0;

    depth--;

    // in a treeTable, the the first "rows" property affects how many
    // children of the root element to show.
    return (depth >= rows.length) ? rows[rows.length - 1] : rows[depth];
  }

  /**
   * Gets the range start index for the current collection.
   * The current collection is the children of the parent of the
   * current rowData. ie: the current collection is the collection of
   * siblings of the current rowData.
   * @return zero based index of the row that must be displayed first.
   * @see #getRowData()
   */
  @Override
  public final int getFirst()
  {
    // "first" does not change per path. It changes per parent path.
    // this is because "first", "rows" and "rowCount" applies to the container
    // element and not the current element:
    Object container = _getContainerPath();
    Integer first = _firstMap.get(container);
    return (first != null) ? first.intValue() : 0;
  }

  /**
   * Sets the range start index for the current collection.
   * The current collection is the children of the parent of the
   * current rowData. ie: the current collection is the collection of
   * siblings of the current rowData.
   * @param index zero based index of the row that must be displayed first.
   * @see #getRowData()
   */
  public void setFirst(int index)
  {
    // "first" does not change per path. It changes per parent path.
    // this is because "first", "rows" and "rowCount" applies to the container
    // element and not the current element:
    Object container = _getContainerPath();
    Map<Object, Integer> comparant = Collections.emptyMap();
    if (_firstMap == comparant)
      _firstMap = new HashMap<Object, Integer>(3);

    if (index <= 0)
      _firstMap.remove(container);
    else
      _firstMap.put(container, Integer.valueOf(index));
  }

  /**
   * Adds a RangeChangeListener.
   */
  public void addRangeChangeListener(RangeChangeListener listener)
  {
    addFacesListener(listener);
  }

  /**
   * Removes a RangeChangeListener.
   */
  public void removeRangeChangeListener(RangeChangeListener listener)
  {
    removeFacesListener(listener);
  }


  /**
   * Retrieves all RangeChangeListeners
   */
  public RangeChangeListener[] getRangeChangeListeners()
  {
    return (RangeChangeListener[]) getFacesListeners(RangeChangeListener.class);
  }

  @Override
  public Object saveState(FacesContext context)
  {
    Object[] array = new Object[2];
    array[0] = super.saveState(context);
    array[1] = (_firstMap.isEmpty()) ? null : _firstMap;

    if (array[0] == null && array[1] == null)
      return null;

    return array;
  }

  @Override
  @SuppressWarnings("unchecked")
  public void restoreState(FacesContext context, Object state)
  {
    Object[] array = (Object[]) state;
    super.restoreState(context, array[0]);
    _firstMap = (Map<Object, Integer>) array[1];
    if (_firstMap == null)
      _firstMap = Collections.emptyMap();
  }

  @Override
  public void broadcast(FacesEvent event) throws AbortProcessingException
  {
    // Notify the specified disclosure listener method (if any)
    if (event instanceof FocusEvent)
    {
      setFocusRowKey(getRowKey());
      //pu: Implicitly record a Change for 'focusPath' attribute
      addAttributeChange("focusPath",
                         getFocusRowKey());
      // it is nice to expand the focused item:
      getDisclosedRowKeys().add();

      broadcastToMethodExpression(event, getFocusListener());
    }
    else if (event instanceof RangeChangeEvent)
    {
      RangeChangeEvent rce = (RangeChangeEvent) event;
      setFirst(rce.getNewStart());
      broadcastToMethodExpression(event, getRangeChangeListener());
    }

    // Perform standard superclass processing
    super.broadcast(event);
  }


  /**
   * Gets the stamps. This returns the children of this component plus
   * the nodeStamp stamp (if any).
   */
  // TODO cache the result.
  @Override
  protected final List<UIComponent> getStamps()
  {
   
    List<UIComponent> children = getChildren();
    List<UIComponent> stamps;
   
    if (children.isEmpty())
    {
      // no children, so use Node stamps as the stamp
      stamps = super.getStamps();
    }
    else
    {
      UIComponent nodeStamp = getNodeStamp();
     
      if (nodeStamp == null)
      {
        // no node stamp, so stamp, is only the children
        stamps = children;
      }
      else
      {
        // stamps are the children plus the node stamp
        stamps = new ArrayList<UIComponent>(children.size() + 1);
        stamps.addAll(children);
        stamps.add(nodeStamp);
      }
    }
   
    return stamps;
  }

  /**
   * Restores the state for the given stamp.
   * This method avoids changing the state of facets on columns.
   */
  @Override
  protected final void restoreStampState(FacesContext context, UIComponent stamp,
                                         Object stampState)
  {
    if (stamp instanceof UIXColumn)
    {
      // if it is a column, we don't want the facets processed.
      // Only the children:
      StampState.restoreChildStampState(context, stamp, this, stampState);
    }
    else
      super.restoreStampState(context, stamp, stampState);
  }

  /**
   * Saves the state for the given stamp.
   * This method avoids changing the state of facets on columns.
   */
  @Override
  protected final Object saveStampState(FacesContext context, UIComponent stamp)
  {
    if (stamp instanceof UIXColumn)
    {
      // if it is a column, we don't want the facets processed.
      // Only the children:
      return StampState.saveChildStampState(context, stamp, this);
    }
    else
      return super.saveStampState(context, stamp);
  }

  @SuppressWarnings("unchecked")
  @Override
  protected void processFacetsAndChildren(
    FacesContext context,
    PhaseId phaseId)
  {
    // process all the facets of this hgrid just once
    // (except for the "nodeStamp" facet which must be processed once
    // per row):
    TableUtils.processFacets(context, this, this, phaseId,
      UIXTreeTable.NODE_STAMP_FACET);

    UIComponent nodeStamp = getNodeStamp();
    // process any facets of the nodeStamp column:
    TableUtils.processFacets(context, this, nodeStamp, phaseId, null);

    // process all the facets of this table's column children:
    TableUtils.processColumnFacets(context, this, this, phaseId);

    // recursively process any grandchild columns of the nodeStamp column:
    TableUtils.processColumnFacets(context, this, nodeStamp, phaseId);

    Object oldPath = getRowKey();
    RowKeySet state = getDisclosedRowKeys();
    try
    {
      Object path = getFocusRowKey();
      setRowKey(path);
      if (path == null)
      {
        HierarchyUtils.__iterateOverTree(context,
                                         phaseId,
                                         this,
                                         state,
                                         true);       

      }
      else
      {
        TableUtils.processStampedChildren(context, this, phaseId);
        processComponent(context, nodeStamp, phaseId); // bug 4688568
 
        if (state.isContained())
        {
          enterContainer();
          HierarchyUtils.__iterateOverTree(context,
                                           phaseId,
                                           this,
                                           state,
                                           true);
        }
      }
    }
    finally
    {
      setRowKey(oldPath);
    }
  }

  @Override
  protected boolean visitChildren(
    VisitContext  visitContext,
    VisitCallback callback)
  {
    // need to override to do the default since our superclass
    // UIXTree does stuff here we don't want
    return defaultVisitChildren(visitContext, callback);
  }

  @Override
  protected boolean visitUnstampedFacets(
    VisitContext  visitContext,
    VisitCallback callback)
  {
    // Visit the facets except for the node stamp
    int facetCount = getFacetCount();
   
    if (facetCount > 0)
    {
      UIComponent nodeStamp = getNodeStamp();
     
      // if our only facet is the node stamp, we don't need to do this
      if ((facetCount > 1) || (nodeStamp == null))
      {
        for (UIComponent facet : getFacets().values())
        {
          // ignore the nodeStamp facet, since it is stamped
          if (facet != nodeStamp)
          {
            if (UIXComponent.visitTree(visitContext, facet, callback))
            {
              return true;
            }
          }
        }
      }
    }

    return false;
  }

  @Override
  protected boolean visitData(
    VisitContext  visitContext,
    VisitCallback callback)
  {
    Object focusedPath = getFocusRowKey();
    Object oldRowKey = null;
   
    // start from the focused area
    if (focusedPath != null)
    {
      oldRowKey = getRowKey();
      setRowKey(focusedPath);
    }
   
    boolean done;
   
    try
    {
      done = super.visitData(new NoColumnFacetsVisitContext(visitContext), callback);
    }
    finally
    {
      if (focusedPath != null)
      {
        setRowKey(oldRowKey);
      }
    }
   
    return done;
  }

  /**
   * Gets the path of the parent
   */
  private Object _getContainerPath()
  {
    Object parentKey = getTreeModel().getContainerRowKey();
    return parentKey;
  }

  /**
   * Is target a stamped child UIComponent in the treeTable body
   */
  private boolean _isStampedChild(UIComponent target)
  {
    assert _containerClientIdCache != null;
    return !_containerClientIdCache.containsKey(target);
  }

  /**
   * Reset the cache of child components used in getContainerClientId
   */
  private void _resetContainerClientIdCache()
  {
    if(_containerClientIdCache == null)
      _containerClientIdCache = new IdentityHashMap<UIComponent, Boolean>();
    else
      _containerClientIdCache.clear();

    // cache treeTable header/footer items
    TableUtils.cacheHeaderFooterFacets(this, _containerClientIdCache);
    // cache child column header/footer items, including nested columns
    TableUtils.cacheColumnHeaderFooterFacets(this, _containerClientIdCache);

    UIComponent nodeStamp = getNodeStamp();
    if(nodeStamp != null)
    {
      // cache nodeStamp header/footer items
      TableUtils.cacheHeaderFooterFacets(nodeStamp, _containerClientIdCache);
      // cache any nested columns in nodeStamp facet
      TableUtils.cacheColumnHeaderFooterFacets(nodeStamp, _containerClientIdCache);     
    }
  }

  /**
   * Gets the internal state of this component.
   */
  @Override
  Object __getMyStampState()
  {
    Object[] state = new Object[2];
    state[0] = super.__getMyStampState();
    state[1] = (_firstMap.isEmpty()) ? null : _firstMap;

    return state;
  }
 
  /**
   * Sets the internal state of this component.
   * @param stampState the internal state is obtained from this object.
   */
  @Override
  @SuppressWarnings("unchecked")
  void __setMyStampState(Object stampState)
  {
    Object[] state = (Object[]) stampState;
    super.__setMyStampState(state[0]);
    _firstMap = (Map<Object, Integer>) state[1];
    if (_firstMap == null)
      _firstMap = Collections.emptyMap();
  }

  @Override
  void __resetMyStampState()
  {
    super.__resetMyStampState();
    _firstMap = Collections.emptyMap();
  }
 
  private Map<Object, Integer> _firstMap = Collections.emptyMap();
  // cache of child components inside this treeTable header/footer facets and column header/footer
  // facets
  transient private IdentityHashMap<UIComponent, Boolean> _containerClientIdCache = null;

  /**
   * Gets If the root node should be rendered or not. Defaults to true.
   *
   * @return  the new rootNodeRendered value
   */
  final public boolean isRootNodeRendered()
  {
    return ComponentUtils.resolveBoolean(getProperty(ROOT_NODE_RENDERED_KEY), true);
  }

  /**
   * Sets If the root node should be rendered or not. Defaults to true.
   *
   * @param rootNodeRendered  the new rootNodeRendered value
   */
  final public void setRootNodeRendered(boolean rootNodeRendered)
  {
    setProperty(ROOT_NODE_RENDERED_KEY, rootNodeRendered ? Boolean.TRUE : Boolean.FALSE);
  }

  /**
   * Gets the maximum number of records that can be displayed at
   *               one time (range size).
   *               Each level of depth in the tree can have a different range size.
   *               The first number in the array sets the range size for the root
   *               collection. Each subsequent number sets the range size for the
   *               corresponding depth. The last number becomes the default for
   *               each subsequent level of depth.
   *
   *               If a node has more children than
   *               the range size, navigation rows will be rendered above and
   *               below the child nodes.
   *
   * @return  the new rowsByDepth value
   */
  final public int[] getRowsByDepth()
  {
    return (int[])getProperty(ROWS_BY_DEPTH_KEY);
  }

  /**
   * Sets the maximum number of records that can be displayed at
   *               one time (range size).
   *               Each level of depth in the tree can have a different range size.
   *               The first number in the array sets the range size for the root
   *               collection. Each subsequent number sets the range size for the
   *               corresponding depth. The last number becomes the default for
   *               each subsequent level of depth.
   *
   *               If a node has more children than
   *               the range size, navigation rows will be rendered above and
   *               below the child nodes.
   *
   * @param rowsByDepth  the new rowsByDepth value
   */
  final public void setRowsByDepth(int[] rowsByDepth)
  {
    setProperty(ROWS_BY_DEPTH_KEY, (rowsByDepth));
  }

  /**
   * Gets a method reference to a rangeChange listener that
   *          will be called when a new range is selected.
   *
   * @return  the new rangeChangeListener value
   */
  final public MethodExpression getRangeChangeListener()
  {
    return (MethodExpression)getProperty(RANGE_CHANGE_LISTENER_KEY);
  }

  /**
   * Sets a method reference to a rangeChange listener that
   *          will be called when a new range is selected.
   *
   * @param rangeChangeListener  the new rangeChangeListener value
   */
  final public void setRangeChangeListener(MethodExpression rangeChangeListener)
  {
    setProperty(RANGE_CHANGE_LISTENER_KEY, (rangeChangeListener));
  }

  @Override
  public String getFamily()
  {
    return COMPONENT_FAMILY;
  }

  @Override
  protected FacesBean.Type getBeanType()
  {
    return TYPE;
  }

  /**
   * Construct an instance of the UIXTreeTable.
   */
  protected UIXTreeTable(
    String rendererType
    )
  {
    super(rendererType);
  }

  static
  {
    TYPE.lockAndRegister("org.apache.myfaces.trinidad.TreeTable","org.apache.myfaces.trinidad.BaseTreeTable");
  }
}
TOP

Related Classes of org.apache.myfaces.trinidad.component.UIXTreeTable

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.