You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by de...@apache.org on 2017/09/17 12:30:06 UTC

[myfaces-trinidad] 02/10: Checkpoint

This is an automated email from the ASF dual-hosted git repository.

deki pushed a commit to branch anrobins_1.2.12.3_visitTree_4
in repository https://gitbox.apache.org/repos/asf/myfaces-trinidad.git

commit d135e77a71beefcb3e4323204454e3c3d8f1b96e
Author: Andrew Robinson <ar...@apache.org>
AuthorDate: Fri Jul 16 22:18:43 2010 +0000

    Checkpoint
---
 .../trinidad/component/UIXIteratorTemplate.java    | 359 +++++++++++++++++----
 .../component/UIXNavigationLevelTemplate.java      |  55 +++-
 .../component/UIXNavigationPathTemplate.java       | 103 +++++-
 .../component/UIXNavigationTreeTemplate.java       |  40 +++
 .../trinidad/component/UIXPageTemplate.java        |  87 +++++
 .../trinidad/component/UIXProcessTemplate.java     |  79 ++++-
 .../trinidad/component/UIXShowDetailTemplate.java  |  28 +-
 .../trinidad/component/UIXShowOneTemplate.java     | 100 +++++-
 .../trinidad/component/UIXSwitcherTemplate.java    |  33 +-
 .../trinidad/component/UIXTreeTableTemplate.java   | 101 +++++-
 .../trinidad/component/UIXTreeTemplate.java        |  27 +-
 .../core/layout/CorePanelAccordionTemplate.java    | 110 ++++++-
 .../myfaces/trinidad/component/UIXCollection.java  | 270 +++++++++++++++-
 .../myfaces/trinidad/component/UIXComponent.java   | 229 ++++++++-----
 .../myfaces/trinidad/component/UIXHierarchy.java   | 124 +++++--
 .../component/visit/VisitContextWrapper.java       |  80 +++++
 .../myfaces/trinidad/render/CoreRenderer.java      |  44 ++-
 17 files changed, 1627 insertions(+), 242 deletions(-)

diff --git a/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXIteratorTemplate.java b/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXIteratorTemplate.java
index 7152e2b..de9a83f 100644
--- a/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXIteratorTemplate.java
+++ b/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXIteratorTemplate.java
@@ -6,9 +6,9 @@
  *  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
@@ -21,25 +21,33 @@ package org.apache.myfaces.trinidad.component;
 import java.io.IOException;
 
 import java.util.AbstractMap;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
 import java.util.List;
 
 import java.util.Map;
 import java.util.Set;
 import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
+import javax.faces.event.AbortProcessingException;
 import javax.faces.event.PhaseId;
 
 import javax.faces.render.Renderer;
+
+import org.apache.myfaces.trinidad.component.visit.VisitCallback;
+import org.apache.myfaces.trinidad.component.visit.VisitContext;
 import org.apache.myfaces.trinidad.model.CollectionModel;
 import org.apache.myfaces.trinidad.model.LocalRowKeyIndex;
 import org.apache.myfaces.trinidad.model.ModelUtils;
+import org.apache.myfaces.trinidad.render.ClientRowKeyManager;
 
 /**
  * This component iterates over some given data.
  * Each child is repeatedly stamped as many times as necessary.
  * Iteration is done starting at the index given by {@link #getFirst()}
  * for as many indices as specified by {@link #getRows()}.
- * If {@link #getRows()} returns 0, then the iteration continues until 
+ * If {@link #getRows()} returns 0, then the iteration continues until
  * there are no more elements in the underlying data.
  */
 public abstract class UIXIteratorTemplate extends UIXCollection implements FlattenedComponent, LocalRowKeyIndex
@@ -67,29 +75,41 @@ public abstract class UIXIteratorTemplate extends UIXCollection implements Flatt
     final ComponentProcessor<S> childProcessor,
     final S callbackContext) throws IOException
   {
-    // Mimic what would normally happen in the non-flattening case for encodeBegin():
-    __processFlattenedChildrenBegin();
+    boolean processedChildren;
+
+    setupVisitingContext(context);
 
-    Runner runner = new Runner(cpContext)
+    try
     {
-      @Override
-      protected void process(UIComponent kid, ComponentProcessingContext cpContext) throws IOException
+      // Mimic what would normally happen in the non-flattening case for encodeBegin():
+      __processFlattenedChildrenBegin();
+
+      Runner runner = new IndexedRunner(cpContext)
+      {
+        @Override
+        protected void process(UIComponent kid, ComponentProcessingContext cpContext) throws IOException
+        {
+          childProcessor.processComponent(context, cpContext, kid, callbackContext);
+        }
+      };
+
+      processedChildren = runner.run();
+      Exception exp = runner.getException();
+      if (exp != null)
       {
-        childProcessor.processComponent(context, cpContext, kid, callbackContext);
+        if (exp instanceof RuntimeException)
+          throw (RuntimeException) exp;
+
+        if (exp instanceof IOException)
+          throw (IOException) exp;
+        throw new IllegalStateException(exp);
       }
-    };
-    boolean processedChildren = runner.run();
-    Exception exp = runner.exception;
-    if (exp != null)
+    }
+    finally
     {
-      if (exp instanceof RuntimeException)
-        throw (RuntimeException) exp;
-
-      if (exp instanceof IOException)
-        throw (IOException) exp;
-      throw new IllegalStateException(exp);
+      tearDownVisitingContext(context);
     }
-    
+
     return processedChildren;
   }
 
