You are viewing a plain text version of this content. The canonical link for it is here.
Posted to adffaces-commits@incubator.apache.org by aw...@apache.org on 2006/12/15 23:04:44 UTC

svn commit: r487705 - in /incubator/adffaces/trunk/trinidad: trinidad-build/src/main/resources/META-INF/maven-faces-plugin/renderers/trinidad/ trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/xhtml/

Author: awiner
Date: Fri Dec 15 15:04:43 2006
New Revision: 487705

URL: http://svn.apache.org/viewvc?view=rev&rev=487705
Log:
Add Faces-major version of TreeRenderer.  Haven't deleted the old one yet.

Added:
    incubator/adffaces/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/xhtml/TreeRenderer.java
Modified:
    incubator/adffaces/trunk/trinidad/trinidad-build/src/main/resources/META-INF/maven-faces-plugin/renderers/trinidad/Tree.xml
    incubator/adffaces/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/xhtml/SkinSelectors.java

Modified: incubator/adffaces/trunk/trinidad/trinidad-build/src/main/resources/META-INF/maven-faces-plugin/renderers/trinidad/Tree.xml
URL: http://svn.apache.org/viewvc/incubator/adffaces/trunk/trinidad/trinidad-build/src/main/resources/META-INF/maven-faces-plugin/renderers/trinidad/Tree.xml?view=diff&rev=487705&r1=487704&r2=487705
==============================================================================
--- incubator/adffaces/trunk/trinidad/trinidad-build/src/main/resources/META-INF/maven-faces-plugin/renderers/trinidad/Tree.xml (original)
+++ incubator/adffaces/trunk/trinidad/trinidad-build/src/main/resources/META-INF/maven-faces-plugin/renderers/trinidad/Tree.xml Fri Dec 15 15:04:43 2006
@@ -21,7 +21,7 @@
     <renderer>
       <component-family>org.apache.myfaces.trinidad.Tree</component-family>
       <renderer-type>org.apache.myfaces.trinidad.Tree</renderer-type>
-      <renderer-class>org.apache.myfaces.trinidadinternal.renderkit.uix.TreeRenderer</renderer-class>
+      <renderer-class>org.apache.myfaces.trinidadinternal.renderkit.core.xhtml.TreeRenderer</renderer-class>
       <renderer-extension>
         <mfp:component-type>org.apache.myfaces.trinidad.CoreTree</mfp:component-type>
         <mfp:unsupported-agents>phone voice</mfp:unsupported-agents>

Modified: incubator/adffaces/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/xhtml/SkinSelectors.java
URL: http://svn.apache.org/viewvc/incubator/adffaces/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/xhtml/SkinSelectors.java?view=diff&rev=487705&r1=487704&r2=487705
==============================================================================
--- incubator/adffaces/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/xhtml/SkinSelectors.java (original)
+++ incubator/adffaces/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/xhtml/SkinSelectors.java Fri Dec 15 15:04:43 2006
@@ -1217,7 +1217,22 @@
      "af|treeTable::prev-disabled-icon";
    public static final String AF_TREE_TABLE_NB_NEXT_DISABLED_ICON_NAME =
      "af|treeTable::next-disabled-icon";
-     
+
+
+  //                                                                         //
+  //                                                                         //
+  // ============================== tr:tree =============================== //
+  //                                                                         //
+  //
+  public static final String TREE_NODE_ADJUST_STYLE_CLASS = 
+    "p_OraTreeNodeAdjust";
+  public static final String TREE_ROW_STYLE_CLASS = "p_OraTreeRow";
+  public static final String TREE_ROW_SELECTED_STYLE_CLASS = 
+    "p_OraTreeRowSelected";
+  public static final String TREE_ICON_STYLE_CLASS = "p_OraTreeIcon";
+  public static final String TREE_DISCLOSED_SYMBOL_STYLE_CLASS = 
+    "p_OraTreeDisclosedSymbol";
+
   //                                                                         //
   //                                                                         //
   // ============================== tr:chart =============================== //