@@ -125,7 +145,7 @@ public abstract class UIXIteratorTemplate extends UIXCollection implements Flatt
     }
     else // this is not the table. it must be the iterator
     {
-      Runner runner = new Runner()
+      Runner runner = new IndexedRunner()
       {
         @Override
         protected void process(UIComponent kid,
@@ -135,7 +155,7 @@ public abstract class UIXIteratorTemplate extends UIXCollection implements Flatt
         }
       };
       runner.run();
-      Exception exp = runner.exception;
+      Exception exp = runner.getException();
       if (exp != null)
       {
         if (exp instanceof RuntimeException)
@@ -167,7 +187,7 @@ public abstract class UIXIteratorTemplate extends UIXCollection implements Flatt
       public Object get(Object key)
       {
         // some of these keys are from <c:forEach>, ie:
-        // javax.servlet.jsp.jstl.core.LoopTagStatus 
+        // javax.servlet.jsp.jstl.core.LoopTagStatus
         if ("begin".equals(key)) // from jstl
         {
           return Integer.valueOf(getFirst());
@@ -188,7 +208,7 @@ public abstract class UIXIteratorTemplate extends UIXCollection implements Flatt
         }
         return map.get(key);
       }
-    
+
       @Override
       public Set<Map.Entry<String, Object>> entrySet()
       {
@@ -202,7 +222,7 @@ public abstract class UIXIteratorTemplate extends UIXCollection implements Flatt
     CollectionModel current,
     Object value)
   {
-    CollectionModel model = ModelUtils.toCollectionModel(value); 
+    CollectionModel model = ModelUtils.toCollectionModel(value);
     // initialize to -1. we need to do this incase some application logic
     // changed this index. Also, some JSF1.0 RI classes were initially starting
     // with a rowIndex of 0.
@@ -217,7 +237,7 @@ public abstract class UIXIteratorTemplate extends UIXCollection implements Flatt
     final FacesContext context,
     final PhaseId phaseId)
   {
-    Runner runner = new Runner()
+    Runner runner = new IndexedRunner()
     {
       @Override
       protected void process(UIComponent kid, ComponentProcessingContext cpContext)
@@ -227,7 +247,140 @@ public abstract class UIXIteratorTemplate extends UIXCollection implements Flatt
     };
     runner.run();
   }
-  
+
+  // Extract the current row token from the clientId
+  private String _getClientToken(String clientIdPrefix, String cellClientId)
+  {
+    int tokenStartIndex = clientIdPrefix.length() + 1;
+    int tokenEndIndex = cellClientId.indexOf(':', tokenStartIndex);
+
+    if (tokenEndIndex != -1)
+    {
+      return cellClientId.substring(tokenStartIndex, tokenEndIndex);
+    }
+    else
+    {
+      return null;
+    }
+  }
+
+  @Override
+  protected boolean visitData(
+    final VisitContext  visitContext,
+    final VisitCallback visitCallback)
+  {
+    Collection<String> subtreeIds = visitContext.getSubtreeIdsToVisit(this);
+
+    // create a special VisitContext that doesn't visit the Facets
+    // of column components since they aren't visited on each row
+    final VisitContext noColumnFacetContext = new NoColumnFacetsVisitContext(visitContext);
+
+    // runner to use to process the rows
+    Runner runner;
+
+    if (VisitContext.ALL_IDS.equals(subtreeIds))
+    {
+      // we're processing all of the rows, so use the indexed runner (plus, we can't call size() on
+      // the ALL_IDS collection, so we don't have a whole lot of choice here
+      runner = new IndexedRunner()
+      {
+        @Override
+        protected void process(UIComponent kid, ComponentProcessingContext cpContext)
+        {
+          if (kid.getChildCount() > 0)
+          {
+            for (UIComponent grandKid : kid.getChildren())
+            {
+              if (UIXComponent.visitTree(noColumnFacetContext, grandKid, visitCallback))
+              {
+                throw new AbortProcessingException();
+              }
+            }
+          }
+        }
+      };
+    }
+    else
+    {
+      // We are only visiting a subset of the tree, so figure out which rows to visit
+
+      String ourClientIdPrefix = getClientId(visitContext.getFacesContext());
+
+      int subtreeIdCount = subtreeIds.size();
+
+      // build up a set of the row keys to visit rather than iterating
+      // and visiting every row
+      Set<String> rowsToVisit;
+
+      if (subtreeIdCount > 1)
+      {
+        rowsToVisit = new HashSet<String>(subtreeIdCount);
+
+        for (String currClientId : subtreeIds)
+        {
+          String clientToken = _getClientToken(ourClientIdPrefix, currClientId);
+
+          if (clientToken != null)
+          {
+            rowsToVisit.add(clientToken);
+          }
+        }
+      }
+      else
+      {
+        String clientToken = _getClientToken(ourClientIdPrefix,
+                                             subtreeIds.iterator().next());
+
+        if (clientToken != null)
+        {
+          rowsToVisit = Collections.singleton(clientToken);
+        }
+        else
+        {
+          rowsToVisit = Collections.emptySet();
+        }
+      }
+
+      // we didn't visit any data
+      if (rowsToVisit.isEmpty())
+        return false;
+
+      // visit only the rows we need to
+      runner = new KeyedRunner(rowsToVisit)
+      {
+        @Override
+        protected void process(
+          UIComponent                kid,
+          ComponentProcessingContext cpContext
+          ) throws IOException
+        {
+          if (kid.getChildCount() > 0)
+          {
+            for (UIComponent grandKid : kid.getChildren())
+            {
+              if (UIXComponent.visitTree(noColumnFacetContext, grandKid, visitCallback))
+              {
+                throw new AbortProcessingException();
+              }
+            }
+          }
+        }
+      };
+    }
+
+    try
+    {
+      runner.run();
+    }
+    finally
+    {
+      return (runner.getException() instanceof AbortProcessingException);
+    }
+  }
+
+  /**
+   * Abstract class for processing rows
+   */
   private abstract class Runner implements ComponentProcessor<Object>
   {
     public Runner()
@@ -239,11 +392,81 @@ public abstract class UIXIteratorTemplate extends UIXCollection implements Flatt
     {
       _cpContext = cpContext;
     }
-    
+
+    public abstract boolean run();
+
+    /**
+     * Sets up the context for the child and processes it
+     */
+    public void processComponent(
+      FacesContext context,
+      ComponentProcessingContext cpContext,
+      UIComponent component,
+      Object callbackContext) throws IOException
+    {
+      try
+      {
+        process(component, cpContext);
+      }
+      catch (IOException ioe)
+      {
+        throw ioe;
+      }
+      catch (AbortProcessingException ape)
+      {
+        // we're done, so abort
+        _exception = ape;
+        throw ape;
+      }
+      catch (Exception e)
+      {
+        _exception = e;
+      }
+    }
+
+    public Exception getException()
+    {
+      return _exception;
+    }
+
+    protected abstract void process(UIComponent comp, ComponentProcessingContext cpContext)
+      throws Exception;
+
+    protected final ComponentProcessingContext getComponentProcessingContext()
+    {
+      return _cpContext;
+    }
+
+    public final void setException(Exception e)
+    {
+      _exception = e;
+    }
+
+    private Exception _exception = null;
+
+    private final ComponentProcessingContext _cpContext;
+  }
+
+  /**
+   * Class for visiting getRows() by index rows starting getFirst()
+   */
+  private abstract class IndexedRunner extends Runner
+  {
+    public IndexedRunner()
+    {
+      this(null);
+    }
+
+    public IndexedRunner(ComponentProcessingContext cpContext)
+    {
+      super(cpContext);
+    }
+
     public final boolean run()
     {
       FacesContext context = FacesContext.getCurrentInstance();
-      
+      ComponentProcessingContext cpContext = getComponentProcessingContext();
+
       List<UIComponent> stamps = getStamps();
       int oldIndex = getRowIndex();
       int first = getFirst();
@@ -251,9 +474,9 @@ public abstract class UIXIteratorTemplate extends UIXCollection implements Flatt
       int end = (rows <= 0) //show everything
         ? Integer.MAX_VALUE
         : first + rows;
-      
+
       boolean processedChild = false;
-      
+
       try
       {
         for(int i=first; i<end; i++)
@@ -262,8 +485,8 @@ public abstract class UIXIteratorTemplate extends UIXCollection implements Flatt
           if (isRowAvailable())
           {
             // latch processedChild the first time we process a child
-            processedChild |= (_cpContext != null)
-              ? UIXComponent.processFlattenedChildren(context, _cpContext, this, stamps, null)
+            processedChild |= (cpContext != null)
+              ? UIXComponent.processFlattenedChildren(context, cpContext, this, stamps, null)
               : UIXComponent.processFlattenedChildren(context, this, stamps, null);
           }
           else
@@ -272,45 +495,70 @@ public abstract class UIXIteratorTemplate extends UIXCollection implements Flatt
       }
       catch (IOException e)
       {
-        exception = e;
+        setException(e);
       }
       finally
       {
         setRowIndex(oldIndex);
       }
-      
+
       return processedChild;
     }
+  }
 
-    /**
-     * Sets up the context for the child and processes it
-     */
-    public void processComponent(
-      FacesContext context,
-      ComponentProcessingContext cpContext,
-      UIComponent component,
-      Object callbackContext) throws IOException
+  /**
+   * Runner that visits the rows specified by the client row key tokens
+   */
+  private abstract class KeyedRunner extends Runner
+  {
+    public KeyedRunner(Iterable<String> clientKeys)
+    {
+      super();
+      _clientKeys = clientKeys;
+    }
+
+    public final boolean run()
     {
+      FacesContext context = FacesContext.getCurrentInstance();
+
+      List<UIComponent> stamps = getStamps();
+      int oldIndex = getRowIndex();
+
+      boolean processedChild = false;
+
       try
       {
-        process(component, cpContext);
+        // need to convert row key tokens to row keys
+        ClientRowKeyManager rowKeyManager = getClientRowKeyManager();
+
+        for(String clientKey : _clientKeys)
+        {
+          Object rowKey = rowKeyManager.getRowKey(context, UIXIterator.this, clientKey);
+
+          if (rowKey != null)
+          {
+            setRowKey(rowKey);
+            if (isRowAvailable())
+            {
+              // latch processedChild the first time we process a child
+              processedChild |= UIXComponent.processFlattenedChildren(context, this, stamps, null);
+            }
+          }
+        }
       }
-      catch (IOException ioe)
+      catch (IOException e)
       {
-        throw ioe;
+        setException(e);
       }
-      catch (Exception e)
+      finally
       {
-        exception = e;
+        setRowIndex(oldIndex);
       }
-    }
 
-    protected abstract void process(UIComponent comp, ComponentProcessingContext cpContext)
-      throws Exception;
-
-    public Exception exception = null;
+      return processedChild;
+    }
 
-    private final ComponentProcessingContext _cpContext;
+    private final Iterable<String> _clientKeys;
   }
 
   @Override
@@ -355,7 +603,7 @@ public abstract class UIXIteratorTemplate extends UIXCollection implements Flatt
           first = 0;
         else
         {
-          // scroll to the last page: 
+          // scroll to the last page:
           first = size - rows;
           model.setRowIndex(first);
           // make sure the row is indeed available:
@@ -375,5 +623,4 @@ public abstract class UIXIteratorTemplate extends UIXCollection implements Flatt
       model.setRowIndex(oldIndex);
     }
   }
-
 }
diff --git a/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXNavigationLevelTemplate.java b/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXNavigationLevelTemplate.java
index e40e606..8577f8c 100644
--- a/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXNavigationLevelTemplate.java
+++ b/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXNavigationLevelTemplate.java
@@ -6,9 +6,9 @@
  *  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
@@ -18,16 +18,21 @@
  */
 package org.apache.myfaces.trinidad.component;
 
+import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import javax.faces.event.PhaseId;
 
+import org.apache.myfaces.trinidad.component.visit.VisitCallback;
+import org.apache.myfaces.trinidad.component.visit.VisitContext;
+
 
 /**
  * Base class for the NavigationLevel component.
  *
  * @version $Name:  $ ($Revision$) $Date$
  */
-abstract public class UIXNavigationLevelTemplate extends UIXNavigationHierarchy
+abstract public class UIXNavigationLevelTemplate
+  extends UIXNavigationHierarchy
 {
 /**/ // Abstract methods implemented by code gen
 /**/  abstract public int getLevel();
@@ -48,8 +53,52 @@ abstract public class UIXNavigationLevelTemplate extends UIXNavigationHierarchy
     TableUtils.__processChildren(context, this, phaseId);
   }
 
+  @Override
+  protected boolean visitChildren(
+    VisitContext  visitContext,
+    VisitCallback callback)
+  {
+    boolean done = visitData(visitContext, callback);
+
+    if (!done)
+    {
+      // process the children
+      int childCount = getChildCount();
+      if (childCount > 0)
+      {
+        for (UIComponent child : getChildren())
+        {
+          done = UIXComponent.visitTree(visitContext, child, callback);
+
+          if (done)
+            break;
+        }
+      }
+    }
+
+    return done;
+  }
+
+  @Override
+  protected boolean visitData(
+    VisitContext  visitContext,
+    VisitCallback callback)
+  {
+    Object oldKey = getRowKey();
 
+    boolean done;
 
+    HierarchyUtils.__setStartDepthPath(this, getLevel());
 
+    try
+    {
+      done = visitLevel(visitContext, callback, getStamps());
+    }
+    finally
+    {
+      setRowKey(oldKey);
+    }
 
+    return done;
+  }
 }
diff --git a/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXNavigationPathTemplate.java b/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXNavigationPathTemplate.java
index 10c7d23..bf599b9 100644
--- a/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXNavigationPathTemplate.java
+++ b/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXNavigationPathTemplate.java
@@ -6,9 +6,9 @@
  *  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
@@ -25,33 +25,36 @@ import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import javax.faces.event.PhaseId;
 
+import org.apache.myfaces.trinidad.component.visit.VisitCallback;
+import org.apache.myfaces.trinidad.component.visit.VisitContext;
+
 
 /**
  * Base class for the NavigationPath component.
  *
  * @version $Name:  $ ($Revision$) $Date$
  */
-abstract public class UIXNavigationPathTemplate extends UIXNavigationHierarchy
+abstract public class UIXNavigationPathTemplate
+  extends UIXNavigationHierarchy
 {
-	
   @Override
   protected void processFacetsAndChildren(
     FacesContext context,
-    PhaseId phaseId)
+    PhaseId      phaseId)
   {
     Object oldPath = getRowKey();
-    
+
     Object focusPath = getFocusRowKey();
-    
+
     if (focusPath != null )
     {
-      List<Object> paths = 
+      List<Object> paths =
         new ArrayList<Object>(getAllAncestorContainerRowKeys(focusPath));
-      
+
       paths.add(focusPath);
       int focusPathSize = paths.size();
       UIComponent nodeStamp = getFacet("nodeStamp");
-      
+
       if (nodeStamp != null)
       {
         for (int i = 0; i < focusPathSize; i++)
@@ -61,12 +64,84 @@ abstract public class UIXNavigationPathTemplate extends UIXNavigationHierarchy
         }
       }
     }
-    
+
     setRowKey(oldPath);
-    
+
     // process the children
     TableUtils.__processChildren(context, this, phaseId);
-  }  
+  }
+
+
+  @Override
+  protected boolean visitChildren(
+    VisitContext  visitContext,
+    VisitCallback callback)
+  {
+    boolean done = visitData(visitContext, callback);
+
+    if (!done)
+    {
+      // process the children
+      int childCount = getChildCount();
+      if (childCount > 0)
+      {
+        for (UIComponent child : getChildren())
+        {
+          done = UIXComponent.visitTree(visitContext, child, callback);
+
+          if (done)
+            break;
+        }
+      }
+    }
+
+    return done;
+  }
+
+  @Override
+  protected boolean visitData(
+    VisitContext  visitContext,
+    VisitCallback callback)
+  {
+    Object focusPath = getFocusRowKey();
+    Object oldRowKey = null;
+
+    boolean done = false;
+
+    // start from the focused area
+    if (focusPath != null)
+    {
+      List<UIComponent> stamps = getStamps();
+
+      if (!stamps.isEmpty())
+      {
+        List<Object> paths =  new ArrayList<Object>(getAllAncestorContainerRowKeys(focusPath));
+        paths.add(focusPath);
+
+        int focusPathSize = paths.size();
+
+        try
+        {
+          for (int i = 0; i < focusPathSize && !done; i++)
+          {
+            setRowKey(paths.get(i));
+
+            for (UIComponent stamp : stamps)
+            {
+              done = UIXComponent.visitTree(visitContext, stamp, callback);
+
+              if (done)
+                break;
+            }
+          }
+        }
+        finally
+        {
+          setRowKey(oldRowKey);
+        }
+      }
+    }
 
-    
+    return done;
+  }
 }
diff --git a/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXNavigationTreeTemplate.java b/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXNavigationTreeTemplate.java
index daaf0b8..c890267 100644
--- a/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXNavigationTreeTemplate.java
+++ b/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXNavigationTreeTemplate.java
@@ -29,6 +29,9 @@ import javax.faces.event.PhaseId;
 
 import org.apache.myfaces.trinidad.bean.FacesBean;
 import org.apache.myfaces.trinidad.bean.PropertyKey;
+import org.apache.myfaces.trinidad.component.visit.VisitCallback;
+import org.apache.myfaces.trinidad.component.visit.VisitContext;
+import org.apache.myfaces.trinidad.component.visit.VisitHint;
 import org.apache.myfaces.trinidad.model.CollectionModel;
 import org.apache.myfaces.trinidad.model.RowKeySet;
 import org.apache.myfaces.trinidad.model.RowKeySetTreeImpl;
@@ -103,6 +106,43 @@ abstract public class UIXNavigationTreeTemplate extends UIXNavigationHierarchy
   }
 
   @Override
+  protected boolean visitChildren(
+    VisitContext  visitContext,
+    VisitCallback callback)
+  {
+    return visitData(visitContext, callback);
+  }
+
+  @Override
+  protected boolean visitData(
+    VisitContext  visitContext,
+    VisitCallback callback)
+  {
+    Object oldRowKey = getRowKey();
+
+    // if we are only visiting rendered stamps, then pass in the disclosed row keys, otherwise
+    // pass in null, indicating that all row keys should be visited
+    RowKeySet disclosedRowKeys = (visitContext.getHints().contains(VisitHint.SKIP_UNRENDERED))
+                                   ? getDisclosedRowKeys()
+                                   : null;
+
+    boolean done;
+
+    HierarchyUtils.__setStartDepthPath(this, getStartLevel());
+
+    try
+    {
+      done = visitHierarchy(visitContext, callback, getStamps(), disclosedRowKeys);
+    }
+    finally
+    {
+      setRowKey(oldRowKey);
+    }
+
+    return done;
+  }
+
+  @Override
   void __encodeBegin(FacesContext context) throws IOException
   {
     HierarchyUtils.__handleEncodeBegin(this, getDisclosedRowKeys());
diff --git a/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXPageTemplate.java b/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXPageTemplate.java
index fc79abf..ad45078 100644
--- a/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXPageTemplate.java
+++ b/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXPageTemplate.java
@@ -32,6 +32,9 @@ import javax.faces.event.PhaseId;
 
 import org.apache.myfaces.trinidad.bean.FacesBean;
 import org.apache.myfaces.trinidad.bean.PropertyKey;
+import org.apache.myfaces.trinidad.component.visit.VisitCallback;
+import org.apache.myfaces.trinidad.component.visit.VisitContext;
+import org.apache.myfaces.trinidad.component.visit.VisitHint;
 import org.apache.myfaces.trinidad.model.CollectionModel;
 import org.apache.myfaces.trinidad.model.RowKeySet;
 import org.apache.myfaces.trinidad.model.RowKeySetTreeImpl;
@@ -49,6 +52,7 @@ abstract public class UIXPageTemplate extends UIXMenuHierarchy
 /**/  public abstract void setDisclosedRowKeys(RowKeySet state);
 /**/  public abstract MethodBinding getRowDisclosureListener();
 /**/  static public final PropertyKey DISCLOSED_ROW_KEYS_KEY = null;
+/**/  public abstract UIComponent getNodeStamp();
 
   /**
    * Sets the phaseID of UI events depending on the "immediate" property.
@@ -119,6 +123,89 @@ abstract public class UIXPageTemplate extends UIXMenuHierarchy
   }
 
   @Override
+  protected boolean visitChildren(
+    VisitContext  visitContext,
+    VisitCallback callback)
+  {
+    boolean done = visitData(visitContext, callback);
+
+    if (!done)
+    {
+      // process the children
+      int childCount = getChildCount();
+      if (childCount > 0)
+      {
+        for (UIComponent child : getChildren())
+        {
+          done = UIXComponent.visitTree(visitContext, child, callback);
+
+          if (done)
+            break;
+        }
+      }
+
+      // process the non-stamp facet children
+      if (!done)
+      {
+        // 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))
+                {
+                  done = true;
+                  break;
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+
+    return done;
+  }
+
+  @Override
+  protected boolean visitData(
+    VisitContext  visitContext,
+    VisitCallback callback)
+  {
+    Object oldPath = getRowKey();
+
+    // if we are only visiting rendered stamps, then pass in the disclosed row keys, otherwise
+    // pass in null, indicating that all row keys should be visited
+    RowKeySet disclosedRowKeys = (visitContext.getHints().contains(VisitHint.SKIP_UNRENDERED))
+                                   ? getDisclosedRowKeys()
+                                   : null;
+
+    setRowKey(null);
+
+    boolean done;
+
+    try
+    {
+      done = visitHierarchy(visitContext, callback, getStamps(), disclosedRowKeys);
+    }
+    finally
+    {
+      setRowKey(oldPath);
+    }
+
+    return done;
+  }
+  @Override
   void __encodeBegin(FacesContext context) throws IOException
   {
     HierarchyUtils.__handleEncodeBegin(this, getDisclosedRowKeys());
diff --git a/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXProcessTemplate.java b/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXProcessTemplate.java
index 0169371..9f4bca5 100644
--- a/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXProcessTemplate.java
+++ b/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXProcessTemplate.java
@@ -6,9 +6,9 @@
  *  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
@@ -18,35 +18,86 @@
  */
 package org.apache.myfaces.trinidad.component;
 
+import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import javax.faces.event.PhaseId;
 
+import org.apache.myfaces.trinidad.component.visit.VisitCallback;
+import org.apache.myfaces.trinidad.component.visit.VisitContext;
+
 
 /**
  * Base class for the Process component, which shows the steps of a process.
  *
  * @version $Name:  $ ($Revision$) $Date$
  */
-abstract public class UIXProcessTemplate extends UIXMenuHierarchy
+abstract public class UIXProcessTemplate
+  extends UIXMenuHierarchy
 {
-  
   @Override
   protected void processFacetsAndChildren(
     FacesContext context,
     PhaseId phaseId)
   {
     Object oldPath = getRowKey();
-    Object focusPath = getFocusRowKey();    
-    setRowKey(focusPath);      
-    // process stamp for one level 
-    HierarchyUtils.__processLevel(context, phaseId, this);        
-    setRowKey(oldPath);    
-    
+    Object focusPath = getFocusRowKey();
+    setRowKey(focusPath);
+    // process stamp for one level
+    HierarchyUtils.__processLevel(context, phaseId, this);
+    setRowKey(oldPath);
+
     // process the children
     TableUtils.__processChildren(context, this, phaseId);
-    
-  }  
 
-  
-  
+  }
+
+  @Override
+  protected boolean visitChildren(
+    VisitContext  visitContext,
+    VisitCallback callback)
+  {
+    boolean done = visitData(visitContext, callback);
+
+    if (!done)
+    {
+      // process the children
+      int childCount = getChildCount();
+      if (childCount > 0)
+      {
+        for (UIComponent child : getChildren())
+        {
+          done = UIXComponent.visitTree(visitContext, child, callback);
+
+          if (done)
+            break;
+        }
+      }
+    }
+
+    return done;
+  }
+
+  @Override
+  protected boolean visitData(
+    VisitContext  visitContext,
+    VisitCallback callback)
+  {
+    Object oldKey = getRowKey();
+
+    Object focusPath = getFocusRowKey();
+    setRowKey(focusPath);
+
+    boolean done;
+
+    try
+    {
+      done = visitLevel(visitContext, callback, getStamps());
+    }
+    finally
+    {
+      setRowKey(oldKey);
+    }
+
+    return done;
+  }
 }