Added: incubator/adffaces/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/xhtml/TreeRenderer.java
URL: http://svn.apache.org/viewvc/incubator/adffaces/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/xhtml/TreeRenderer.java?view=auto&rev=487705
==============================================================================
--- incubator/adffaces/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/xhtml/TreeRenderer.java (added)
+++ incubator/adffaces/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/xhtml/TreeRenderer.java Fri Dec 15 15:04:43 2006
@@ -0,0 +1,851 @@
+/*
+ * Copyright  2000-2006 The Apache Software Foundation.
+ *
+ * Licensed 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.trinidadinternal.renderkit.core.xhtml;
+
+import java.io.IOException;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.faces.component.NamingContainer;
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+import javax.faces.context.ResponseWriter;
+
+import org.apache.myfaces.trinidad.bean.FacesBean;
+import org.apache.myfaces.trinidad.bean.PropertyKey;
+import org.apache.myfaces.trinidad.component.UIXHierarchy;
+import org.apache.myfaces.trinidad.component.UIXTree;
+import org.apache.myfaces.trinidad.component.core.data.CoreTree;
+import org.apache.myfaces.trinidad.context.Agent;
+import org.apache.myfaces.trinidad.context.FormData;
+import org.apache.myfaces.trinidad.context.RequestContext;
+import org.apache.myfaces.trinidad.logging.TrinidadLogger;
+import org.apache.myfaces.trinidad.model.RowKeySet;
+
+import org.apache.myfaces.trinidad.context.RenderingContext;
+import org.apache.myfaces.trinidadinternal.renderkit.core.xhtml.table.TreeUtils;
+
+/**
+ * Renderer for trees. 
+ *
+ * @author The Oracle ADF Faces Team
+ */
+public class TreeRenderer extends XhtmlRenderer
+{
+  public TreeRenderer()
+  {
+    this(CoreTree.TYPE);
+  }
+
+  protected TreeRenderer(FacesBean.Type type)
+  {
+    super(type);
+  }
+
+  @Override
+  protected void findTypeConstants(FacesBean.Type type)
+  {
+    super.findTypeConstants(type);
+    _immediateKey = type.findKey("immediate");
+  }
+
+  @Override
+  public boolean getRendersChildren()
+  {
+    return true;
+  }
+
+  /**
+   * @todo do not mess with selection here. queue an event.
+   */
+  @SuppressWarnings("unchecked")
+  @Override
+  public void decode(FacesContext context, UIComponent component)
+  {
+    Map<String, String> parameters =
+      context.getExternalContext().getRequestParameterMap();
+    String source = parameters.get(XhtmlConstants.SOURCE_PARAM);
+
+    if (!component.getClientId(context).equals(source))
+      return;
+
+    TreeUtils.decodeExpandEvents(parameters, component, 
+                                 Collections.emptyList());
+    String currencyStrParam = 
+      source + NamingContainer.SEPARATOR_CHAR + SELECTED_PARAM;
+    String currencyStr = parameters.get(currencyStrParam);
+    if ((currencyStr != null) && (!"".equals(currencyStr)))
+    {
+      UIXTree tree = (UIXTree) component;
+      Object oldPath = tree.getRowKey();
+      tree.setClientRowKey(currencyStr);
+      tree.getSelectedRowKeys().clear();
+      tree.getSelectedRowKeys().add();
+      tree.setRowKey(oldPath);
+    }
+
+    RequestContext.getCurrentInstance().addPartialTarget(component);
+  }
+
+  @Override
+  protected void encodeAll(
+    FacesContext     context,
+    RenderingContext rc,    
+    UIComponent      component,
+    FacesBean        bean) throws IOException
+  {
+    UIXHierarchy tree = (UIXHierarchy) component;
+    TreeUtils.expandFocusRowKey((UIXTree) component);
+
+    Object oldPath = tree.getRowKey();
+    try
+    {
+      boolean continueRendering = setInitialPath(tree, bean);
+      if (!continueRendering)
+        return;
+
+      _renderContent(context, rc, tree, bean);
+    }
+    finally
+    {
+      tree.setRowKey(oldPath);
+    }
+  }
+
+  protected boolean shouldRenderId(FacesContext context,
+                                   UIComponent component)
+  {
+    return true;
+  }
+  
+  private void _renderContent(FacesContext context,
+                              RenderingContext rc,
+                              UIXHierarchy tree,
+                              FacesBean bean)
+    throws IOException
+  {
+    FormData fd = rc.getFormData();
+    if (fd == null)
+    {
+      _LOG.warning("The tree component must be used inside of a form.");
+      return;
+    }
+
+    ResponseWriter rw = context.getResponseWriter();
+    rw.startElement("div", tree);
+    renderId(context, tree);
+    renderAllAttributes(context, rc, bean);
+    
+    final String id = getClientId(context, tree);
+    UIComponent stamp = getFacet(tree, CoreTree.NODE_STAMP_FACET);
+
+    //@todo - will this tree.getFocusPath survive?
+    //    List focusPath = getFocusPath(context, node);
+    Object focusPath = tree.getFocusRowKey();
+    String formName = fd.getName();
+
+    // Bug 3931544:  don't use colons in Javascript variable names.
+    // We'll just replace colons with underscores;  not perfect, but adequate
+    final String varName = "_adftree" + XhtmlUtils.getJSIdentifier(id);
+
+    boolean leftToRight = !rc.isRightToLeft();
+    int rootSize = tree.getRowCount();
+    RowKeySet state = getExpandedRowKeys(tree);
+    Map<Object, Boolean> selectedPaths = getSelectedPaths(focusPath);
+
+    // render each of the root nodes
+    for (int i = 0; i < rootSize; i++)
+    {
+      tree.setRowIndex(i);
+      _renderNode(context, rc, tree, bean, stamp, varName, state, 
+                  selectedPaths, new Boolean[_DEFAULT_TREE_DEPTH], 
+                  leftToRight, (i == 0), (i == rootSize - 1), 0);
+    }
+
+    rw.startElement("script", null);
+    renderScriptDeferAttribute(context, rc);
+    renderScriptTypeAttribute(context, rc);
+
+    _renderTreeJS(context, rc, bean);
+
+    //out.writeText("_setNodes('"+name+"','"+nodesRendered+"');");
+
+    String selectedParam = 
+      id + NamingContainer.SEPARATOR_CHAR + SELECTED_PARAM;
+
+    rw.writeText("var " + varName + " = " + 
+                     _createNewJSSelectionState(formName, id, 
+                                                selectedParam), null);
+    rw.endElement("script");
+    rw.endElement("div");
+    
+    fd.addNeededValue(selectedParam);
+    fd.addNeededValue(_PATH_PARAM);
+
+
+  }
+
+
+  // return whether to continue with rendering
+
+  protected boolean setInitialPath(UIXHierarchy tree, FacesBean bean)
+  {
+    tree.setRowKey(null);
+    return true;
+  }
+
+
+  private boolean _isShownSelected(UIXHierarchy tree, 
+                                   Map<Object, Boolean> selectedPaths, 
+                                   Object currPath)
+  {
+
+    boolean selected = false;
+    if (tree instanceof UIXTree)
+      selected = ((UIXTree) tree).getSelectedRowKeys().isContained();
+
+    if (selected)
+      return true;
+
+    Object value = selectedPaths.get(currPath);
+
+    if (value != null)
+      return true;
+
+    return false;
+  }
+
+  protected Map<Object, Boolean> getSelectedPaths(Object focusPath)
+  {
+    if (focusPath == null)
+      return new HashMap<Object, Boolean>(0);
+
+    Map<Object, Boolean> selectedPaths = new HashMap<Object, Boolean>(1);
+
+    selectedPaths.put(focusPath, Boolean.TRUE);
+    return selectedPaths;
+  }
+
+  protected RowKeySet getExpandedRowKeys(UIXHierarchy tree)
+  {
+    return ((UIXTree) tree).getDisclosedRowKeys();
+  }
+
+  protected String getConnectingBackgroundIcon(boolean isLine, 
+                                               boolean leftToRight)
+  {
+    return null;
+  }
+
+  protected String getIconBackgroundIcon(int expand, boolean isLeftToRight)
+  {
+    return null;
+  }
+
+
+  // render the correct icon for a specific node
+
+  protected void renderExpandCell(FacesContext context, 
+                                  RenderingContext rc,
+                                  int expanded, String onclick)
+    throws IOException
+  {
+
+
+    Object altText = null;
+
+    String text = null;
+
+    boolean isMacOS = rc.getAgent().getPlatformName().equals(Agent.PLATFORM_MACOS);
+    // add in the expandability
+    switch (expanded)
+    {
+      case NO_CHILDREN:
+        break;
+      case EXPAND_CLOSED:
+        // "\u21D2"; // Double Arrow right
+
+        if (isMacOS)
+          // single arrow left
+          text = 
+            rc.isRightToLeft()? "\u2190": "\u2192"; // single arrow right
+        else // triangle left
+          text = 
+            rc.isRightToLeft()? "\u25C4": "\u25BA"; // triangle right
+        altText = rc.getTranslatedString(_EXPAND_TIP_KEY);
+        break;
+      case EXPAND_OPEN:
+        //"\u21D3"; // double arrow down
+        if (isMacOS)
+          text = "\u2193"; // single arrow down
+        else
+          text = "\u25BC"; // triangle down
+        altText = rc.getTranslatedString(_COLLAPSE_TIP_KEY);
+        break;
+      case EXPAND_ALWAYS:
+        if (isMacOS)
+          text = "\u2193"; // single arrow down
+        else
+          text = "\u25BC"; // triangle down
+        altText = rc.getTranslatedString(_DISABLED_COLLAPSE_TIP_KEY);
+        break;
+    }
+
+    _renderTextCell(context, rc, text, altText, _ICON_WIDTH, onclick, 
+                    SkinSelectors.TREE_DISCLOSED_SYMBOL_STYLE_CLASS);
+
+  }
+
+
+  private void _renderTextCell(FacesContext context,
+                               RenderingContext rc,
+                               String text, 
+                               Object altText, String width, 
+                               String onclick, String styleClass)
+    throws IOException
+  {
+    ResponseWriter writer = context.getResponseWriter();
+
+    writer.startElement(XhtmlConstants.TABLE_DATA_ELEMENT, null);
+    writer.writeAttribute(XhtmlConstants.WIDTH_ATTRIBUTE, width, null);
+    writer.writeAttribute("title", altText, null);
+    renderStyleClass(context, rc, styleClass);
+
+    if (onclick != null)
+    {
+      writer.startElement(XhtmlConstants.LINK_ELEMENT, null);
+      writer.writeAttribute(XhtmlConstants.HREF_ATTRIBUTE, "#", null);
+      writer.writeAttribute(XhtmlConstants.ONCLICK_ATTRIBUTE, onclick, null);
+    }
+
+    writer.writeText(text, null);
+
+    if (onclick != null)
+    {
+      writer.endElement(XhtmlConstants.LINK_ELEMENT);
+    }
+
+    writer.endElement(XhtmlConstants.TABLE_DATA_ELEMENT);
+  }
+
+
+  protected void renderIconCell(FacesContext context, RenderingContext rc,
+                                UIXHierarchy tree, String backgroundIcon, 
+                                String icon, boolean isIconAbsoluteURI, 
+                                Object altText, String width, 
+                                String height, String onclick)
+    throws IOException
+  {
+    ResponseWriter writer = context.getResponseWriter();
+
+    writer.startElement(XhtmlConstants.TABLE_DATA_ELEMENT, null);
+    writer.writeAttribute(XhtmlConstants.WIDTH_ATTRIBUTE, width, null);
+
+    if (backgroundIcon != null)
+    {
+      String backgroundIconURI = getAbsoluteImageUri(context, rc, backgroundIcon);
+      writer.writeAttribute(XhtmlConstants.STYLE_ATTRIBUTE, 
+                            _BACKGROUND_IMAGE_URL + backgroundIconURI + 
+                            _END_FUNC, null);
+    }
+
+    if (onclick != null)
+    {
+      writer.startElement(XhtmlConstants.LINK_ELEMENT, null);
+      writer.writeAttribute(XhtmlConstants.HREF_ATTRIBUTE, "#", null);
+      writer.writeAttribute(XhtmlConstants.ONCLICK_ATTRIBUTE, onclick, null);
+      String treeName = getClientId(context, tree);
+      String id = treeName + NamingContainer.SEPARATOR_CHAR + "lnk";
+      writer.writeAttribute(XhtmlConstants.ID_ATTRIBUTE, id, null);
+    }
+
+    _renderIcon(context, rc, icon, isIconAbsoluteURI, altText, width, height);
+
+    if (onclick != null)
+    {
+      writer.endElement(XhtmlConstants.LINK_ELEMENT);
+    }
+
+    writer.endElement(XhtmlConstants.TABLE_DATA_ELEMENT);
+  }
+
+
+  private static String _createNewJSSelectionState(String formName, 
+                                                   String treeClientId, 
+                                                   String selectParam)
+  {
+    return "new _adfTreeSelector('" + selectParam + "'," + 
+      TreeUtils.createNewJSCollectionComponentState(formName, 
+                                                    treeClientId) + ");";
+  }
+
+  private static String _callJSSelect(UIXHierarchy tree, String jsVarName)
+  {
+    String currencyStr = tree.getClientRowKey();
+    return jsVarName + ".select(this,'" + currencyStr + "');";
+  }
+
+  private void _renderTreeJS(FacesContext context,
+                             RenderingContext rc,
+                             FacesBean bean)
+    throws IOException
+  {
+    if (!rc.getProperties().containsKey(_JS_RENDERED_KEY))
+    {
+      rc.getProperties().put(_JS_RENDERED_KEY, Boolean.TRUE);
+      ResponseWriter writer = context.getResponseWriter();
+      writer.writeText("function _adfTreeSelector(selectParam,tState) {" + 
+                       "this._selectParam = selectParam;" + 
+                       "this._pTag = null;" + "this.treeState = tState;" + 
+                       "}" + 
+                       "_adfTreeSelector.prototype.select = function(tag,path) {" + 
+                       "if (this._pTag != null) {" + 
+                       "this._pTag.className='" + SkinSelectors.TREE_ROW_STYLE_CLASS + 
+                       "';" + "}" + "this._pTag = tag;" + 
+                       "document.forms[this.treeState.getFormName()][this._selectParam].value=path;" + 
+                       "tag.className='" + SkinSelectors.TREE_ROW_SELECTED_STYLE_CLASS + 
+                       "';" + "};", null);
+
+
+      // _setSelection(..) and _getSelection(..) are called by the
+      // ClientStateTreeDataProxy (if selection is enabled for this particular
+      // tree). _setSelection is called to set the initial selection (as
+      // determined by the proxy). _getSelection is called to get at the
+      // current selection state (to send back to the server by the proxy)
+
+      // @param source the name or ID of the tree
+      // @param sel something that identifies the current selected node
+      // _setSelection(source,sel)
+
+      // @param source the name or ID of the tree
+      // @return something that identifies the current selected node
+      // _getSelection(source)
+
+      //      writer.writeText
+      //        ("var _treeSel = new Object();"  +
+      //         "var _treeNodes = new Object();"  +
+      //         "function _setSelection(source,sel) {"
+      //         + "_treeSel[source]=sel;"  +
+      //         "}"  +
+      //         "function _getSelection(source) {"
+      //         + "return _treeSel[source];"  +
+      //         "}"  +
+      //
+      //         // _setNodes is used to indicate the number of tree nodes that are
+      //         // currently visible. This is so that _clearSelection knows exactly
+      //         // how many elements to clear
+      //         "function _setNodes(source,nodes) {"
+      //         + "_treeNodes[source]=nodes;"  +
+      //         "}"  +
+      //         "function _getNodes(source) {"
+      //         + "return _treeNodes[source];"  +
+      //         "}",
+      //         null  );
+      //
+      //      writer.writeText
+      //        ("function _select(name,index,nodeID) {"
+      //         + "_clearSelection(name);"
+      //         + "var e =_getElementById(document,name+index);"
+      //         + "e.className = '",
+      //         null  );
+      //      writer.writeText(TREE_ROW_SELECTED_STYLE_CLASS+"';", null);
+      //      writer.writeText
+      //        ("  _setSelection(name,nodeID);return true;"  +
+      //         "}",
+      //         null  );
+      //
+      //      writer.writeText
+      //        ("function _clearSelection(name) {"
+      //         + "var sz = _getNodes(name);"
+      //         + "for (var i = 0; i < sz; i++) {"
+      //         +   "var e =_getElementById(document,name+i);"
+      //         +   "e.className='",
+      //         null);
+      //      writer.writeText(TREE_ROW_STYLE_CLASS+"';", null);
+      //      writer.writeText
+      //        ("  }"  +
+      //         "}",
+      //         null);
+
+      boolean immediate = getImmediate(bean);
+      String buff = 
+        TreeUtils.setupJSTreeCollectionComponent(!immediate) + ";";
+      writer.writeText(buff, null);
+    }
+  }
+
+  // render one row of the tree
+
+  private void _renderNode(FacesContext context,
+                           RenderingContext rc,
+                           UIXHierarchy tree, 
+                           FacesBean bean,
+                           UIComponent stamp,
+                           final String varName, 
+                           RowKeySet state, 
+                           Map<Object, Boolean> selectedPaths, 
+                           Boolean[] prepend, boolean leftToRight, 
+                           boolean isFirstSibling, boolean isLastSibling, 
+                           int nodeDepth)
+    throws IOException
+  {
+    ResponseWriter writer = context.getResponseWriter();
+
+    // each row is a table
+    writer.startElement(XhtmlConstants.TABLE_ELEMENT, null);
+    OutputUtils.renderLayoutTableAttributes(context, rc, "0", "0", "0", null);
+    writer.startElement(XhtmlConstants.TABLE_ROW_ELEMENT, null);
+
+
+    // render the prepend
+    _prependIcons(context, rc, tree, prepend, leftToRight);
+
+
+    String onclickExpand = null;
+    int expand = _getExpandValue(tree, state);
+
+    if ((expand != NO_CHILDREN) && supportsNavigation(rc))
+    {
+      onclickExpand = 
+          TreeUtils.callJSExpandNode(tree, varName + ".treeState", 
+                                     (expand == EXPAND_CLOSED));
+    }
+
+    renderExpandCell(context, rc, expand, onclickExpand);
+
+
+    //    DataObject curData = BeanAdapterUtils.getAdapter(context, tree.getRowData());
+    String treeStyle = SkinSelectors.TREE_ROW_STYLE_CLASS;
+
+
+    // location was a colon separated list of IDs
+    //boolean selected = proxy.isSelected(context, node, location);
+    Object currPath = tree.getRowKey();
+    boolean selected = _isShownSelected(tree, selectedPaths, currPath);
+
+    String onClick = _callJSSelect(tree, varName);
+
+    //    if ( proxy.selectionEnabled(context) )
+    //    {
+    //      // selection with the proxy doesn't work on netscape
+    //      // filed as bug 1817185 - so far we have not figured
+    //      // out a way without using layers and we are seeing nodes
+    //      // jump around with layers so disabling selection on netscape
+    //      if ( isNetscape(context) )
+    //        selected = false;
+    //      else
+    //      {
+    //        if (supportsNavigation(context))
+    //          onClick = "return _select('" + treename + "'," + renderedIndex +
+    //            ",'" + location + "');";
+    //      }
+    //    }
+
+    if (selected)
+    {
+      treeStyle = SkinSelectors.TREE_ROW_SELECTED_STYLE_CLASS;
+    }
+
+    // render the icon
+    if (true/*icon != null*/)
+    {
+      String backgroundIcon = getIconBackgroundIcon(expand, leftToRight);
+
+      writer.startElement(XhtmlConstants.TABLE_DATA_ELEMENT, null);
+
+      if (backgroundIcon != null)
+      {
+        String backgroundIconURI = 
+          getAbsoluteImageUri(context, rc, backgroundIcon);
+
+        StringBuffer backgroundStyle = 
+          new StringBuffer(_BACKGROUND_IMAGE_URL.length() + 
+                           backgroundIconURI.length() + 
+                           _END_FUNC.length());
+
+        backgroundStyle.append(_BACKGROUND_IMAGE_URL);
+        backgroundStyle.append(backgroundIconURI);
+        backgroundStyle.append(_END_FUNC);
+
+        writer.writeAttribute(XhtmlConstants.STYLE_ATTRIBUTE, backgroundStyle.toString(), 
+                              null);
+      }
+
+      writer.endElement(XhtmlConstants.TABLE_DATA_ELEMENT);
+
+      // render space between icon and node stamp
+      // alt Text
+      renderIconCell(context, rc, tree, null, TRANSPARENT_GIF, false, null, 
+                     _NODE_SPACER, _ICON_HEIGHT, null);
+    }
+
+    // render the node stamp
+    writer.startElement(XhtmlConstants.TABLE_DATA_ELEMENT, null);
+    writer.writeAttribute(XhtmlConstants.NOWRAP_ATTRIBUTE, Boolean.FALSE, null);
+    renderStyleClass(context, rc, SkinSelectors.TREE_NODE_ADJUST_STYLE_CLASS);
+
+
+    writer.startElement(XhtmlConstants.SPAN_ELEMENT, null);
+    //    out.writeAttribute(ID_ATTRIBUTE,
+    //                       treename + IntegerUtils.getString(renderedIndex));
+    renderStyleClass(context, rc, treeStyle);
+    writer.writeAttribute(XhtmlConstants.ONCLICK_ATTRIBUTE, onClick, null);
+
+    // if screen reader mode render the stamp with level of node from root
+    _renderStampBasedOnAccessibilty(context, rc, stamp, nodeDepth);
+
+    writer.endElement(XhtmlConstants.SPAN_ELEMENT);
+    writer.endElement(XhtmlConstants.TABLE_DATA_ELEMENT);
+
+    // end row
+    writer.endElement(XhtmlConstants.TABLE_ROW_ELEMENT);
+    //end table
+    writer.endElement(XhtmlConstants.TABLE_ELEMENT);
+
+    // render children
+    if ((expand == EXPAND_OPEN) || (expand == EXPAND_ALWAYS))
+    {
+      tree.enterContainer();
+      int childCount = tree.getRowCount();
+
+      if (childCount > 0)
+      {
+        // prepare the prepended icons for the child nodes
+        prepend = 
+            _appendIcon(prepend, (isLastSibling)? Boolean.FALSE: Boolean.TRUE);
+        Boolean[] currClone;
+
+
+        ++nodeDepth; // increment the depth of the child from the root
+
+        int oldIndex = tree.getRowIndex();
+        for (int i = 0; i < childCount; i++)
+        {
+          currClone = new Boolean[prepend.length];
+          System.arraycopy(prepend, 0, currClone, 0, prepend.length);
+
+          tree.setRowIndex(i);
+          _renderNode(context, rc, tree, bean, stamp, varName, state, 
+                      selectedPaths, currClone, leftToRight, false, 
+                      (i == childCount - 1), nodeDepth);
+        }
+        tree.setRowIndex(oldIndex);
+        --nodeDepth;
+      }
+      tree.exitContainer();
+    }
+  }
+
+  // is this row childless, open, or closed?
+
+  private int _getExpandValue(UIXHierarchy tree, RowKeySet state)
+  {
+    if (tree.isContainer())
+    {
+      if (state.isContained())
+        return EXPAND_OPEN;
+      else
+        return EXPAND_CLOSED;
+    }
+
+    return NO_CHILDREN;
+  }
+
+
+  // render an icon with our own special formatting
+
+  private void _renderIcon(FacesContext context, RenderingContext rc, String icon, 
+                           boolean isIconAbsoluteURI, Object text, 
+                           String width, String height)
+    throws IOException
+  {
+    if (icon != null)
+    {
+      ResponseWriter writer = context.getResponseWriter();
+
+      // TODO: change 
+      writer.startElement("img", null);
+      renderStyleClass(context, rc, SkinSelectors.TREE_ICON_STYLE_CLASS);
+      writer.writeAttribute(XhtmlConstants.WIDTH_ATTRIBUTE, width, null);
+      writer.writeAttribute(XhtmlConstants.HEIGHT_ATTRIBUTE, height, null);
+
+      // Convert iconURL to an absolute uri
+      if (!isIconAbsoluteURI)
+        icon = getAbsoluteImageUri(context, rc, icon);
+    
+      renderEncodedResourceURI(context, "src", icon);
+
+      // Ensure that we're never rendering null;  see bug 4161181
+      // why this logic is not in renderAltAndTooltipForImage().
+      // This is, in essence, re-introducing a more restricted version
+      // of that bug.
+      OutputUtils.renderAltAndTooltipForImage(context, rc, text == null? "": text);
+
+      writer.writeAttribute("border", "0", null);
+      writer.endElement("img");
+    }
+  }
+
+
+  // add a boolean flag to the chain of icons.
+  // the chain is rendered before each icon
+
+  private Boolean[] _appendIcon(Boolean[] prepend, Boolean isLine)
+  {
+    int currLength = prepend.length;
+
+    if (prepend[currLength - 1] != null)
+    {
+      // resize, incrementing should be fine
+      Boolean[] newBools = 
+        new Boolean[currLength + _DEFAULT_TREE_INCREMENT];
+      System.arraycopy(prepend, 0, newBools, 0, currLength);
+      prepend = newBools;
+    }
+
+    for (int i = 0; i < currLength; i++)
+    {
+      if (prepend[i] == null)
+      {
+        prepend[i] = isLine;
+        break;
+      }
+    }
+
+    return prepend;
+  }
+
+
+  private void _prependIcons(FacesContext context, RenderingContext rc,
+                             UIXHierarchy tree, Boolean[] prepend, 
+                             boolean leftToRight)
+    throws IOException
+  {
+    int currLength = prepend.length;
+    Boolean isLine;
+
+    for (int i = 0; i < currLength; i++)
+    {
+
+      isLine = prepend[i];
+
+      if (isLine != null)
+      {
+        String icon = TRANSPARENT_GIF;
+
+        String backgroundIcon = 
+          getConnectingBackgroundIcon(isLine.booleanValue(), leftToRight);
+
+        // alt text
+        renderIconCell(context, rc, tree, backgroundIcon, icon, false, null, 
+                       _ICON_WIDTH, _ICON_HEIGHT, null);
+      }
+    }
+
+  }
+
+
+  protected boolean getImmediate(FacesBean bean)
+  {
+    Object o = bean.getProperty(_immediateKey);
+    if (o == null)
+      o = _immediateKey.getDefault();
+
+    return Boolean.TRUE.equals(o);
+  }
+
+
+
+  protected String getDefaultIconName()
+  {
+    return null;
+  }
+
+
+  private void _renderStampBasedOnAccessibilty(FacesContext context,
+                                               RenderingContext rc,
+                                               UIComponent stamp,
+                                               int depth)
+    throws IOException
+  {
+    if (isScreenReaderMode(rc))
+    {
+      RenderingContext arc = RenderingContext.getCurrentInstance();
+      FacesContext fc = FacesContext.getCurrentInstance();
+      if (rc.isRightToLeft())
+      {
+        //TODO: do we need default stamp support???
+        encodeChild(context, stamp);
+        TreeUtils.writeNodeLevel(fc, arc, depth, _NODE_LEVEL_TEXT_KEY);
+      }
+      else
+      {
+        TreeUtils.writeNodeLevel(fc, arc, depth, _NODE_LEVEL_TEXT_KEY);
+        encodeChild(context, stamp);
+      }
+    }
+    else
+      encodeChild(context, stamp);
+  }
+
+  private static final String _BACKGROUND_IMAGE_URL = 
+    "background-image:url(";
+  private static final String _END_FUNC = ");";
+
+  private static final String _ICON_WIDTH = "16";
+  private static final String _ICON_HEIGHT = "22";
+  private static final String _NODE_ICON_HEIGHT = "16";
+  private static final String _NODE_SPACER = "6";
+
+
+  // expanded states
+  protected static final int NO_CHILDREN = 0;
+  protected static final int EXPAND_CLOSED = 1;
+  protected static final int EXPAND_OPEN = 2;
+  protected static final int EXPAND_ALWAYS = 3;
+
+  // prepend chain constants
+  private static final int _DEFAULT_TREE_DEPTH = 10;
+  private static final int _DEFAULT_TREE_INCREMENT = 5;
+
+  // =-= ACW: this key is used to make sure that certain javascript functions
+  // used by this renderer, are rendered only once per render cycle.
+  private static final Object _JS_RENDERED_KEY = new Object();
+
+  // Key used by StyledTextBean to query style class
+  static final String _STYLE_CLASS_KEY = "_styleClass";
+
+
+  private PropertyKey _immediateKey;
+
+  // translation keys
+  private static final String _DISABLED_COLLAPSE_TIP_KEY = 
+    "af_tree.DISABLED_COLLAPSE_TIP";
+  private static final String _COLLAPSE_TIP_KEY = "af_tree.COLLAPSE_TIP";
+  private static final String _EXPAND_TIP_KEY = "af_tree.EXPAND_TIP";
+  private static final String _FOLDER_TIP_KEY = "af_tree.FOLDER_TIP";
+  private static final String _NODE_LEVEL_TEXT_KEY = "af_tree.NODE_LEVEL";
+
+  private static final String _PATH_PARAM = "path";
+  public static final String SELECTED_PARAM = "_selected";
+
+
+  private static final TrinidadLogger _LOG = 
+    TrinidadLogger.createTrinidadLogger(TreeRenderer.class);
+}