diff --git a/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXShowDetailTemplate.java b/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXShowDetailTemplate.java
index fb9b19a..a1069b2 100644
--- a/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXShowDetailTemplate.java
+++ b/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXShowDetailTemplate.java
@@ -6,9 +6,9 @@
  *  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
@@ -25,6 +25,9 @@ import javax.faces.event.AbortProcessingException;
 import javax.faces.event.FacesEvent;
 import javax.faces.event.PhaseId;
 
+import org.apache.myfaces.trinidad.component.visit.VisitCallback;
+import org.apache.myfaces.trinidad.component.visit.VisitContext;
+import org.apache.myfaces.trinidad.component.visit.VisitHint;
 import org.apache.myfaces.trinidad.event.DisclosureEvent;
 
 import org.apache.myfaces.trinidad.logging.TrinidadLogger;
@@ -85,12 +88,12 @@ abstract public class UIXShowDetailTemplate extends UIXComponentBase
     {
       // Do not update the disclosed if "transient"
       if (!isDisclosedTransient())
-      {      
+      {
         // Expand or collapse this showDetail
         boolean isDisclosed = ((DisclosureEvent) event).isExpanded();
-        // If the component is already in that disclosure state, we 
+        // If the component is already in that disclosure state, we
         // have a renderer bug.  Either it delivered an unnecessary event,
-        // or even worse it set disclosed on its own instead of waiting 
+        // or even worse it set disclosed on its own instead of waiting
         // for the disclosure event to do that, which will lead to lifecycle
         // problems.  So in either case, warn the developer.
         if (isDisclosed == isDisclosed())
@@ -101,12 +104,12 @@ abstract public class UIXShowDetailTemplate extends UIXComponentBase
         {
           setDisclosed(isDisclosed);
         }
-  
+
         //pu: Implicitly record a Change for 'disclosed' attribute
         addAttributeChange("disclosed",
                            isDisclosed ? Boolean.TRUE : Boolean.FALSE);
       }
-      
+
       if (isImmediate())
         getFacesContext().renderResponse();
 
@@ -133,5 +136,16 @@ abstract public class UIXShowDetailTemplate extends UIXComponentBase
     super.queueEvent(e);
   }
 
+  @Override
+  protected boolean visitChildren(
+    VisitContext  visitContext,
+    VisitCallback callback)
+  {
+    return
+      (visitContext.getHints().contains(VisitHint.SKIP_UNRENDERED) == false ||
+        this.isDisclosed()) &&
+      super.visitChildren(visitContext, callback);
+  }
+
   static private final TrinidadLogger _LOG = TrinidadLogger.createTrinidadLogger(UIXShowDetail.class);
 }
diff --git a/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXShowOneTemplate.java b/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXShowOneTemplate.java
index 4aa07a9..896580c 100644
--- a/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXShowOneTemplate.java
+++ b/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXShowOneTemplate.java
@@ -6,9 +6,9 @@
  *  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
@@ -19,22 +19,27 @@
 package org.apache.myfaces.trinidad.component;
 
 import java.io.IOException;
-import java.util.List;
 
 import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import javax.faces.event.FacesEvent;
 import javax.faces.event.PhaseId;
 
+import org.apache.myfaces.trinidad.component.visit.VisitCallback;
+import org.apache.myfaces.trinidad.component.visit.VisitContext;
+import org.apache.myfaces.trinidad.component.visit.VisitContextWrapper;
+import org.apache.myfaces.trinidad.component.visit.VisitHint;
+import org.apache.myfaces.trinidad.component.visit.VisitResult;
 import org.apache.myfaces.trinidad.event.DisclosureEvent;
 
+
 /**
  * Base class for ShowOne component.
  * @version $Name:  $ ($Revision$) $Date$
  */
-abstract public class UIXShowOneTemplate extends UIXComponentBase
+abstract public class UIXShowOneTemplate
+  extends UIXComponentBase
 {
-	
   @Override
   @SuppressWarnings("unchecked")
   public void queueEvent(FacesEvent e)
@@ -85,6 +90,26 @@ abstract public class UIXShowOneTemplate extends UIXComponentBase
     super.queueEvent(e);
   }
 
+  @Override
+  public boolean visitTree(
+    VisitContext  visitContext,
+    VisitCallback callback)
+  {
+    if (visitContext.getHints().contains(VisitHint.SKIP_UNRENDERED))
+    {
+      // Filter which children to be visited so that only one show detail
+      // is visited for this show one component
+      visitContext = new PartialVisitContext(visitContext);
+    }
+    return super.visitTree(visitContext, callback);
+  }
+
+  protected boolean isChildSelected(
+    UIXShowDetail component)
+  {
+    return component.isDisclosed();
+  }
+
   /**
    * State passed to the UndisclosureCallback.
    */
@@ -145,5 +170,70 @@ abstract public class UIXShowOneTemplate extends UIXComponentBase
     }
   }
 
+  private class PartialVisitContext
+    extends VisitContextWrapper
+  {
+    PartialVisitContext(VisitContext wrapped)
+    {
+      _wrapped = wrapped;
+    }
+
+    public VisitContext getWrapped()
+    {
+      return _wrapped;
+    }
+
+    @Override
+    public VisitResult invokeVisitCallback(
+      UIComponent   component,
+      VisitCallback visitCallback)
+    {
+      if (component instanceof UIXShowDetail)
+      {
+        UIXShowDetail showDetail = (UIXShowDetail)component;
+        if (_isShowDetailForCurrentComponent(showDetail))
+        {
+          if (_foundItemToRender || !isChildSelected(showDetail))
+          {
+            // We already visited the one to be shown
+            return VisitResult.REJECT;
+          }
+          else
+          {
+            _foundItemToRender = true;
+          }
+        }
+      }
+
+      return super.invokeVisitCallback(component, visitCallback);
+    }
+
+    private boolean _isShowDetailForCurrentComponent(
+      UIXShowDetail showDetail)
+    {
+      for (UIComponent parent = showDetail.getParent(); parent != null; parent = parent.getParent())
+      {
+        if (parent == UIXShowOne.this)
+        {
+          return true;
+        }
+
+        if (parent instanceof FlattenedComponent &&
+          ((FlattenedComponent)parent).isFlatteningChildren(getFacesContext()))
+        {
+          continue;
+        }
+
+        // The first-non flattened component is not the show one, do not filter it
+        return false;
+      }
+
+      return false;
+    }
+
+    private boolean      _foundItemToRender;
+    private VisitContext _wrapped;
+  }
+
   private final UndisclosureCallback _undisclosureCallback = new UndisclosureCallback();
 }
diff --git a/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXSwitcherTemplate.java b/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXSwitcherTemplate.java
index 901ab83..d541f76 100644
--- a/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXSwitcherTemplate.java
+++ b/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXSwitcherTemplate.java
@@ -6,9 +6,9 @@
  *  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
@@ -23,6 +23,10 @@ import java.io.IOException;
 import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 
+import org.apache.myfaces.trinidad.component.visit.VisitCallback;
+import org.apache.myfaces.trinidad.component.visit.VisitContext;
+import org.apache.myfaces.trinidad.component.visit.VisitHint;
+
 
 /**
  * Base class for the switcher componnet.
@@ -57,7 +61,6 @@ abstract public class UIXSwitcherTemplate extends UIXComponentBase implements Fl
       facet.processValidators(context);
   }
 
-
   /**
    * Only process updates on the currently active facet.
    */
@@ -79,7 +82,7 @@ abstract public class UIXSwitcherTemplate extends UIXComponentBase implements Fl
     final S callbackContext) throws IOException
   {
     UIComponent facet = _getFacet();
-    
+
     if (facet != null)
       return UIXComponent.processFlattenedChildren(context,
                                                    cpContext,
@@ -112,7 +115,6 @@ abstract public class UIXSwitcherTemplate extends UIXComponentBase implements Fl
       __encodeRecursive(context, facet);
   }
 
-
   /**
    * Override to return true.
    */
@@ -122,6 +124,26 @@ abstract public class UIXSwitcherTemplate extends UIXComponentBase implements Fl
     return true;
   }
 
+  @Override
+  protected boolean visitChildren(
+    VisitContext  visitContext,
+    VisitCallback callback)
+  {
+    if (visitContext.getHints().contains(VisitHint.SKIP_UNRENDERED))
+    {
+      UIComponent facet = _getFacet();
+      if (facet != null)
+      {
+        return UIXComponent.visitTree(visitContext, facet, callback);
+      }
+      return false;
+    }
+    else
+    {
+      return super.visitChildren(visitContext, callback);
+    }
+  }
+
   private UIComponent _getFacet()
   {
     if (!isRendered())
@@ -141,7 +163,6 @@ abstract public class UIXSwitcherTemplate extends UIXComponentBase implements Fl
 
     return null;
   }
-
 }
 
 
diff --git a/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXTreeTableTemplate.java b/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXTreeTableTemplate.java
index b7ff644..286c166 100644
--- a/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXTreeTableTemplate.java
+++ b/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXTreeTableTemplate.java
@@ -6,9 +6,9 @@
  *  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
@@ -36,6 +36,8 @@ import javax.faces.event.AbortProcessingException;
 import javax.faces.event.FacesEvent;
 import javax.faces.event.PhaseId;
 
+import org.apache.myfaces.trinidad.component.visit.VisitCallback;
+import org.apache.myfaces.trinidad.component.visit.VisitContext;
 import org.apache.myfaces.trinidad.event.FocusEvent;
 import org.apache.myfaces.trinidad.event.RangeChangeEvent;
 import org.apache.myfaces.trinidad.event.RangeChangeListener;
@@ -59,9 +61,9 @@ abstract public class UIXTreeTableTemplate extends UIXTree
   public void decode(FacesContext context)
   {
     _resetContainerClientIdCache();
-    super.decode(context);    
+    super.decode(context);
   }
-  
+
   /**
    * Override to update the container client id cache before validations
    */
@@ -71,16 +73,16 @@ abstract public class UIXTreeTableTemplate extends UIXTree
     _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
@@ -101,7 +103,7 @@ abstract public class UIXTreeTableTemplate extends UIXTree
   {
     String id;
     if (_containerClientIdCache == null || _isStampedChild(child))
-    {   
+    {
       // call the UIXCollection getContainerClientId, which attaches currency string to the client id
       id = getContainerClientId(context);
     }
@@ -358,14 +360,14 @@ abstract public class UIXTreeTableTemplate extends UIXTree
                                          phaseId,
                                          this,
                                          state,
-                                         true);        
+                                         true);
 
       }
       else
       {
         TableUtils.__processStampedChildren(context, this, phaseId);
         processComponent(context, nodeStamp, phaseId); // bug 4688568
-  
+
         if (state.isContained())
         {
           enterContainer();
@@ -383,6 +385,81 @@ abstract public class UIXTreeTableTemplate extends UIXTree
     }
   }
 
+
+  @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
    */
@@ -422,7 +499,7 @@ abstract public class UIXTreeTableTemplate extends UIXTree
       // cache nodeStamp header/footer items
       TableUtils.cacheHeaderFooterFacets(nodeStamp, _containerClientIdCache);
       // cache any nested columns in nodeStamp facet
-      TableUtils.cacheColumnHeaderFooterFacets(nodeStamp, _containerClientIdCache);      
+      TableUtils.cacheColumnHeaderFooterFacets(nodeStamp, _containerClientIdCache);
     }
   }
 
@@ -438,7 +515,7 @@ abstract public class UIXTreeTableTemplate extends UIXTree
 
     return state;
   }
-  
+
   /**
    * Sets the internal state of this component.
    * @param stampState the internal state is obtained from this object.
diff --git a/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXTreeTemplate.java b/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXTreeTemplate.java
index 928c06d..f3ebd7f 100644
--- a/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXTreeTemplate.java
+++ b/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXTreeTemplate.java
@@ -31,6 +31,9 @@ import javax.faces.event.PhaseId;
 
 import org.apache.myfaces.trinidad.bean.FacesBean;
 import org.apache.myfaces.trinidad.bean.PropertyKey;
+import org.apache.myfaces.trinidad.component.visit.VisitCallback;
+import org.apache.myfaces.trinidad.component.visit.VisitContext;
+import org.apache.myfaces.trinidad.component.visit.VisitHint;
 import org.apache.myfaces.trinidad.event.RowDisclosureEvent;
 import org.apache.myfaces.trinidad.event.SelectionEvent;
 import org.apache.myfaces.trinidad.model.CollectionModel;
@@ -149,6 +152,29 @@ abstract public class UIXTreeTemplate extends UIXHierarchy
   }
 
   @Override
+  protected boolean visitChildren(
+    VisitContext  visitContext,
+    VisitCallback callback)
+  {
+    return visitData(visitContext, callback);
+  }
+
+  @Override
+  protected boolean visitData(
+    VisitContext  visitContext,
+    VisitCallback callback)
+  {
+    // if we are only visiting rendered stamps, then pass in the disclosed row keys, otherwise
+    // pass in null, indicating that all row keys should be visited
+    RowKeySet disclosedRowKeys = (visitContext.getHints().contains(VisitHint.SKIP_UNRENDERED))
+                                   ? getDisclosedRowKeys()
+                                   : null;
+
+    return visitHierarchy(visitContext, callback, getStamps(), disclosedRowKeys);
+  }
+
+
+  @Override
   void __init()
   {
     super.__init();
@@ -158,7 +184,6 @@ abstract public class UIXTreeTemplate extends UIXHierarchy
       setSelectedRowKeys(new RowKeySetTreeImpl());
   }
 
-
   /**
    * Gets the internal state of this component.
    */
diff --git a/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/core/layout/CorePanelAccordionTemplate.java b/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/core/layout/CorePanelAccordionTemplate.java
index 9515c61..544bbdc 100644
--- a/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/core/layout/CorePanelAccordionTemplate.java
+++ b/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/core/layout/CorePanelAccordionTemplate.java
@@ -18,20 +18,29 @@
  */
 package org.apache.myfaces.trinidad.component.core.layout;
 
+import java.util.List;
+
 import javax.faces.component.UIComponent;
-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 java.util.List;
 
-import org.apache.myfaces.trinidad.event.DisclosureEvent;
+import org.apache.myfaces.trinidad.component.FlattenedComponent;
+import org.apache.myfaces.trinidad.component.UIXPanel;
 import org.apache.myfaces.trinidad.component.UIXShowDetail;
+import org.apache.myfaces.trinidad.component.visit.VisitCallback;
+import org.apache.myfaces.trinidad.component.visit.VisitContext;
+import org.apache.myfaces.trinidad.component.visit.VisitContextWrapper;
+import org.apache.myfaces.trinidad.component.visit.VisitHint;
+import org.apache.myfaces.trinidad.component.visit.VisitResult;
+import org.apache.myfaces.trinidad.event.DisclosureEvent;
+
 
-abstract public class CorePanelAccordion extends UIXPanel
+abstract public class CorePanelAccordionTemplate
+  extends UIXPanel
 {
-    /**
+/**/ public abstract boolean isDiscloseMany();
+
+  /**
    * Queues an event recursively to the root component.
    * @param event
    * @throws javax.faces.event.AbortProcessingException
@@ -67,4 +76,91 @@ abstract public class CorePanelAccordion extends UIXPanel
     super.queueEvent(event);
   }
 
+  protected boolean isChildSelected(
+    UIXShowDetail component)
+  {
+    return component.isDisclosed();
+  }
+
+  @Override
+  public boolean visitTree(
+    VisitContext  visitContext,
+    VisitCallback callback)
+  {
+    if (visitContext.getHints().contains(VisitHint.SKIP_UNRENDERED) &&
+     !isDiscloseMany())
+    {
+      // Filter which children to be visited so that only one show detail
+      // is visited for this accordion
+      visitContext = new PartialVisitContext(visitContext);
+    }
+    return super.visitTree(visitContext, callback);
+  }
+
+  private class PartialVisitContext
+    extends VisitContextWrapper
+  {
+    PartialVisitContext(
+      VisitContext wrapped)
+    {
+      _wrapped = wrapped;
+    }
+
+    public VisitContext getWrapped()
+    {
+      return _wrapped;
+    }
+
+    @Override
+    public VisitResult invokeVisitCallback(
+      UIComponent   component,
+      VisitCallback visitCallback)
+    {
+      if (component instanceof UIXShowDetail)
+      {
+        UIXShowDetail showDetail = (UIXShowDetail)component;
+        if (_isShowDetailForCurrentComponent(showDetail))
+        {
+          if (_foundItemToRender || !isChildSelected(showDetail))
+          {
+            // We already visited the one to be shown
+            return VisitResult.REJECT;
+          }
+          else
+          {
+            _foundItemToRender = true;
+          }
+        }
+      }
+
+      return super.invokeVisitCallback(component, visitCallback);
+    }
+
+    private boolean _isShowDetailForCurrentComponent(
+      UIXShowDetail showDetail)
+    {
+      for (UIComponent parent = showDetail.getParent(); parent != null;
+           parent = parent.getParent())
+      {
+        if (parent == CorePanelAccordion.this)
+        {
+          return true;
+        }
+
+        if (parent instanceof FlattenedComponent &&
+          ((FlattenedComponent)parent).isFlatteningChildren(getFacesContext()))
+        {
+          continue;
+        }
+
+        // The first-non flattened component is not the show one, do not filter it
+        return false;
+      }
+
+      return false;
+    }
+
+    private boolean      _foundItemToRender;
+    private VisitContext _wrapped;
+  }
 }
\ No newline at end of file
diff --git a/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXCollection.java b/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXCollection.java
index 532c395..1c02cdc 100644
--- a/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXCollection.java
+++ b/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXCollection.java
@@ -40,6 +40,10 @@ import javax.faces.render.Renderer;
 
 import org.apache.myfaces.trinidad.bean.FacesBean;
 import org.apache.myfaces.trinidad.bean.PropertyKey;
+import org.apache.myfaces.trinidad.component.visit.VisitCallback;
+import org.apache.myfaces.trinidad.component.visit.VisitContext;
+import org.apache.myfaces.trinidad.component.visit.VisitContextWrapper;
+import org.apache.myfaces.trinidad.component.visit.VisitResult;
 import org.apache.myfaces.trinidad.event.SelectionEvent;
 import org.apache.myfaces.trinidad.logging.TrinidadLogger;
 import org.apache.myfaces.trinidad.model.CollectionModel;
@@ -1092,6 +1096,240 @@ public abstract class UIXCollection extends UIXComponentBase
   }
 
   /**
+   * <p>
+   * Override default children visiting code to visit the facets and facets of the columns
+   * before delegating to the <code>visitData</code> to visit the individual rows of data.
+   * </p><p>
+   * Subclasses should override this method if they wish to change the way in which the non-stamped
+   * children are visited.  If they wish to change the wash the the stamped children are visited,
+   * they should override <code>visitData</code> instead.
+   * </p>
+   * @param visitContext
+   * @param callback
+   * @return <code>true</code> if all of the children to visit have been visited
+   * @see #visitData
+   */
+  @Override
+  protected boolean visitChildren(
+    VisitContext  visitContext,
+    VisitCallback callback)
+  {
+    return defaultVisitChildren(visitContext, callback);
+  }
+
+  protected final boolean defaultVisitChildren(
+    VisitContext  visitContext,
+    VisitCallback callback)
+  {
+    boolean doneVisiting;
+
+    // Clear out the row index if one is set so that
+    // we start from a clean slate.
+    int oldRowIndex = getRowIndex();
+    setRowIndex(-1);
+
+    try
+    {
+      // visit the unstamped children
+      doneVisiting = visitUnstampedFacets(visitContext, callback);
+
+      if (!doneVisiting)
+      {
+        doneVisiting = _visitStampedColumnFacets(visitContext, callback);
+
+        // visit the stamped children
+        if (!doneVisiting)
+        {
+          doneVisiting = visitData(visitContext, callback);
+        }
+      }
+    }
+    finally
+    {
+      // restore the original rowIndex
+      setRowIndex(oldRowIndex);
+    }
+
+    return doneVisiting;
+  }
+
+  /**
+   * Hook method for subclasses to override to change the behavior
+   * of how unstamped facets of the UIXCollection are visited.  The
+   * Default implementation visits all of the facets of the
+   * UIXCollection.
+   */
+  protected boolean visitUnstampedFacets(
+    VisitContext  visitContext,
+    VisitCallback callback)
+  {
+    // Visit the facets with no row
+    if (getFacetCount() > 0)
+    {
+      for (UIComponent facet : getFacets().values())
+      {
+        if (UIXComponent.visitTree(visitContext, facet, callback))
+        {
+          return true;
+        }
+      }
+    }
+
+    return false;
+  }
+
+
+  /**
+   * VistiContext that visits the facets of the UIXColumn children, including
+   * nested UIXColumn childrem
+   */
+  private static class ColumnFacetsOnlyVisitContext
+    extends VisitContextWrapper
+  {
+    public ColumnFacetsOnlyVisitContext(VisitContext wrappedContext)
+    {
+      _wrapped = wrappedContext;
+    }
+
+    @Override
+    public VisitContext getWrapped()
+    {
+      return _wrapped;
+    }
+
+    @Override
+    public VisitResult invokeVisitCallback(
+      UIComponent   component,
+      VisitCallback callback)
+    {
+      if (component instanceof UIXColumn)
+      {
+        if (component.getFacetCount() > 0)
+        {
+          // visit the facet children without filtering for just UIXColumn children
+          for (UIComponent facetChild : component.getFacets().values())
+          {
+            if (UIXComponent.visitTree(getWrapped(), facetChild, callback))
+              return VisitResult.COMPLETE;
+          }
+
+          // visit the indexed children, recursively looking for more columns
+          for (UIComponent child : component.getChildren())
+          {
+            if (UIXComponent.visitTree(this, child, callback))
+              return VisitResult.COMPLETE;
+          }
+        }
+      }
+
+      // at this point, we either have already manually processed the UIXColumn's children, or
+      // the component wasn't a UIXColumn and shouldn't be processed
+      return VisitResult.REJECT;
+    }
+
+    private final VisitContext _wrapped;
+  }
+
+  /**
+   * VisitContext implementation that doesn't visit any of the Facets of
+   * UIXColumn children.  This is used when stamping children
+   */
+  protected static final class NoColumnFacetsVisitContext extends VisitContextWrapper
+  {
+    NoColumnFacetsVisitContext(VisitContext wrapped)
+    {
+      _wrapped = wrapped;
+    }
+
+    @Override
+    public VisitContext getWrapped()
+    {
+      return _wrapped;
+    }
+
+    @Override
+    public VisitResult invokeVisitCallback(UIComponent component, VisitCallback callback)
+    {
+      if (component instanceof UIXColumn)
+      {
+        if (component.getChildCount() > 0)
+        {
+          // visit only the indexed children of the columns
+          for (UIComponent child : component.getChildren())
+          {
+            if (UIXComponent.visitTree(this, child, callback))
+              return VisitResult.COMPLETE;
+          }
+        }
+
+        return VisitResult.REJECT;
+      }
+      else
+      {
+        if (UIXComponent.visitTree(getWrapped(), component, callback))
+          return VisitResult.COMPLETE;
+        else
+          return VisitResult.REJECT;
+      }
+    }
+
+    private final VisitContext _wrapped;
+  }
+
+  /**
+   * Implementation used to visit each stamped row
+   */
+  private boolean _visitStampedColumnFacets(
+    VisitContext      visitContext,
+    VisitCallback     callback)
+  {
+    // visit the facets of the stamped columns
+    List<UIComponent> stamps = getStamps();
+
+    if (!stamps.isEmpty())
+    {
+      VisitContext columnVisitingContext = new ColumnFacetsOnlyVisitContext(visitContext);
+
+      for (UIComponent stamp : stamps)
+      {
+        if (UIXComponent.visitTree(columnVisitingContext, stamp, callback))
+        {
+          return true;
+        }
+      }
+    }
+
+    return false;
+  }
+
+
+  /**
+   * Visit the rows and children of the columns of the collection per row-index. This should
+   * not visit row index -1 (it will be perfomed in the visitTree method). The columns
+   * themselves should not be visited, only their children in this function.
+   * <p>
+   * Note that in Trinidad 1.2 this method does nothing, but it must be overridden. It is
+   * only being made empty in order to avoid an API change of forcing subclasses to implement
+   * this function, but visiting will not work without it being implemented. In Trinidad 2
+   * this method is abstract.
+   * </p>
+   *
+   * @param visitContext The visiting context
+   * @param callback The visit callback
+   * @return true if the visiting should stop
+   * @see #visitChildren(VisitContext, VisitCallback)
+   */
+  /*protected boolean visitData(
+    VisitContext  visitContext,
+    VisitCallback callback)
+  {
+    return false;
+  }*/
+  protected abstract boolean visitData(
+      VisitContext  visitContext,
+      VisitCallback callback);
+
+  /**
    * Gets the CollectionModel to use with this component.
    *
    * @param createIfNull  creates the collection model if necessary
@@ -1179,14 +1417,14 @@ public abstract class UIXCollection extends UIXComponentBase
     };
   }
 
-  
+
   //
   // LocalRowKeyIndex implementation
   //
 
   /**
    * Given a row index, check if a row is locally available
-   * @param rowIndex index of row to check 
+   * @param rowIndex index of row to check
    * @return true if row is locally available
    */
   public boolean isRowLocallyAvailable(int rowIndex)
@@ -1196,7 +1434,7 @@ public abstract class UIXCollection extends UIXComponentBase
 
   /**
    * Given a row key, check if a row is locally available
-   * @param rowKey row key for the row to check 
+   * @param rowKey row key for the row to check
    * @return true if row is locally available
    */
   public boolean isRowLocallyAvailable(Object rowKey)
@@ -1216,7 +1454,7 @@ public abstract class UIXCollection extends UIXComponentBase
 
   /**
    * Check if a range of rows is locally available starting from a row index
-   * @param startIndex staring index for the range  
+   * @param startIndex staring index for the range
    * @param rowCount number of rows in the range
    * @return true if range of rows is locally available
    */
@@ -1227,7 +1465,7 @@ public abstract class UIXCollection extends UIXComponentBase
 
   /**
    * Check if a range of rows is locally available starting from a row key
-   * @param startRowKey staring row key for the range  
+   * @param startRowKey staring row key for the range
    * @param rowCount number of rows in the range
    * @return true if range of rows is locally available
    */
@@ -1235,9 +1473,9 @@ public abstract class UIXCollection extends UIXComponentBase
   {
     return getCollectionModel().areRowsLocallyAvailable(startRowKey, rowCount);
   }
-  
+
   /**
-   * Convenient API to return a row count estimate.  This method can be optimized 
+   * Convenient API to return a row count estimate.  This method can be optimized
    * to avoid a data fetch which may be required to return an exact row count
    * @return estimated row count
    */
@@ -1248,14 +1486,14 @@ public abstract class UIXCollection extends UIXComponentBase
 
 
   /**
-   * Helper API to determine if the row count returned from {@link #getEstimatedRowCount} 
+   * Helper API to determine if the row count returned from {@link #getEstimatedRowCount}
    * is EXACT, or an ESTIMATE
    */
   public LocalRowKeyIndex.Confidence getEstimatedRowCountConfidence()
   {
     return getCollectionModel().getEstimatedRowCountConfidence();
   }
-  
+
   /**
    * clear all rows from the local cache
    */
@@ -1263,7 +1501,7 @@ public abstract class UIXCollection extends UIXComponentBase
   {
     getCollectionModel().clearLocalCache();
   }
-  
+
   /**
    * Clear the requested range of rows from the local cache
    * @param startingIndex starting row index for the range to clear
@@ -1273,7 +1511,7 @@ public abstract class UIXCollection extends UIXComponentBase
   {
     getCollectionModel().clearCachedRows(startingIndex, rowsToClear);
   }
-  
+
   /**
    * Clear the requested range of rows from the local cache
    * @param startingRowKey starting row key for the range to clear
@@ -1283,7 +1521,7 @@ public abstract class UIXCollection extends UIXComponentBase
   {
     getCollectionModel().clearCachedRows(startingRowKey, rowsToClear);
   }
-  
+
   /**
    * Clear a row from the local cache by row index
    * @param index row index for the row to clear from the cache
@@ -1292,16 +1530,16 @@ public abstract class UIXCollection extends UIXComponentBase
   {
     getCollectionModel().clearCachedRow(index);
   }
-  
+
   /**
    * Clear a row from the local cache by row key
    * @param rowKey row key for the row to clear from the cache
    */
   public void clearCachedRow(Object rowKey)
   {
-    getCollectionModel().clearCachedRow(rowKey);    
+    getCollectionModel().clearCachedRow(rowKey);
   }
-  
+
   /**
    * Indicates the caching strategy supported by the model
    * @see LocalCachingStrategy
@@ -1311,7 +1549,7 @@ public abstract class UIXCollection extends UIXComponentBase
   {
     return getCollectionModel().getCachingStrategy();
   }
-  
+
 
   /**
    * override this method to place initialization code that must run
diff --git a/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXComponent.java b/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXComponent.java
index a80aa48..a3fef4c 100644
--- a/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXComponent.java
+++ b/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXComponent.java
@@ -251,7 +251,7 @@ abstract public class UIXComponent extends UIComponent
   {
     ComponentProcessingContext processingContext = new ComponentProcessingContext();
     processingContext.__setIsRendering();
-    
+
     return processFlattenedChildren(context,
                                     processingContext,
                                     childProcessor,
@@ -327,6 +327,81 @@ abstract public class UIXComponent extends UIComponent
   }
 
   /**
+   * Hook for subclasses to override the manner in which the component's children are visited.  The default
+   * implementation visits all of the children and facets of the Component.
+   * <code>setupChildrenVisitingContext</code> will have been called before this method is
+   * invoked and <code>tearDownChildrenVisitingContext</code> will be called after.
+   * respectively.  If the purpose of this visit was to encode the component and the
+   * component uses a CoreRenderer, the CoreRenderer's
+   * <code>setupChildrenEncodingContext</code> and <code>tearDownChildrenEncodingContext</code>
+   * will be called before and after this method is invoked, respectively.
+   * @param visitContext the <code>VisitContext</code> for this visit
+   * @param callback the <code>VisitCallback</code> instance
+   * @return <code>true</code> if the visit is complete.
+   * @see #setupChildrenVisitingContext
+   * @see #tearDownChildrenVisitingContext
+   * @see org.apache.myfaces.trinidad.render.CoreRenderer#setupChildrenEncodingContext
+   * @see org.apache.myfaces.trinidad.render.CoreRenderer#tearDownChildrenEncodingContext
+   */
+  protected boolean visitChildren(
+    VisitContext  visitContext,
+    VisitCallback callback)
+  {
+    // See if this is during encoding, if so, allow the renderer to control the visitation of
+    // the children so that any special encoding context may be applied around the visitation
+    // of each child.
+    if (_isEncodingVisit(visitContext))
+    {
+      Renderer renderer = getRenderer(visitContext.getFacesContext());
+      if (renderer instanceof CoreRenderer)
+      {
+        CoreRenderer coreRenderer = (CoreRenderer)renderer;
+        return coreRenderer.visitChildrenForEncoding(this, visitContext, callback);
+      }
+    }
+
+    // visit all of the children of the component
+    return _visitAllChildren(this, visitContext, callback);
+  }
+
+  /**
+   * Default implementation of visiting children that visits all children without iterating
+   * @param visitContext the <code>VisitContext</code> for this visit
+   * @param callback the <code>VisitCallback</code> instance
+   * @return <code>true</code> if the visit is complete.
+   */
+  private static boolean _visitAllChildren(
+    UIComponent   component,
+    VisitContext  visitContext,
+    VisitCallback callback)
+  {
+    // visit the children of the component
+    Iterator<UIComponent> kids = component.getFacetsAndChildren();
+
+    while (kids.hasNext())
+    {
+      // If any kid visit returns true, we are done.
+      UIComponent kid = kids.next();
+      if (kid instanceof UIXComponent)
+      {
+        if (((UIXComponent)kid).visitTree(visitContext, callback))
+        {
+          return true;
+        }
+      }
+      else
+      {
+        if (visitTree(visitContext, kid, callback))
+        {
+          return true;
+        }
+      }
+    }
+
+    return false;
+  }
+
+  /**
   * <p>Perform a tree visit starting at the specified node in the tree.</p>
   *
   * <p>UIXComponent.visitTree() implementations do not invoke the
@@ -350,7 +425,7 @@ abstract public class UIXComponent extends UIComponent
   * @see VisitContext#invokeVisitCallback VisitContext.invokeVisitCallback()
   */
   public static boolean visitTree(
-    VisitContext visitContext,
+    VisitContext  visitContext,
     UIComponent   component,
     VisitCallback callback)
   {
@@ -374,113 +449,105 @@ abstract public class UIXComponent extends UIComponent
       uixComponent = null;
     }
 
-    // invoke the callback for this component
-    VisitResult result = visitContext.invokeVisitCallback(component, callback);
-
-    if (result == VisitResult.COMPLETE)
-      return true;
-    else if (result == VisitResult.ACCEPT)
+    FacesContext facesContext = visitContext.getFacesContext();
+    RenderingContext rc = null;
+    if (uixComponent != null)
+    {
+      // We only need the rendering context if we are visiting a UIXComponent
+      rc = (uixComponent != null && _isEncodingVisit(visitContext))
+                                  ? RenderingContext.getCurrentInstance()
+                                  : null;
+
+      // UIXComponents are allowed to set up their context differently for encoding
+      // than normal processing, so behave differently if this is the RenderResponse
+      // phase
+      if (rc != null)
+      {
+        uixComponent.setUpEncodingContext(facesContext, rc);
+      }
+      else
+      {
+        uixComponent.setupVisitingContext(facesContext);
+      }
+    }
+    try
     {
-      // now visit the children
-      FacesContext context = visitContext.getFacesContext();
-      PhaseId phaseId = visitContext.getPhaseId();
-      RenderingContext rc = (PhaseId.RENDER_RESPONSE == phaseId)
-                              ? RenderingContext.getCurrentInstance()
-                              : null;
+      // invoke the callback for this component
+      VisitResult result = visitContext.invokeVisitCallback(component, callback);
 
-      if (uixComponent != null)
+      if (result == VisitResult.COMPLETE)
+        return true;
+      else if (result == VisitResult.ACCEPT)
       {
-        // assume that all UIXComponent NamingContainers always act as NamingContainers,
-        // (unlike <h:form>) and this it is OK to put the optimization where we
-        // don't visit the children if we know that we don't have any ids in this
-        // subtree to visit
-        if (uixComponent instanceof NamingContainer)
+        // now visit the children
+        if (uixComponent != null)
+        {
+          // assume that all UIXComponent NamingContainers always act as NamingContainers,
+          // (unlike <h:form>) and this it is OK to put the optimization where we
+          // don't visit the children if we know that we don't have any ids in this
+          // subtree to visit
+          if (uixComponent instanceof NamingContainer)
+          {
+            if (visitContext.getSubtreeIdsToVisit(uixComponent).isEmpty())
+              return false;
+          }
+        }
+        else
         {
-          if (visitContext.getSubtreeIdsToVisit(uixComponent).isEmpty())
-            return false;
+          // we only optimize walking into non-UIXComponent NamingContainers
+          // if they are UINamingConainer (which is used by <f:subview>
+          if (UINamingContainer.class == component.getClass())
+          {
+            if (visitContext.getSubtreeIdsToVisit(component).isEmpty())
+              return false;
+          }
         }
 
-        // UIXComponents are allowed to set up their context differently for encoding
-        // than normal processing, so behave differently if this is the RenderResponse
-        // phase
-        if (PhaseId.RENDER_RESPONSE == phaseId)
+        if (uixComponent != null)
         {
-          uixComponent.setUpEncodingContext(context, rc);
+          return uixComponent.visitChildren(visitContext, callback);
         }
         else
         {
-          uixComponent.setupVisitingContext(context);
+          return _visitAllChildren(component, visitContext, callback);
         }
       }
       else
       {
-        // we only optimize walking into non-UIXComponent NamingContainers
-        // if they are UINamingConainer (which is used by <f:subview>
-        if (UINamingContainer.class == component.getClass())
-        {
-          if (visitContext.getSubtreeIdsToVisit(component).isEmpty())
-            return false;
-        }
+        assert(result == VisitResult.REJECT);
       }
-
-      // visit the children of the component
-      try
+    }
+    finally
+    {
+      if (uixComponent != null)
       {
-        Iterator<UIComponent> kids = component.getFacetsAndChildren();
-
-        while(kids.hasNext())
+        if (rc != null)
         {
-          boolean done;
-
-          UIComponent currChild = kids.next();
-
-          if (currChild instanceof UIXComponent)
-          {
-            UIXComponent uixChild = (UIXComponent)currChild;
-
-            // delegate to UIXComponent's visitTree implementation to allow
-            // subclassses to modify the behavior
-            done = uixChild.visitTree(visitContext, callback);
-          }
-          else
-          {
-            // use generic visit implementation
-            done = visitTree(visitContext, currChild, callback);
-          }
-
-          // If any kid visit returns true, we are done.
-          if (done)
-          {
-            return true;
-          }
+          uixComponent.tearDownEncodingContext(facesContext, rc);
         }
-      }
-      finally
-      {
-        // tear down the context we set up in order to visit our children
-        if (uixComponent != null)
+        else
         {
-          if (PhaseId.RENDER_RESPONSE == phaseId)
-          {
-            uixComponent.tearDownEncodingContext(context, rc);
-          }
-          else
-          {
-            uixComponent.tearDownVisitingContext(context);
-          }
+          uixComponent.tearDownVisitingContext(facesContext);
         }
       }
     }
-    else
-    {
-      assert(result == VisitResult.REJECT);
-    }
 
     // if we got this far, we're not done
     return false;
   }
 
   /**
+   * Returns <code>true</code> if the components are being visited
+   * for the purpose of encoding.
+   */
+  private static boolean _isEncodingVisit(
+    VisitContext visitContext)
+  {
+    return (visitContext.getHints().contains(VisitHint.EXECUTE_LIFECYCLE) &&
+      visitContext.getPhaseId() == PhaseId.RENDER_RESPONSE);
+  }
+
+  /**
    * Add a component as a partial target to the current request. This code handles the
    * delegation to {@link #setPartialTarget(FacesContext, PartialPageContext)}
    * for UIXComponents or assumes for {@link UIComponent} that components with a renderer
diff --git a/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXHierarchy.java b/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXHierarchy.java
index a9ec25a..ee22ca6 100644
--- a/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXHierarchy.java
+++ b/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXHierarchy.java
@@ -6,9 +6,9 @@
  *  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
@@ -19,11 +19,12 @@
 package org.apache.myfaces.trinidad.component;
 
 import java.util.Collections;
-
 import java.util.List;
 
 import javax.faces.component.UIComponent;
 
+import org.apache.myfaces.trinidad.component.visit.VisitCallback;
+import org.apache.myfaces.trinidad.component.visit.VisitContext;
 import org.apache.myfaces.trinidad.model.CollectionModel;
 import org.apache.myfaces.trinidad.model.LocalRowKeyIndex;
 import org.apache.myfaces.trinidad.model.ModelUtils;
@@ -37,7 +38,7 @@ import org.apache.myfaces.trinidad.model.TreeModel;
  *
  * @version $Name:  $ ($Revision: adfrt/faces/adf-faces-api/src/main/java/oracle/adf/view/faces/component/UIXHierarchy.java#0 $) $Date: 10-nov-2005.19:09:52 $
  */
-abstract public class UIXHierarchy extends UIXCollection implements CollectionComponent, LocalRowKeyIndex, 
+abstract public class UIXHierarchy extends UIXCollection implements CollectionComponent, LocalRowKeyIndex,
              TreeLocalRowKeyIndex
 {
   /**
@@ -58,7 +59,7 @@ abstract public class UIXHierarchy extends UIXCollection implements CollectionCo
   public CollectionModel createCollectionModel(CollectionModel current, Object value)
   {
     TreeModel model = ModelUtils.toTreeModel(value);
-    model.setRowKey(null);    
+    model.setRowKey(null);
     return model;
   }
 
@@ -80,8 +81,8 @@ abstract public class UIXHierarchy extends UIXCollection implements CollectionCo
   public int getRows()
   {
     return 0;
-  }  
-  
+  }
+
   /**
   * Treats the current element as a parent element and steps into the children.
   * A new path is constructed by appending the null value to the old path.
@@ -128,7 +129,7 @@ abstract public class UIXHierarchy extends UIXCollection implements CollectionCo
    */
   public boolean isContainerEmpty()
   {
-    
+
     return getTreeModel().isContainerEmpty();
   }
 
@@ -169,7 +170,7 @@ abstract public class UIXHierarchy extends UIXCollection implements CollectionCo
   {
     return getTreeModel().getContainerRowKey(childKey);
   }
-  
+
   /**
    * Gets the all the rowKeys of the ancestors of the given child row.
    * @see TreeModel#getAllAncestorContainerRowKeys(Object)
@@ -184,8 +185,8 @@ abstract public class UIXHierarchy extends UIXCollection implements CollectionCo
   //
 
   /**
-   * Indicates whether data for a child model (children of the current node) is 
-   * locally available. 
+   * Indicates whether data for a child model (children of the current node) is
+   * locally available.
    * @see TreeModel#isChildCollectionLocallyAvailable()
    * @return true if child data is locally available
    */
@@ -196,7 +197,7 @@ abstract public class UIXHierarchy extends UIXCollection implements CollectionCo
 
   /**
    * Indicates whether child data for the node with the given index is
-   * locally available.   
+   * locally available.
    * @see TreeModel#isChildCollectionLocallyAvailable(int)
    * @param index row index to check
    * @return true if child data is available, false otherwise
@@ -208,7 +209,7 @@ abstract public class UIXHierarchy extends UIXCollection implements CollectionCo
 
   /**
    * Indicates whether child data for the node with the given row key is
-   * locally available.   
+   * locally available.
    * @see TreeModel#isChildCollectionLocallyAvailable(Object)
    * @param rowKey row key to check
    * @return true if child data is available, false otherwise
@@ -221,7 +222,7 @@ abstract public class UIXHierarchy extends UIXCollection implements CollectionCo
   /**
    * Check if a range of rows is locally available starting from a row index.  The range
    * can include child nodes in any expanded nodes within the range.
-   * @param startIndex staring index for the range  
+   * @param startIndex staring index for the range
    * @param rowCount number of rows in the range
    * @param disclosedRowKeys set of expanded nodes which may fall within the range to check for
    * availability
@@ -237,7 +238,7 @@ abstract public class UIXHierarchy extends UIXCollection implements CollectionCo
   /**
    * Check if a range of rows is locally available starting from a row key.   The range
    * can include child nodes in any expanded nodes within the range.
-   * @param startRowKey staring row key for the range  
+   * @param startRowKey staring row key for the range
    * @param rowCount number of rows in the range
    * @param disclosedRowKeys set of expanded nodes which may fall within the range to check for
    * availability
@@ -273,8 +274,8 @@ abstract public class UIXHierarchy extends UIXCollection implements CollectionCo
   {
     TreeModel model = (TreeModel) getCollectionModel();
     return model;
-  } 
-  
+  }
+
   @Override
   protected List<UIComponent> getStamps()
   {
@@ -283,7 +284,94 @@ abstract public class UIXHierarchy extends UIXCollection implements CollectionCo
       return Collections.singletonList(nodeStamp);
     else
       return Collections.emptyList();
-  }  
+  }
 
   abstract public Object getFocusRowKey();
+
+  protected final boolean visitLevel(
+    VisitContext      visitContext,
+    VisitCallback     callback,
+    List<UIComponent> stamps)
+  {
+    if (getRowCount() != 0)
+    {
+      if (!stamps.isEmpty())
+      {
+        int oldRow = getRowIndex();
+        int first = getFirst();
+        int last = TableUtils.getLast(this, first);
+
+        try
+        {
+          for (int i = first; i <= last; i++)
+          {
+            setRowIndex(i);
+
+            for (UIComponent currStamp : stamps)
+            {
+              // visit the stamps.  If we have visited all of the visit targets then return early
+              if (UIXComponent.visitTree(visitContext, currStamp, callback))
+                return true;
+            }
+          }
+        }
+        finally
+        {
+          setRowIndex(oldRow);
+        }
+      }
+    }
+
+    return false;
+  }
+
+  protected final boolean visitHierarchy(
+    VisitContext      visitContext,
+    VisitCallback     callback,
+    List<UIComponent> stamps,
+    RowKeySet         disclosedRowKeys)
+  {
+    int oldRow = getRowIndex();
+    int first = getFirst();
+    int last = TableUtils.getLast(this, first);
+
+    try
+    {
+      for(int i = first; i <= last; i++)
+      {
+        setRowIndex(i);
+        if (!stamps.isEmpty())
+        {
+          for (UIComponent currStamp : stamps)
+          {
+            // visit the stamps.  If we have visited all of the visit targets then return early
+            if (UIXComponent.visitTree(visitContext, currStamp, callback))
+              return true;
+          }
+        }
+
+        if (isContainer() && ((disclosedRowKeys == null) || disclosedRowKeys.isContained()))
+        {
+          enterContainer();
+
+          try
+          {
+            // visit this container.  If we have visited all of the visit targets then return early
+            if (visitHierarchy(visitContext, callback, stamps, disclosedRowKeys))
+              return true;
+          }
+          finally
+          {
+            exitContainer();
+          }
+        }
+      }
+    }
+    finally
+    {
+      setRowIndex(oldRow);
+    }
+
+    return false;
+  }
 }
diff --git a/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/visit/VisitContextWrapper.java b/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/visit/VisitContextWrapper.java
new file mode 100644
index 0000000..3a0345b
--- /dev/null
+++ b/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/visit/VisitContextWrapper.java
@@ -0,0 +1,80 @@
+/*
+ *  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.visit;
+
+import java.util.Collection;
+import java.util.Set;
+
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+import javax.faces.event.PhaseId;
+
+
+/**
+ * A port of the JSF 2 <code>VisitContextWrapper</code> class so that we may be able to use
+ * its functionality in JSF 1.2 with Trinidad 1.2
+ */
+public abstract class VisitContextWrapper
+  extends VisitContext
+{
+  /**
+   * Get the wrapped visit context
+   */
+  public abstract VisitContext getWrapped();
+
+  @Override
+  public FacesContext getFacesContext()
+  {
+    return getWrapped().getFacesContext();
+  }
+
+  @Override
+  public PhaseId getPhaseId()
+  {
+    return getWrapped().getPhaseId();
+  }
+
+  @Override
+  public Set<VisitHint> getHints()
+  {
+    return getWrapped().getHints();
+  }
+
+  @Override
+  public Collection<String> getIdsToVisit()
+  {
+    return getWrapped().getIdsToVisit();
+  }
+
+  @Override
+  public Collection<String> getSubtreeIdsToVisit(
+    UIComponent component)
+  {
+    return getWrapped().getSubtreeIdsToVisit(component);
+  }
+
+  @Override
+  public VisitResult invokeVisitCallback(
+    UIComponent   component,
+    VisitCallback callback)
+  {
+    return getWrapped().invokeVisitCallback(component, callback);
+  }
+}
diff --git a/trinidad-api/src/main/java/org/apache/myfaces/trinidad/render/CoreRenderer.java b/trinidad-api/src/main/java/org/apache/myfaces/trinidad/render/CoreRenderer.java
index 63f6dc4..366fbe0 100644
--- a/trinidad-api/src/main/java/org/apache/myfaces/trinidad/render/CoreRenderer.java
+++ b/trinidad-api/src/main/java/org/apache/myfaces/trinidad/render/CoreRenderer.java
@@ -161,6 +161,46 @@ public class CoreRenderer extends Renderer
       tearDownEncodingContext(context, rc, (UIXComponent)component);
   }
 
+  /**
+   * Hook to allow the renderer to customize the visitation of the children components
+   * of a component during the visitation of a component during rendering.
+   *
+   * @param component the component which owns the children to visit
+   * @param visitContext the visitation context
+   * @param callback the visit callback
+   * @return <code>true</code> if the visit is complete.
+   * @see UIXComponent#visitChildren(VisitContext, VisitCallback)
+   */
+  public boolean visitChildrenForEncoding(
+    UIXComponent  component,
+    VisitContext  visitContext,
+    VisitCallback callback)
+  {
+    // visit the children of the component
+    Iterator<UIComponent> kids = component.getFacetsAndChildren();
+
+    while (kids.hasNext())
+    {
+      // If any kid visit returns true, we are done.
+      UIComponent kid = kids.next();
+      if (kid instanceof UIXComponent)
+      {
+        if (((UIXComponent)kid).visitTree(visitContext, callback))
+        {
+          return true;
+        }
+      }
+      else
+      {
+        if (UIXComponent.visitTree(visitContext, kid, callback))
+        {
+          return true;
+        }
+      }
+    }
+
+    return false;
+  }
 
   //
   // COERCION HELPERS
@@ -684,9 +724,9 @@ public class CoreRenderer extends Renderer
   {
     return (Agent.PLATFORM_GENERICPDA.equals(rc.getAgent().getPlatformName()));
   }
-  
+
   /**
-   * This method returns true if a user-agent's platform is NokiaS60 
+   * This method returns true if a user-agent's platform is NokiaS60
    * @param arc - RenderingContext of a request
    * @return boolean
    */

-- 
To stop receiving notification emails like this one, please contact
"commits@myfaces.apache.org" <co...@myfaces.apache.org>.