incubator-adffaces-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Pavitra Subramaniam" <pavitra.subraman...@oracle.com>
Subject RE: svn commit: r451772 [1/8] - in /incubator/adffaces/trunk/trinidad: src/site/xdoc/ trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/desktop/ trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/xh
Date Mon, 02 Oct 2006 19:13:44 GMT
Hello Simon,

Thanks for checking in the new train renderer. I have one comment.

Can you update the af|train::link to be af|train::stop-link, like we agreed upon? ::link is too generic as I have to support a version where the stop icons are links besides the stop label as well. 
Other than that everything else is fine.

Thanks
- Pavitra
 

> -----Original Message-----
> From: slessard@apache.org [mailto:slessard@apache.org] 
> Sent: Sunday, October 01, 2006 10:27 AM
> To: adffaces-commits@incubator.apache.org
> Subject: svn commit: r451772 [1/8] - in 
> /incubator/adffaces/trunk/trinidad: src/site/xdoc/ 
> trinidad-impl/src/main/java/org/apache/myfaces/trinidadinterna
l/renderkit/core/desktop/ trinidad-> impl/src/main/java/org/apache/myfaces/trinidadinternal/renderk
> it/core/xht...
> 
> Author: slessard
> Date: Sun Oct  1 10:26:55 2006
> New Revision: 451772
> 
> URL: http://svn.apache.org/viewvc?view=rev&rev=451772
> Log:
> Applied patch for ADFFACES-60 with some small changes to 
> compile with the new public rendering API.
> 
> Modified:
>     incubator/adffaces/trunk/trinidad/src/site/xdoc/skin-selectors.xml
>     
> incubator/adffaces/trunk/trinidad/trinidad-impl/src/main/java/
org/apache/myfaces/trinidadinternal/renderkit/core/desktop/TrainRenderer.> java
>     
> incubator/adffaces/trunk/trinidad/trinidad-impl/src/main/java/
org/apache/myfaces/trinidadinternal/renderkit/core/xhtml/SkinProperties.j> ava
>     
> incubator/adffaces/trunk/trinidad/trinidad-impl/src/main/java/
org/apache/myfaces/trinidadinternal/renderkit/core/xhtml/SkinSelectors.ja> va
>     
> incubator/adffaces/trunk/trinidad/trinidad-impl/src/main/resou
rces/META-INF/adf/styles/base-desktop.xss
>     
> incubator/adffaces/trunk/trinidad/trinidad-impl/src/main/resou
rces/META-INF/adf/styles/minimal-desktop.xss
>     
> incubator/adffaces/trunk/trinidad/trinidad-impl/src/test/resou
rces/org/apache/myfaces/trinidadinternal/renderkit/golden/train-minimal-> golden.xml
>     
> incubator/adffaces/trunk/trinidad/trinidad-impl/src/test/resou
rces/org/apache/myfaces/trinidadinternal/renderkit/golden/train-> minimalIE-golden.xml
>     
> incubator/adffaces/trunk/trinidad/trinidad-impl/src/test/resou
rces/org/apache/myfaces/trinidadinternal/renderkit/golden/train-> minimalIERtl-golden.xml
>     
> incubator/adffaces/trunk/trinidad/trinidad-impl/src/test/resou
rces/org/apache/myfaces/trinidadinternal/renderkit/golden/train-> minimalInacc-golden.xml
>     
> incubator/adffaces/trunk/trinidad/trinidad-impl/src/test/resou
rces/org/apache/myfaces/trinidadinternal/renderkit/golden/train-> minimalSaf-golden.xml
>     
> incubator/adffaces/trunk/trinidad/trinidad-impl/src/test/resou
rces/org/apache/myfaces/trinidadinternal/renderkit/golden/train-> minimalScrRdr-golden.xml
> 
> Modified: 
> incubator/adffaces/trunk/trinidad/src/site/xdoc/skin-selectors.xml
> URL: 
> http://svn.apache.org/viewvc/incubator/adffaces/trunk/trinidad
> /src/site/xdoc/skin-selectors.xml?view=diff&rev=451772&r1=4517
> 71&r2=451772
> ==============================================================
> ================
> --- 
> incubator/adffaces/trunk/trinidad/src/site/xdoc/skin-selectors
> .xml (original)
> +++ 
> incubator/adffaces/trunk/trinidad/src/site/xdoc/skin-selectors
> .xml Sun Oct  1 10:26:55 2006
> @@ -2954,7 +2954,52 @@
>            </tr>
>          </table>
>        </subsection>
> -      <subsection name="tr:processTrain Component">
> +      <subsection name="tr:train Component">
> +        <table>
> +          <tr>
> +            <th colspan="2">
> +              <i>Properties</i>
> +            </th>
> +          </tr>
> +          <tr>
> +            <th>Name</th>
> +            <th>Description</th>
> +          </tr>
> +          <tr>
> +            <td>-ora-render-parent-train</td>
> +            <td>Boolean value that specifies if parent train 
> icons should be
> +                rendered if this train is a sub-train. A 
> sub-train is a process
> +                not located at the root of its TreeModel.</td>
> +          </tr>
> +          <tr>
> +            <td>-ora-visible-stop-count</td>
> +            <td>Strictly positive integer value specifying 
> the maximum amount of
> +                stops visible at a time.</td>
> +          </tr>
> +        </table>
> +        <table>
> +          <tr>
> +            <th colspan="2">
> +              <i>Aliases</i>
> +            </th>
> +          </tr>
> +          <tr>
> +            <th>Name</th>
> +            <th>Description</th>
> +          </tr>
> +          <tr>
> +            <td>.AFTrainContent:alias</td>
> +            <td>Styles all train station content.</td>
> +          </tr>
> +          <tr>
> +            <td>.AFTrainIconCell:alias</td>
> +            <td>Styles all train station icons.</td>
> +          </tr>
> +          <tr>
> +            <td>.AFTrainJoin:alias</td>
> +            <td>Styles all train station joins.</td>
> +          </tr>
> +        </table>
>          <table>
>            <tr>
>              <th colspan="2">
> @@ -2966,33 +3011,215 @@
>              <th>Description</th>
>            </tr>
>            <tr>
> -            <td>af|processTrain::step-active</td>
> -            <td>Styles the active train station.</td>
> +            <td>af|train</td>
> +            <td>Styles the whole train.</td>
> +          </tr>
> +          <tr>
> +            <td>af|train::stop</td>
> +            <td>Styles a train stop. A stop include both the 
> icon and its content.
> +                This selector is often combined with one or 
> more station pseudo-classes like
> +                :selected, :unvisited, :disabled, :read-only 
> and .p_AFVisited and
> +                used in descendant selector, e.g. 
> "af|train::stop:unvisited af|train::link"
> +                would style the link generated for an 
> unvisited stop.</td>
> +          </tr>
> +          <tr>
> +            <td>af|train::stop-icon-cell</td>
> +            <td>Styles the icon section of the stop. This 
> selector is combinable
> +                with state pseudo-classes. This selector 
> includes .AFTrainIconCell:alias.
> +                </td>
>            </tr>
>            <tr>
> -            <td>af|processTrain::step-visited</td>
> -            <td>Styles the visited train stations.</td>
> +            <td>af|train::stop-content</td>
> +            <td>Styles the content section of the stop. This 
> selector is combinable
> +                with state pseudo-classes. This selector 
> includes .AFTrainContent:alias.
> +                </td>
>            </tr>
>            <tr>
> -            <td>af|processTrain::step-disabled</td>
> -            <td>Styles the disabled train stations.</td>
> +            <td>af|train::join</td>
> +            <td>Styles the join between stop icons. This 
> selector is combinable with state
> +                pseudo-classes, except :selected. This 
> selector includes .AFTrainJoin:alias.
> +                </td>
>            </tr>
>            <tr>
> -            <td>af|processTrain::step-unvisited</td>
> -            <td>Styles the unvisited train stations.</td>
> +            <td>af|train::overflow-start</td>
> +            <td>Styles a train start overflow. A start 
> overflow is generated when the amount
> +                of steps in the process is higher than the 
> amount of visibled stop defined by
> +                the -ora-visible-stop-count property. In LTR 
> mode, this selector represents
> +                the left side overflow (previous step 
> group). This selector includes both the
> +                icon and its content. This selector is 
> combinable with state pseudo-classes.</td>
>            </tr>
>            <tr>
> -            <td>.AFTrainStation:alias</td>
> -            <td>Style that is included by all of the 
> af|processTrain* style
> -                classes.</td>
> +            <td>af|train::overflow-start-icon-cell</td>
> +            <td>Styles the icon section of the 
> overflow-start. This selector is combinable
> +                with state pseudo-classes. This selector 
> includes .AFTrainIconCell:alias.
> +                </td>
>            </tr>
>            <tr>
> -            <td>af|processTrain::step-visited 
> af|processTrain:: link</td>
> -            <td>Styles the visited train stations links.</td>
> +            <td>af|train::overflow-start-content</td>
> +            <td>Styles the content section of the 
> overflow-start. This selector is combinable
> +                with state pseudo-classes. This selector 
> includes .AFTrainContent:alias.
> +                </td>
> +          </tr>
> +          <tr>
> +            <td>af|train::overflow-end</td>
> +            <td>Styles a train end overflow. A end overflow 
> is generated when the amount
> +                of steps in the process is higher than the 
> amount of visibled stop defined by
> +                the -ora-visible-stop-count property. In LTR 
> mode, this selector represents
> +                the right side overflow (next step group). 
> This selector includes both the
> +                icon and its content. This selector is 
> combinable with state pseudo-classes.</td>
> +          </tr>
> +          <tr>
> +            <td>af|train::overflow-end-icon-cell</td>
> +            <td>Styles the icon section of the overflow-end. 
> This selector is combinable
> +                with state pseudo-classes. This selector 
> includes .AFTrainIconCell:alias.
> +                </td>
> +          </tr>
> +          <tr>
> +            <td>af|train::overflow-end-content</td>
> +            <td>Styles the content section of the 
> overflow-end. This selector is combinable
> +                with state pseudo-classes. This selector 
> includes .AFTrainContent:alias.
> +                </td>
> +          </tr>
> +          <tr>
> +            <td>af|train::join-overflow</td>
> +            <td>Styles the join between overflows and stop 
> icons. This selector is combinable
> +                with state pseudo-classes, except :selected. 
> This selector includes
> +                .AFTrainJoin:alias.</td>
> +          </tr>
> +          <tr>
> +            <td>af|train::parent-start</td>
> +            <td>Styles a train start parent. A parent is 
> generated when the current train is
> +                not located at the root of its TreeModel and 
> that -ora-render-parent-train
> +                property is set to true. In LTR mode this 
> will be rendered to the left of the
> +                first step's stop. This selector includes 
> both the icon and its content.
> +                This selector is NOT combinable with state 
> pseudo-classes.</td>
> +          </tr>
> +          <tr>
> +            <td>af|train::parent-start-icon-cell</td>
> +            <td>Styles the icon section of the parent-start. 
> This selector is NOT combinable
> +                with state pseudo-classes. This selector 
> includes .AFTrainIconCell:alias.
> +                </td>
> +          </tr>
> +          <tr>
> +            <td>af|train::parent-start-content</td>
> +            <td>Styles the content section of the 
> parent-start. This selector is NOT combinable
> +                with state pseudo-classes. This selector 
> includes .AFTrainContent:alias.
> +                </td>
> +          </tr>
> +          <tr>
> +            <td>af|train::parent-end</td>
> +            <td>Styles a train end parent. A parent is 
> generated when the current train is
> +                not located at the root of its TreeModel and 
> that -ora-render-parent-train
> +                property is set to true. In LTR mode this 
> will be rendered to the right of
> +                the last step's stop. This selector includes 
> both the icon and its content.
> +                This selector is NOT combinable with state 
> pseudo-classes.</td>
> +          </tr>
> +          <tr>
> +            <td>af|train::parent-end-icon-cell</td>
> +            <td>Styles the icon section of the parent-end. 
> This selector is NOT combinable
> +                with state pseudo-classes. This selector 
> includes .AFTrainIconCell:alias.
> +                </td>
> +          </tr>
> +          <tr>
> +            <td>af|train::parent-end-content</td>
> +            <td>Styles the content section of the 
> parent-end. This selector is NOT combinable
> +                with state pseudo-classes. This selector 
> includes .AFTrainContent:alias.
> +                </td>
> +          </tr>
> +          <tr>
> +            <td>af|train::join-parent</td>
> +            <td>Styles the join between parent and stop 
> icons. This selector is NOT combinable
> +                with state pseudo-classes. This selector 
> includes .AFTrainJoin:alias.</td>
> +          </tr>
> +          <tr>
> +            <td>af|train::link</td>
> +            <td>Styles the links generated within the stop's 
> content. This selector is
> +                NOT combinable with state pseudo-classes</td>
> +          </tr>
> +        </table>
> +        <table>
> +          <tr>
> +            <th colspan="2">
> +              <i>Icons</i>
> +            </th>
> +          </tr>
> +          <tr>
> +            <th>Name</th>
> +            <th>Description</th>
>            </tr>
>            <tr>
> -            <td>af|processTrain::step-unvisited 
> af|processTrain::link</td>
> -            <td>Styles the unvisited train stations links.</td>
> +            <td colspan="2">
> +              Stop and overflow icons are combinable with 
> one or more state pseudo-classes.
> +              For example, it's possible to build icons for 
> a very specific situations like
> +              a read-only visited stop being different from 
> a read-only unvisited stop. The
> +              valid classes are:
> +              <ul>
> +                <li>:visited for steps that were already 
> completed (assumed to be all steps
> +                    before the current one, this might 
> change in the future);</li>
> +                <li>:selected for the current step. This 
> state is not available to overflows;
> +                    </li>
> +                <li>:unvisited for steps that were not 
> completed by the user (assumed to be
> +                    all steps after the current one, this 
> might change in the future);</li>
> +                <li>:read-only for steps that cannot be 
> accessed directly by the user by
> +                    clicking on the link (clicking on the 
> icon is not implemented at this
> +                    time). This state is combinable with any 
> of the previous three states,
> +                    but must be placed after them, e.g. 
> :selected:read-only-icon is valid,
> +                    while :read-only:selected is not;</li>
> +                <li>:disabled for steps that cannot be 
> accessed by the user using the link
> +                    and should theorically not be accessible 
> at all until some condition is
> +                    met. This state has absolute priority 
> and is not combinable with any other
> +                    state.</li>
> +              </ul>
> +            </td>
> +          </tr>
> +          <tr>
> +            <td>af|train::stop&lt;states&gt;-icon</td>
> +            <td>Define the icons for stops. At least one 
> state must be specified.
> +                For example:
> +                <ul>
> +                  <li>VALID: af|train::stop:selected-icon;</li>
> +                  <li>INVALID: af|train::stop-icon;</li>
> +                </ul></td>
> +          </tr>
> +          <tr>
> +            <td>af|train::overflow-start&lt;states&gt;-icon</td>
> +            <td>Define the icons for overflows toward the 
> previous step group. At least one
> +                state must be specified.
> +                For example:
> +                <ul>
> +                  <li>VALID: 
> af|train::overflow-start:read-only-icon;</li>
> +                  <li>INVALID: af|train::overflow-start-icon;</li>
> +                </ul></td>
> +          </tr>
> +          <tr>
> +            <td>af|train::overflow-end&lt;states&gt;-icon</td>
> +            <td>Define the icons for overflows toward the 
> next step group. At least one
> +                state must be specified.
> +                For example:
> +                <ul>
> +                  <li>VALID: 
> af|train::overflow-end:read-only-icon;</li>
> +                  <li>INVALID: af|train::overflow-end-icon;</li>
> +                </ul></td>
> +          </tr>
> +          <tr>
> +            <td>af|train::parent-start&lt;states&gt;-icon</td>
> +            <td>Define the icons for the parent train that 
> include this train.
> +                It appears before the first stop's icon. 
> This icon is NOT
> +                combinable with state pseudo-classes. For example:
> +                <ul>
> +                  <li>VALID: af|train::parent-start-icon;</li>
> +                  <li>INVALID: 
> af|train::parent-start:read-only-icon;</li>
> +                </ul></td>
> +          </tr>
> +          <tr>
> +            <td>af|train::parent-end&lt;states&gt;-icon</td>
> +            <td>Define the icons for the parent train that 
> follow the parent train
> +                including this train. It appears after the 
> last stop's icon. This
> +                icon is NOT combinable with state 
> pseudo-classes. For example:
> +                <ul>
> +                  <li>VALID: af|train::parent-end-icon;</li>
> +                  <li>INVALID: 
> af|train::parent-end:read-only-icon;</li>
> +                </ul></td>
>            </tr>
>          </table>
>        </subsection>
> @@ -3119,7 +3346,7 @@
>            </tr>
>          </table>
>        </subsection>
> -      <subsection name="tr:selectInputDate Component">
> +      <subsection name="tr:inputDate Component">
>          <table>
>            <tr>
>              <th colspan="2">
> 
> Modified: 
> incubator/adffaces/trunk/trinidad/trinidad-impl/src/main/java/
org/apache/myfaces/trinidadinternal/renderkit/core/desktop/TrainRenderer.> java
> URL: 
> http://svn.apache.org/viewvc/incubator/adffaces/trunk/trinidad
> /trinidad-impl/src/main/java/org/apache/myfaces/trinidadintern
al/renderkit/core/desktop/TrainRenderer.java?view=diff&rev=451772&r1=> 451771&r2=451772
> ==============================================================
> ================
> --- 
> incubator/adffaces/trunk/trinidad/trinidad-impl/src/main/java/
org/apache/myfaces/trinidadinternal/renderkit/core/desktop/TrainRenderer.> java (original)
> +++ 
> incubator/adffaces/trunk/trinidad/trinidad-impl/src/main/java/
org/apache/myfaces/trinidadinternal/renderkit/core/desktop/TrainRenderer.> java Sun Oct  1 10:26:55 2006
> @@ -18,8 +18,14 @@
>  
>  
>  import java.io.IOException;
> -import java.util.HashMap;
> +import java.util.ArrayList;
> +import java.util.Collections;
> +import java.util.Iterator;
> +import java.util.LinkedList;
> +import java.util.List;
> +import java.util.ListIterator;
>  import java.util.Map;
> +import java.util.TreeMap;
>  
>  import javax.faces.component.UIComponent;
>  import javax.faces.context.FacesContext;
> @@ -29,11 +35,14 @@
>  import org.apache.myfaces.trinidad.bean.FacesBean;
>  import org.apache.myfaces.trinidad.component.UIXProcess;
>  import org.apache.myfaces.trinidad.component.core.nav.CoreTrain;
> -import org.apache.myfaces.trinidad.logging.TrinidadLogger;
> +import org.apache.myfaces.trinidad.context.Agent;
>  import org.apache.myfaces.trinidad.context.FormData;
>  import org.apache.myfaces.trinidad.context.RenderingContext;
> +import org.apache.myfaces.trinidad.logging.TrinidadLogger;
> +import org.apache.myfaces.trinidad.skin.Icon;
>  import 
> org.apache.myfaces.trinidadinternal.renderkit.core.xhtml.OutputUtils;
>  import 
> org.apache.myfaces.trinidadinternal.renderkit.core.xhtml.ProcessUtils;
> +import 
> org.apache.myfaces.trinidadinternal.renderkit.core.xhtml.SkinP
> roperties;
>  import 
> org.apache.myfaces.trinidadinternal.renderkit.core.xhtml.SkinS
> electors;
>  import 
> org.apache.myfaces.trinidadinternal.renderkit.core.xhtml.Xhtml
> Constants;
>  import 
> org.apache.myfaces.trinidadinternal.renderkit.core.xhtml.Xhtml
> Renderer;
> @@ -41,7 +50,7 @@
>  
>  /**
>   * Renderer for process train components
> - * * <p>
> + *
>   */
>  public class TrainRenderer
>    extends XhtmlRenderer
> @@ -144,49 +153,78 @@
>  
>    @Override
>    protected void encodeAll(
> -    FacesContext context,
> +    FacesContext     context,
>      RenderingContext arc,
> -    UIComponent component,
> -    FacesBean bean)
> +    UIComponent      component,
> +    FacesBean        bean)
>      throws IOException
>    {
> +    if(!(component instanceof UIXProcess))
> +    {
> +      throw new ClassCastException("TrainRenderer can only 
> renders instances of " +
> +                                   UIXProcess.class.getName() +
> +                                   ", found " +
> +                                   component.getClass().getName());
> +    }
> +
>      UIXProcess process = (UIXProcess) component;
>      UIComponent stamp = process.getNodeStamp();
>  
>      if (stamp != null)
>      {
> -      Object oldPath = process.getRowKey();
> -      Object newPath = null;
> -      boolean isNewPath = _setNewPath(process);
> -      if (isNewPath)
> +      Train train = new Train(context, arc, process, stamp);
> +      try
>        {
> +        process.setRowKey(train.getFocusRowKey());
> +
> +        // Renders some fields and scripts
> +        _renderHiddenFields(context, arc, train);
> +
>          ResponseWriter writer = context.getResponseWriter();
> -
> -        TrainRenderer.TrainState trainState =
> -        _getTrainState(context, arc, process);
> -        _renderHiddenFields(context, arc, trainState);
> -
> -        writer.startElement("table", component);
> -        OutputUtils.renderLayoutTableAttributes(context, 
> arc, "0", null);
> -        writer.writeAttribute("align", "center", null);
> -        newPath = process.getRowKey();
> -        process.setRowKey(oldPath);
> +
> +        // Need to render the frame even if there's no 
> visible station
> +        // to support PPR.
> +        writer.startElement(XhtmlConstants.TABLE_ELEMENT, component);
> +        process.setRowKey(train.getInitialRowKey());
>          renderId(context, component);
> -        process.setRowKey(newPath);
>          renderAllAttributes(context, arc, bean);
> -
> -        int length = process.getRowCount();
> -
> -        if (length == 0)
> -          return;
> -
> -        _encodeChildren(context, arc, process, stamp, 
> trainState, length);
> -
> -        writer.endElement("table");
> -
> -        process.setRowKey(oldPath);
> +        // Does not seem to be needed and this is not XHTML 
> 1.0 Strict compliant
> +        // writer.writeAttribute("align", "center", null);
> +
> +        if(!train.getStations().isEmpty())
> +        {
> +          // There're visible stations currently, let render them.
> +          
> writer.startElement(XhtmlConstants.TABLE_BODY_ELEMENT, null);
> +          _renderTrain(context, arc, process, bean, stamp, train);
> +          writer.endElement(XhtmlConstants.TABLE_BODY_ELEMENT);
> +        }
> +
> +        writer.endElement(XhtmlConstants.TABLE_ELEMENT);
>        }
> +      finally
> +      {
> +        // Always restore the model, whatever happened
> +        process.setRowKey(train.getInitialRowKey());
> +      }
> +    }
> +    else
> +    {
> +      _LOG.warning("Train expect a nodeStamp facet, " +
> +          "no such facet was found for train " + component);
>      }
> +    /*
> +      _encodeChildren(context, arc, process, stamp, 
> trainState, length);
> +    */
> +  }
> +
> +  @Override
> +  protected void renderAllAttributes(
> +      FacesContext     context,
> +      RenderingContext arc,
> +      FacesBean        bean) throws IOException
> +  {
> +    super.renderAllAttributes(context, arc, bean);
> +    OutputUtils.renderLayoutTableAttributes(context, arc, "0", null);
>    }
>  
>    /**
> @@ -195,603 +233,1631 @@
>     */
>    @Override
>    protected void renderStyleAttributes(
> -    FacesContext context,
> +    FacesContext     context,
>      RenderingContext arc,
> -    FacesBean bean)
> +    FacesBean        bean)
>      throws IOException
>    {
> -    renderStyleAttributes(context, arc, bean,
> -                          
> SkinSelectors.AF_PROCESS_TRAIN_STYLE_CLASS);
> +    renderStyleAttributes(context,
> +                          arc,
> +                          bean,
> +                          SkinSelectors.AF_TRAIN_ROOT_STYLE_CLASS);
> +  }
> +
> +  private void _preRenderIconBlock(
> +      FacesContext     context,
> +      RenderingContext arc) throws IOException
> +  {
> +    ResponseWriter writer = context.getResponseWriter();
> +
> +    // Icon cell
> +    writer.startElement(XhtmlConstants.TABLE_DATA_ELEMENT, null);
> +
> +    // Icons need to be in a table to stretch well
> +    writer.startElement(XhtmlConstants.TABLE_ELEMENT, null);
> +    OutputUtils.renderLayoutTableAttributes(context, arc, "0", null);
> +    writer.writeAttribute(XhtmlConstants.STYLE_ATTRIBUTE, 
> "width: 100%", null);
> +
> +    writer.startElement(XhtmlConstants.TABLE_BODY_ELEMENT, null);
> +    writer.startElement(XhtmlConstants.TABLE_ROW_ELEMENT, null);
> +  }
> +
> +  private void _postRenderIconBlock(FacesContext context) 
> throws IOException
> +  {
> +    ResponseWriter writer = context.getResponseWriter();
> +
> +    writer.endElement(XhtmlConstants.TABLE_ROW_ELEMENT);
> +    writer.endElement(XhtmlConstants.TABLE_BODY_ELEMENT);
> +    writer.endElement(XhtmlConstants.TABLE_ELEMENT);
> +    writer.endElement(XhtmlConstants.TABLE_DATA_ELEMENT);
>    }
>  
> -
> -  /**
> -  * Initialize the station state
> -  */
> -  private void _initializeStationState(
> -    FacesContext context,
> +  private void _renderHiddenFields(
> +    FacesContext     context,
>      RenderingContext arc,
> -    TrainRenderer.TrainState train,
> -    TrainRenderer.StationState station,
> -    int currVisChildIndex,
> -    int prevVisChildIndex,
> -    int nextVisChildIndex,
> -    boolean isCurrChildDisabled,
> -    boolean isPrevChildDisabled,
> -    boolean isNextChildDisabled)
> +    Train            train)
> +    throws IOException
>    {
> -    station.isPreviousLink = false;
> -    station.isMoreLink = false;
> -    station.isDisabled = false;
> -    station.isNextDisabled = false;
> -    station.isPrevDisabled = false;
> -    station.index = currVisChildIndex;
> +    if((train.getFormName() != null) && supportsScripting(arc))
> +    {
> +      // render hidden fields to hold the form data
> +      FormData formData = arc.getFormData();
> +      if (formData != null)
> +      {
> +        formData.addNeededValue(XhtmlConstants.EVENT_PARAM);
> +        formData.addNeededValue(XhtmlConstants.SOURCE_PARAM);
> +        formData.addNeededValue(XhtmlConstants.VALUE_PARAM);
> +        formData.addNeededValue(XhtmlConstants.SIZE_PARAM);
> +      }
>  
> -    // train.startIndex is the index into the List that is the
> -    // start of the train. The algorithm is dependent upon 
> the BLAF spec.
> -    if (currVisChildIndex == train.startIndex - 1)
> +      // Render script submission code.
> +      ProcessUtils.renderNavSubmitScript(context, arc);
> +    }
> +  }
> +
> +  private void _renderContentRowLtr(
> +      FacesContext     context,
> +      RenderingContext arc,
> +      UIXProcess       process,
> +      UIComponent      stamp,
> +      Train            train) throws IOException
> +  {
> +    ParentTrain parentTrain = train.getParentTrain();
> +
> +    // Render parent start
> +    if(parentTrain != null && parentTrain.hasParentStart())
> +    {
> +      _renderParentContent(context, arc, 
> parentTrain.getParentStart());
> +    }
> +
> +    for(Station station : train.getStations())
> +    {
> +      _renderStationContent(context, arc, process, stamp, station);
> +    }
> +
> +    // Render parent end
> +    if(parentTrain != null && parentTrain.hasParentEnd())
>      {
> -      station.isPreviousLink = true;
> +      _renderParentContent(context, arc, parentTrain.getParentEnd());
>      }
> -    else if (currVisChildIndex == train.startIndex + 
> _MAX_NUM_LINK_INDEX)
> +  }
> +
> +  private void _renderContentRowRtl(
> +      FacesContext     context,
> +      RenderingContext arc,
> +      UIXProcess       process,
> +      UIComponent      stamp,
> +      Train            train) throws IOException
> +  {
> +    ParentTrain parentTrain = train.getParentTrain();
> +
> +    // Render parent start
> +    if(parentTrain != null && parentTrain.hasParentEnd())
> +    {
> +      _renderParentContent(context, arc, parentTrain.getParentEnd());
> +    }
> +
> +    List<Station>         stations = train.getStations();
> +    ListIterator<Station> iterator = 
> stations.listIterator(stations.size());
> +    while(iterator.hasPrevious())
> +    {
> +      _renderStationContent(context, arc, process, stamp, 
> iterator.previous());
> +    }
> +
> +    // Render parent end
> +    if(parentTrain != null && parentTrain.hasParentStart())
>      {
> -      station.isMoreLink = true;
> +      _renderParentContent(context, arc, 
> parentTrain.getParentStart());
>      }
> +  }
> +
> +  private void _renderIconBlock(
> +      FacesContext     context,
> +      RenderingContext arc,
> +      List<String>     iconNames,
> +      String           shortDesc,
> +      String           styleClass,
> +      String           iconStyleClass,
> +      List<String>     stateStyleClasses) throws IOException
> +  {
> +    ResponseWriter writer = context.getResponseWriter();
>  
> -    // selected nodes cannot be disabled,
> -    // so don't bother getting disabled attribute for the 
> selected node
> -
> -    if (currVisChildIndex != NO_CHILD_INDEX &&
> -        currVisChildIndex != train.selectedIndex)
> +    writer.startElement(XhtmlConstants.TABLE_DATA_ELEMENT, null);
> +
> +    stateStyleClasses.add(styleClass);
> +    stateStyleClasses.add(iconStyleClass);
> +
> +    renderStyleClasses(context,
> +                       arc,
> +                       
> stateStyleClasses.toArray(_EMPTY_STRING_ARRAY));
> +
> +    if(iconNames != null)
> +    {
> +      // Render the first valid icon found. The list should be in
> +      // decreasing priority order.
> +      for(String iconName : iconNames)
> +      {
> +        Icon icon = arc.getIcon(iconName);
> +        if(icon != null)
> +        {
> +          OutputUtils.renderIcon(context, arc, icon, 
> shortDesc, null);
> +          break;
> +        }
> +      }
> +    }
> +
> +    writer.endElement(XhtmlConstants.TABLE_DATA_ELEMENT);
> +  }
> +
> +  private void _renderIconRowLtr(
> +      FacesContext     context,
> +      RenderingContext arc,
> +      UIXProcess       process,
> +      UIComponent      stamp,
> +      Train            train) throws IOException
> +  {
> +    ParentTrain parentTrain = train.getParentTrain();
> +
> +    // Render parent start
> +    if(parentTrain != null && parentTrain.hasParentStart())
> +    {
> +      _renderParentStartLtr(context, arc, process, train);
> +    }
> +
> +    for(Station station : train.getStations())
> +    {
> +      _renderStationIconLtr(context, arc, process, station);
> +    }
> +
> +    // Render parent end
> +    if(parentTrain != null && parentTrain.hasParentEnd())
>      {
> -      station.isDisabled = isCurrChildDisabled;
> +      _renderParentEndLtr(context, arc, process, train);
>      }
> -
> -    // get disabled information about the previous and the 
> next child.
> -    // selectedIndex cannot act disabled
> -    //
> -    if (prevVisChildIndex != NO_CHILD_INDEX &&
> -        prevVisChildIndex != train.selectedIndex)
> +  }
> +
> +  private void _renderIconRowRtl(
> +      FacesContext     context,
> +      RenderingContext arc,
> +      UIXProcess       process,
> +      UIComponent      stamp,
> +      Train            train) throws IOException
> +  {
> +    ParentTrain parentTrain = train.getParentTrain();
> +
> +    // Render parent end
> +    if(parentTrain != null && parentTrain.hasParentEnd())
> +    {
> +      _renderParentEndRtl(context, arc, process, train);
> +    }
> +
> +    List<Station>         stations = train.getStations();
> +    ListIterator<Station> iterator = 
> stations.listIterator(stations.size());
> +    while(iterator.hasPrevious())
> +    {
> +      _renderStationIconRtl(context, arc, process, 
> iterator.previous());
> +    }
> +
> +    // Render parent start
> +    if(parentTrain != null && parentTrain.hasParentStart())
>      {
> -      station.isPrevDisabled = isPrevChildDisabled;
> +      _renderParentStartRtl(context, arc, process, train);
>      }
> -
> -    if (nextVisChildIndex != NO_CHILD_INDEX &&
> -        nextVisChildIndex != train.selectedIndex)
> +
> +  }
> +
> +  private void _renderJoin(
> +      FacesContext     context,
> +      RenderingContext arc,
> +      String           stateStyleClass,
> +      boolean          overflow) throws IOException
> +  {
> +    if(stateStyleClass == _STATE_PARENT)
> +    {
> +      _renderJoin(context,
> +                  arc,
> +                  SkinSelectors.AF_TRAIN_PARENT_JOIN_STYLE_CLASS,
> +                  null);
> +    }
> +    else if(overflow)
> +    {
> +      _renderJoin(context,
> +                  arc,
> +                  SkinSelectors.AF_TRAIN_OVERFLOW_JOIN_STYLE_CLASS,
> +                  stateStyleClass);
> +    }
> +    else
>      {
> -      station.isNextDisabled = isNextChildDisabled;
> -
> +      _renderJoin(context,
> +                  arc,
> +                  SkinSelectors.AF_TRAIN_JOIN_STYLE_CLASS,
> +                  stateStyleClass);
>      }
> +  }
> +
> +  private void _renderJoin(
> +      FacesContext     context,
> +      RenderingContext arc,
> +      String           joinStyleClass,
> +      String           stateStyleClass) throws IOException
> +  {
> +    ResponseWriter writer = context.getResponseWriter();
>  
> -    //
> -    // get the selected and visited flags for our node
> -    //
> -    station.isSelected = (currVisChildIndex == train.selectedIndex);
> -    station.isVisited = (currVisChildIndex <= train.maxVisitedIndex);
> -    station.isNextVisited = (currVisChildIndex < 
> train.maxVisitedIndex);
> -    station.isNext = (currVisChildIndex == 
> (train.maxVisitedIndex + 1));
> -    // if previous station is "next", and disabled, mark 
> this as "next".
> -    if ((currVisChildIndex - 1 == (train.maxVisitedIndex + 1)) &&
> -        (station.isPrevDisabled))
> +    writer.startElement(XhtmlConstants.TABLE_DATA_ELEMENT, null);
> +    renderStyleClasses(context,
> +                       arc,
> +                       new String[]{
> +                         joinStyleClass,
> +                         stateStyleClass});
> +
> +    writer.endElement(XhtmlConstants.TABLE_DATA_ELEMENT);
> +  }
> +
> +  private void _renderJoinIconBlock(
> +      FacesContext     context,
> +      RenderingContext arc,
> +      String           stateStyleClass,
> +      boolean          overflow) throws IOException
> +  {
> +    if(stateStyleClass == _STATE_PARENT)
> +    {
> +      _renderJoinIconBlock(context,
> +                           arc,
> +                           
> SkinSelectors.AF_TRAIN_PARENT_JOIN_STYLE_CLASS,
> +                           null);
> +    }
> +    else if(overflow)
> +    {
> +      _renderJoinIconBlock(context,
> +                           arc,
> +                           
> SkinSelectors.AF_TRAIN_OVERFLOW_JOIN_STYLE_CLASS,
> +                           stateStyleClass);
> +    }
> +    else
>      {
> -      station.isNext = true;
> +      _renderJoinIconBlock(context,
> +                           arc,
> +                           SkinSelectors.AF_TRAIN_JOIN_STYLE_CLASS,
> +                           stateStyleClass);
>      }
>    }
> -
> -  /**
> -   * Returns the MAX_VISITED_ATTR
> -   * @todo =-=jmw Hopefully the controller will tell us this someday.
> -   */
> -  private static Object _getMaxVisited(
> -    RenderingContext arc,
> -    UIComponent component)
> +
> +  private void _renderJoinIconBlock(
> +      FacesContext     context,
> +      RenderingContext arc,
> +      String           joinStyleClass,
> +      String           stateStyleClass) throws IOException
>    {
> -    // return component.getAttributes().get("maxVisited");
> -    return null;
> -  }
> +    ResponseWriter writer = context.getResponseWriter();
>  
> -  /**
> -   * Get the maxVisited attribute from the node and return it.
> -   */
> -  private int _getMaxVisitedIndex(
> -    RenderingContext arc,
> -    UIComponent component)
> +    writer.startElement(XhtmlConstants.TABLE_DATA_ELEMENT, null);
> +    writer.writeAttribute(XhtmlConstants.STYLE_ATTRIBUTE, 
> "width: 50%", null);
> +    renderStyleClasses(context,
> +                       arc,
> +                       new String[]{
> +                         joinStyleClass,
> +                         stateStyleClass});
> +    writer.endElement(XhtmlConstants.TABLE_DATA_ELEMENT);
> +  }
> +
> +  private void _renderParentContent(
> +      FacesContext     context,
> +      RenderingContext arc,
> +      Station          parent) throws IOException
>    {
> -    int maxVisitedIndex = NO_CHILD_INDEX;
> -    Integer maxVisited = (Integer) _getMaxVisited(arc, component);
> -    if (maxVisited != null)
> -    {
> -      maxVisitedIndex = maxVisited.intValue();
> +    ResponseWriter writer = context.getResponseWriter();
> +
> +    String  baseStyleClass = parent.getBaseStyleClass();
> +    writer.startElement(XhtmlConstants.TABLE_DATA_ELEMENT, null);
> +    writer.writeAttribute(XhtmlConstants.COLSPAN_ATTRIBUTE, 
> "3", null);
> +    renderStyleClasses(context,
> +                       arc,
> +                       new String[]{
> +                         baseStyleClass,
> +                         baseStyleClass + _SUFFIX_CONTENT});
> +
> +    /* -= Simon =-
> +     * FIXME HACK for MSIE CSS bug involving composite style classes.
> +     *       Since the bug is most obvious with join 
> background images
> +     *       I hard code background-image to none to fix it.
> +     *       See Jira for issue ADFFACES-206.
> +     */
> +    
> if(arc.getAgent().getAgentName().equalsIgnoreCase(Agent.AGENT_IE))
> +    {
> +      writer.writeAttribute(XhtmlConstants.STYLE_ATTRIBUTE,
> +                            "background-image:none;",
> +                            null);
>      }
> -    return maxVisitedIndex;
> +
> +    writer.endElement(XhtmlConstants.TABLE_DATA_ELEMENT);
>    }
> -
> -  /**
> -   * Return what the starting index into the stations List.
> -   */
> -  private int _getStartIndex(int numPages, int originalSelectedIndex)
> +
> +  private void _renderParentEnd(
> +      FacesContext     context,
> +      RenderingContext arc,
> +      UIXProcess       process,
> +      Train            train,
> +      String           leftState,
> +      String           rightState) throws IOException
> +  {
> +    // Add join
> +    _renderJoin(context, arc, leftState, false);
> +
> +    // Icon cell
> +    _preRenderIconBlock(context, arc);
> +
> +    // Add join
> +    _renderJoinIconBlock(context, arc, leftState, false);
> +
> +    // Add the parent's stop icon
> +    _renderParentEndIconBlock(context, arc, process, train);
> +
> +    // Add join
> +    _renderJoinIconBlock(context, arc, rightState, false);
> +
> +    // End icon cell
> +    _postRenderIconBlock(context);
> +
> +    // Add join
> +    _renderJoin(context, arc, rightState, false);
> +  }
> +
> +  private void _renderParentEndLtr(
> +      FacesContext     context,
> +      RenderingContext arc,
> +      UIXProcess       process,
> +      Train            train) throws IOException
> +  {
> +    _renderParentEnd(context,
> +                     arc,
> +                     process,
> +                     train,
> +                     _STATE_PARENT,
> +                     null);
> +  }
> +
> +  private void _renderParentEndRtl(
> +      FacesContext     context,
> +      RenderingContext arc,
> +      UIXProcess       process,
> +      Train            train) throws IOException
> +  {
> +    _renderParentEnd(context,
> +                     arc,
> +                     process,
> +                     train,
> +                     null,
> +                     _STATE_PARENT);
> +  }
> +
> +  private void _renderParentEndIconBlock(
> +      FacesContext     context,
> +      RenderingContext arc,
> +      UIXProcess       process,
> +      Train            train) throws IOException
> +  {
> +    assert train.getParentTrain().hasParentEnd();
> +
> +    Station parent = train.getParentTrain().getParentEnd();
> +
> +    process.setRowKey(parent.getRowKey());
> +
> +    _renderStationIconBlock(context, arc, process, parent);
> +
> +    // Restore model
> +    process.setRowKey(train.getInitialRowKey());
> +  }
> +
> +  private void _renderParentStartIconBlock(
> +      FacesContext     context,
> +      RenderingContext arc,
> +      UIXProcess       process,
> +      Train            train) throws IOException
> +  {
> +    assert train.getParentTrain().hasParentStart();
> +
> +    Station parent = train.getParentTrain().getParentStart();
> +
> +    process.setRowKey(parent.getRowKey());
> +
> +    _renderStationIconBlock(context, arc, process, parent);
> +
> +    // Restore model
> +    process.setRowKey(train.getInitialRowKey());
> +  }
> +
> +  private void _renderParentStart(
> +      FacesContext     context,
> +      RenderingContext arc,
> +      UIXProcess       process,
> +      Train            train,
> +      String           leftState,
> +      String           rightState) throws IOException
> +  {
> +    // Add join
> +    _renderJoin(context, arc, leftState, false);
> +
> +    // Icon cell
> +    _preRenderIconBlock(context, arc);
> +
> +    // Add join
> +    _renderJoinIconBlock(context, arc, leftState, false);
> +
> +    // Add the parent's stop icon
> +    _renderParentStartIconBlock(context, arc, process, train);
> +
> +    // Add join
> +    _renderJoinIconBlock(context, arc, rightState, false);
> +
> +    _postRenderIconBlock(context);
> +    // End icon cell
> +
> +    // Add join
> +    _renderJoin(context, arc, rightState, false);
> +  }
> +
> +  private void _renderParentStartLtr(
> +      FacesContext     context,
> +      RenderingContext arc,
> +      UIXProcess       process,
> +      Train            train) throws IOException
> +  {
> +    _renderParentStart(context,
> +                       arc,
> +                       process,
> +                       train,
> +                       null,
> +                       _STATE_PARENT);
> +  }
> +
> +  private void _renderParentStartRtl(
> +      FacesContext     context,
> +      RenderingContext arc,
> +      UIXProcess       process,
> +      Train            train) throws IOException
> +  {
> +    _renderParentStart(context,
> +                       arc,
> +                       process,
> +                       train,
> +                       _STATE_PARENT,
> +                       null);
> +  }
> +
> +  private void _renderStationContent(
> +      FacesContext     context,
> +      RenderingContext arc,
> +      UIXProcess       process,
> +      UIComponent      stamp,
> +      Station          station) throws IOException
>    {
> -    int currentMinIndex = 0;
> -
> -    if (numPages <= _MAX_NUM_LINK_INDEX)
> -      return currentMinIndex;
> -
> -    int selectedIndex = originalSelectedIndex;
> -    int currentMaxIndex = _MAX_NUM_LINK_INDEX - 1;
> -
> -    if (selectedIndex < currentMaxIndex)
> +    ResponseWriter writer = context.getResponseWriter();
> +
> +    writer.startElement(XhtmlConstants.TABLE_DATA_ELEMENT, null);
> +
> +    writer.writeAttribute(XhtmlConstants.COLSPAN_ATTRIBUTE, 
> "3", null);
> +
> +    String baseStyleClass = station.getBaseStyleClass();
> +
> +    List<String> stateStyleClasses = station.getStates();
> +    stateStyleClasses.add(baseStyleClass);
> +    stateStyleClasses.add(baseStyleClass + _SUFFIX_CONTENT);
> +
> +    renderStyleClasses(context,
> +                       arc,
> +                       
> stateStyleClasses.toArray(_EMPTY_STRING_ARRAY));
> +
> +    /* -= Simon =-
> +     * FIXME HACK for MSIE CSS bug involving composite style classes.
> +     *       Since the bug is most obvious with join 
> background images
> +     *       I hard code background-image to none to fix it.
> +     *       See Jira for issue ADFFACES-206.
> +     */
> +    
> if(arc.getAgent().getAgentName().equalsIgnoreCase(Agent.AGENT_IE))
> +    {
> +      writer.writeAttribute(XhtmlConstants.STYLE_ATTRIBUTE,
> +                            "background-image:none;",
> +                            null);
> +    }
> +
> +    Map<String, String> originalMap = arc.getSkinResourceKeyMap();
> +
> +    // Init the model
> +    process.setRowIndex(station.getRowIndex());
> +    try
>      {
> -      return currentMinIndex; //0
> +      arc.setSkinResourceKeyMap(_RESOURCE_KEY_MAP);
> +      encodeChild(context, stamp);
>      }
> -
> -    // the algorithm below works, but I thought it was too cryptic
> -    // return (selectedIndex -
> -    //            (((selectedIndex-1)%(_MAX_NUM_LINK_INDEX-2))+1));
> -
> -    // loop until the selectedIndex range is found or
> -    // we have gone past the number of nodes in the train.
> -    // Then we'll know what index to start the visible 
> portion of the train.
> -    while (numPages > currentMaxIndex)
> +    finally
>      {
> -      currentMinIndex = currentMaxIndex - 1;
> -      currentMaxIndex += (_MAX_NUM_LINK_INDEX - 2);
> -      if (selectedIndex > currentMinIndex &&
> -          selectedIndex < currentMaxIndex)
> -        return currentMinIndex;
> +      arc.setSkinResourceKeyMap(originalMap);
>      }
> -
> -    return currentMinIndex;
> +
> +    writer.endElement(XhtmlConstants.TABLE_DATA_ELEMENT);
>    }
> -
> -
> -  /**
> -   * Gather up the train state: selectedIndex, 
> maxVisitedIndex, startIndex,
> -   *  isSubTrain, formName, id,.
> -   *  This way all the parameters we need to pass around to 
> various methods
> -   *  are all in one place, the TrainState
> -   * @param arc RenderingContext
> -   * @param context FacesContext
> -   * @param process the UIXProcess component.
> -   * @return
> -   */
> -  private TrainState _getTrainState(
> -    FacesContext context,
> -    RenderingContext arc,
> -    UIXProcess process)
> -  {
> -    TrainRenderer.TrainState state =
> -      new TrainRenderer.TrainState();
> -
> -    state.selectedIndex = process.getRowIndex();
> -
> -    // get highest node in train visited
> -    state.maxVisitedIndex = _getMaxVisitedIndex(arc, process);
> -
> -    // default to selectedIndex if it wasn't set
> -    // or if it was set to be greater than selectedIndex
> -    if (state.maxVisitedIndex == NO_CHILD_INDEX ||
> -        state.maxVisitedIndex < state.selectedIndex)
> -    {
> -      state.maxVisitedIndex = state.selectedIndex;
> -    }
> -
> -    int totalPages = process.getRowCount();
> -    state.startIndex = _getStartIndex(totalPages, 
> state.selectedIndex);
> -
> -    state.subTrain = _isSubTrain(process);
> -
> -    state.formName = arc.getFormData().getName();
> -
> -    String id = process.getClientId(context);
> -    state.id = (id != null)? id: null;
> -
> -    return state;
> +
> +  private void _renderStationIcon(
> +      FacesContext     context,
> +      RenderingContext arc,
> +      UIXProcess       process,
> +      Station          station,
> +      String           leftJoinState,
> +      String           rightJoinState,
> +      boolean          overflowLeft,
> +      boolean          overflowRight) throws IOException
> +  {
> +    // Add join
> +    _renderJoin(context, arc, leftJoinState, overflowLeft);
> +
> +    // Icon cell
> +    _preRenderIconBlock(context, arc);
> +
> +    // Add join
> +    _renderJoinIconBlock(context, arc, leftJoinState, overflowLeft);
> +
> +    // Add the parent's stop icon
> +    _renderStationIconBlock(context, arc, process, station);
> +
> +    // Add join
> +    _renderJoinIconBlock(context, arc, rightJoinState, 
> overflowRight);
> +
> +    // End icon cell
> +    _postRenderIconBlock(context);
> +
> +    // Add join
> +    _renderJoin(context, arc, rightJoinState, overflowRight);
>    }
> -
> -
> -  /**
> -   * Get the subTrain attribute from the node and return it.
> -   */
> -  private boolean _isSubTrain(UIXProcess component)
> -  {
> -    Object focusRowKey = component.getFocusRowKey();
> -    if (focusRowKey != null && (component.getDepth(focusRowKey) > 0))
> -      return true;
> -
> -    return false;
> +
> +  private void _renderStationIconBlock(
> +      FacesContext     context,
> +      RenderingContext arc,
> +      UIXProcess       process,
> +      Station          station) throws IOException
> +  {
> +    process.setRowIndex(station.getRowIndex());
> +
> +    String baseStyleClass = station.getBaseStyleClass();
> +
> +    _renderIconBlock(context,
> +                     arc,
> +                     station.getIconNames(),
> +                     station.getLabel(),
> +                     baseStyleClass,
> +                     baseStyleClass + _SUFFIX_ICON_CELL,
> +                     station.getStates());
>    }
> -
> -
> -  private void _encodeChildren(
> -    FacesContext context,
> -    RenderingContext arc,
> -    UIXProcess process,
> -    UIComponent stamp,
> -    TrainState train,
> -    int length)
> -    throws IOException
> +
> +  private void _renderStationIconLtr(
> +      FacesContext     context,
> +      RenderingContext arc,
> +      UIXProcess       process,
> +      Station          station) throws IOException
> +  {
> +    _renderStationIcon(context,
> +                       arc,
> +                       process,
> +                       station,
> +                       station.getStartJoinState(),
> +                       station.getEndJoinState(),
> +                       station.hasPrevious() && 
> station.getPrevious().isOverflowStart(),
> +                       station.hasNext()     && 
> station.getNext().isOverflowEnd());
> +  }
> +
> +  private void _renderStationIconRtl(
> +      FacesContext     context,
> +      RenderingContext arc,
> +      UIXProcess       process,
> +      Station          station) throws IOException
> +  {
> +    _renderStationIcon(context,
> +                       arc,
> +                       process,
> +                       station,
> +                       station.getEndJoinState(),
> +                       station.getStartJoinState(),
> +                       station.hasNext()     && 
> station.getNext().isOverflowEnd(),
> +                       station.hasPrevious() && 
> station.getPrevious().isOverflowStart());
> +  }
> +
> +  private void _renderTrain(
> +      FacesContext     context,
> +      RenderingContext arc,
> +      UIXProcess       process,
> +      FacesBean        bean,
> +      UIComponent      stamp,
> +      Train            train) throws IOException
>    {
> -
>      ResponseWriter writer = context.getResponseWriter();
>  
> -    // start FOR SUBTRAIN
> -    // If subTrain, add a row and on the first and last cells, render
> -    // a border which looks like a sub-train
> -    if (train.subTrain)
> -    {
> -      _renderSubTrainRow(context, arc, train, length, writer);
> -
> -      writer.startElement("tr", null);
> -      writer.startElement("td", null);
> -      writer.endElement("td");
> +    // Start of the icon row
> +    writer.startElement(XhtmlConstants.TABLE_ROW_ELEMENT, null);
> +
> +    if(arc.isRightToLeft())
> +    {
> +      _renderIconRowRtl(context, arc, process, stamp, train);
>      }
>      else
>      {
> -      writer.startElement("tr", null);
> +      _renderIconRowLtr(context, arc, process, stamp, train);
>      }
> +
> +    writer.endElement(XhtmlConstants.TABLE_ROW_ELEMENT);
>  
> -    // loop through each rendered station.
> -    int lastTrainIndex = train.startIndex + 
> _getMaxLinks(arc, process);
> -
> -    if (length <= lastTrainIndex)
> +    // Start of the content row
> +    writer.startElement(XhtmlConstants.TABLE_ROW_ELEMENT, null);
> +
> +    if(arc.isRightToLeft())
>      {
> -      lastTrainIndex = length;
> +      _renderContentRowRtl(context, arc, process, stamp, train);
>      }
>      else
>      {
> -      lastTrainIndex++; // length of train is larger than the visible
> -      // number of train stations, so make room for the more
> -      // by adding one to the lastTrainIndex.
> +      _renderContentRowLtr(context, arc, process, stamp, train);
>      }
> -    int currVisChildIndex = Math.max(0, train.startIndex - 1);
> -    boolean isPrevVisChildDisabled = false;
> -    boolean isCurrVisChildDisabled = false;
> -    boolean isNextVisChildDisabled = false;
> -
> -    process.setRowIndex(currVisChildIndex);
> -
> -    isCurrVisChildDisabled =
> -        Boolean.TRUE.equals(stamp.getAttributes().get("disabled"));
> -    // getBooleanAttributeValue(context, stamp, 
> DISABLED_ATTR, false);
> -
> -    for (; currVisChildIndex < lastTrainIndex; currVisChildIndex++)
> +
> +    writer.endElement(XhtmlConstants.TABLE_ROW_ELEMENT);
> +  }
> +
> +  private static class Train
> +  {
> +    public Train(
> +        FacesContext     context,
> +        RenderingContext arc,
> +        UIXProcess       process,
> +        UIComponent      stamp)
> +    {
> +      // Save the model state
> +      int maxVisitedIndex  = _getMaxVisitedIndex(arc, process);
> +      int activeIndex      = _loadStations(process, stamp, 
> maxVisitedIndex);
> +      int visibleStopCount = _getVisibleStopCount(arc);
> +
> +      _formName     = arc.getFormData().getName();
> +      _isSubTrain   = _loadIsSubTrain(process);
> +
> +      if(!_stations.isEmpty())
> +      {
> +        // There's something visible in the train
> +        if(_stations.size() > visibleStopCount)
> +        {
> +          // We have overflow, let resolve it
> +          _resolveOverflow(visibleStopCount, activeIndex);
> +        }
> +        else
> +        {
> +          // No overflow, yay!
> +          _resolveStandard();
> +        }
> +
> +        _initLabels(arc, process, stamp);
> +        _initParentTrain(arc, process, stamp);
> +      }
> +    }
> +
> +    public Object getFocusRowKey()
>      {
> -      //
> -      // get index of the child and
> -      // determine if it is within the range in which it 
> will be rendered.
> -      //
> -      int prevVisChildIndex =
> -        ((currVisChildIndex == 0)? NO_CHILD_INDEX: 
> currVisChildIndex - 1);
> -      int nextVisChildIndex =
> -        ((currVisChildIndex == length - 1)? NO_CHILD_INDEX:
> -         currVisChildIndex + 1);
> -
> -      process.setRowIndex(nextVisChildIndex);
> -
> -      isNextVisChildDisabled =
> -          Boolean.TRUE.equals(stamp.getAttributes().get("disabled"));
> -
> -      process.setRowIndex(currVisChildIndex);
> -
> -      // initialized state of the station
> -      TrainRenderer.StationState station = train.station;
> -      _initializeStationState(context, arc, train, station,
> -                             currVisChildIndex, prevVisChildIndex,
> -                             nextVisChildIndex, 
> isCurrVisChildDisabled,
> -                             isPrevVisChildDisabled,
> -                             isNextVisChildDisabled);
> -
> -      // set up for next pass
> -      isPrevVisChildDisabled = isCurrVisChildDisabled;
> -      isCurrVisChildDisabled = isNextVisChildDisabled;
> -
> -      Object label = stamp.getAttributes().get("text");
> -
> -      String currVisChildText = null;
> -
> -      // Get text from link, or Previous or More text if appropriate
> -      currVisChildText = _getTextForStation(arc, station, label);
> -
> -      String currVisChildID = null;
> -
> -      process.setRowIndex(currVisChildIndex);
> -      _renderLink(context, arc, stamp, writer, train, 
> currVisChildText,
> -                 currVisChildID, station);
> -
> +      return _focusRowKey;
>      }
> -
> -    if (train.subTrain)
> +
> +    public String getFormName()
>      {
> -      writer.startElement("td", null);
> -      writer.endElement("td");
> +      return _formName;
> +    }
> +
> +    public Object getInitialRowKey()
> +    {
> +      return _initialRowKey;
> +    }
> +
> +    public ParentTrain getParentTrain()
> +    {
> +      return _parent;
> +    }
> +
> +    public List<Station> getStations()
> +    {
> +      return _stations;
> +    }
> +
> +    public boolean isSubTrain()
> +    {
> +      return _isSubTrain;
> +    }
> +
> +    private void _createStation(
> +        UIXProcess  process,
> +        UIComponent stamp,
> +        int         index,
> +        boolean     active,
> +        boolean     visited)
> +    {
> +      process.setRowIndex(index);
> +      if(stamp.isRendered())
> +      {
> +        // The station will be visible.
> +        _stations.add(new Station(this,
> +                                  stamp,
> +                                  index,
> +                                  process.getRowKey(),
> +                                  active,
> +                                  visited));
> +      }
>      }
>  
> -    writer.endElement("tr");
> -  }
> -
> -  /**
> -   * Renders the link under the train node
> -   *
> -   */
> -  private void _renderLink(
> -    FacesContext context,
> -    RenderingContext arc,
> -    UIComponent stamp,
> -    ResponseWriter writer,
> -    TrainRenderer.TrainState train,
> -    String currVisChildText,
> -    String currVisChildID,
> -    TrainRenderer.StationState station)
> -    throws IOException
> -  {
> -    //
> -    // Write the link under the train node.
> -    //
> -    writer.startElement("td", null);
> -    writer.writeAttribute("colspan", "2", null);
> -
> -    String styleClass =
> -      (station.isSelected)? 
> SkinSelectors.AF_PROCESS_TRAIN_ACTIVE_STYLE_CLASS:
> -      (station.isDisabled && !station.isMoreLink)?
> -      SkinSelectors.AF_PROCESS_TRAIN_DISABLED_STYLE_CLASS:
> -      (station.isVisited)?
> -      SkinSelectors.AF_PROCESS_TRAIN_VISITED_STYLE_CLASS:
> -      SkinSelectors.AF_PROCESS_TRAIN_UNVISITED_STYLE_CLASS;
> -
> -    renderStyleClass(context, arc, styleClass);
> +    /**
> +     * Get the maxVisited attribute from the node and return it.
> +     */
> +    private int _getMaxVisitedIndex(
> +      RenderingContext arc,
> +      UIComponent component)
> +    {
> +      int maxVisitedIndex = NO_CHILD_INDEX;
> +      Integer maxVisited = (Integer) _getMaxVisited(arc, component);
> +      if (maxVisited != null)
> +      {
> +        maxVisitedIndex = maxVisited.intValue();
> +      }
> +      return maxVisitedIndex;
> +    }
>  
> -    Map<String, String> originalResourceKeyMap = 
> arc.getSkinResourceKeyMap();
> -    try
> +    /**
> +     * Returns the MAX_VISITED_ATTR
> +     * @todo =-=jmw Hopefully the controller will tell us 
> this someday.
> +     */
> +    private static Object _getMaxVisited(
> +      RenderingContext arc,
> +      UIComponent component)
> +    {
> +      // return component.getAttributes().get("maxVisited");
> +      return null;
> +    }
> +
> +    private int _getVisibleStopCount(RenderingContext arc)
> +    {
> +      Object propValue =
> +        
> arc.getSkin().getProperty(SkinProperties.AF_TRAIN_VISIBLE_STOP_COUNT);
> +
> +      if(propValue == null)
> +      {
> +        return DEFAULT_MAX_VISIBLE_STOP_COUNT;
> +      }
> +
> +      try
> +      {
> +        int count = Integer.parseInt(propValue.toString());
> +        if(count <= 0)
> +        {
> +          _LOG.warning("Visible stop count must be > 0, 
> found " + count);
> +          return DEFAULT_MAX_VISIBLE_STOP_COUNT;
> +        }
> +
> +        return count;
> +      }
> +      catch(NumberFormatException e)
> +      {
> +        _LOG.warning("Visible stop count must be an integer, 
> found " + propValue);
> +        return DEFAULT_MAX_VISIBLE_STOP_COUNT;
> +      }
> +    }
> +
> +    private void _initLabels(
> +        RenderingContext arc,
> +        UIXProcess       process,
> +        UIComponent      stamp)
>      {
> -      arc.setSkinResourceKeyMap(_RESOURCE_KEY_MAP);
> -      _renderStamp(context, stamp);
> +      for(Station s : _stations)
> +      {
> +        process.setRowIndex(s.getRowIndex());
> +        s.initLabel(arc, stamp);
> +      }
>      }
> -    finally
> +
> +    private void _initParentTrain(
> +        RenderingContext arc,
> +        UIXProcess       process,
> +        UIComponent      stamp)
>      {
> -      arc.setSkinResourceKeyMap(originalResourceKeyMap);
> +      if(_isSubTrain)
> +      {
> +        if(_shouldRenderParentTrain(arc))
> +        {
> +          _parent = new ParentTrain(arc, process, stamp, this);
> +          if(!_parent.hasParentStart() && !_parent.hasParentEnd())
> +          {
> +            _isSubTrain = false;
> +          }
> +        }
> +        else
> +        {
> +          _isSubTrain = false;
> +        }
> +      }
>      }
> -    writer.endElement("td");
> -  }
> -
> -  /**
> -   * Called to render a child.  This method does not update the
> -   * rendering context (by calling pushChild() and popChild()
> -   * as needed);  subclasses need to use renderIndexedChild() or
> -   * renderNamedChild() for that purpose.
> -   * <p>
> -   * @param context the faces context
> -   * @param child the child under consideration
> -   */
> -  private void _renderStamp(FacesContext context, UIComponent child)
> -    throws IOException
> -  {
> -    if (child != null)
> +
> +    /**
> +     * Determine if this train is a sub-train.
> +     */
> +    private boolean _loadIsSubTrain(UIXProcess process)
>      {
> -      encodeChild(context, child);
> -      // child.render(context);
> +      Object focusRowKey = process.getFocusRowKey();
> +      if (focusRowKey != null && (process.getDepth(focusRowKey) > 0))
> +      {
> +        return true;
> +      }
> +
> +      return false;
>      }
> -  }
> -
> -  /**
> -  * return the string to use for the text of the station
> -  * it is the text of the link or "Previous" or "More"
> -  */
> -  private String _getTextForStation(
> -    RenderingContext arc,
> -    TrainRenderer.StationState station,
> -    Object textObj)
> -  {
> -    String textValue = (textObj == null)? null: textObj.toString();
> -    final String currText;
> +
> +    private int _loadStations(
> +        UIXProcess  process,
> +        UIComponent stamp,
> +        int         maxVisitedIndex)
> +    {
> +      _initialRowKey = process.getRowKey();
> +      try
> +      {
> +        // Set the model on the focus item
> +        _focusRowKey = process.getFocusRowKey();
> +        process.setRowKey(_focusRowKey);
> +
> +        int count       = process.getRowCount();
> +        int activeIndex = process.getRowIndex();
> +        int index       = 0;
> +
> +        assert activeIndex < count;
> +
> +        _stations = new ArrayList<Station>(count);
> +
> +        // Process visited stations
> +        for(; index < activeIndex; index++)
> +        {
> +          _createStation(process, stamp, index, false, true);
> +        }
> +
> +        assert index == activeIndex;
> +
> +        _createStation(process, stamp, index, true, true);
> +        index++;
> +        // Might have an invisible active station. Thsi is 
> weird, but still.
> +        // You never know what users want to do, but let support
> +        // it nevertheless for now.
> +        // selectedIndex is either the active station index 
> or the index
> +        // of the station just before the selected one if 
> active is not visible.
> +        activeIndex = _stations.size() - 1;
> +
> +        if(maxVisitedIndex != NO_CHILD_INDEX)
> +        {
> +          for(; index < maxVisitedIndex; index++)
> +          {
> +            _createStation(process, stamp, index, false, true);
> +          }
> +        }
> +
> +        for(; index < count; index++)
> +        {
> +          _createStation(process, stamp, index, false, false);
> +        }
> +
> +        return activeIndex;
> +      }
> +      finally
> +      {
> +        // Restore the model's state
> +        process.setRowKey(_initialRowKey);
> +      }
> +    }
> +
> +    private void _resolveOverflow(
> +        int visibleStopCount,
> +        int activeIndex)
> +    {
> +      assert _stations != null;
> +      assert activeIndex >= -1;
> +      assert activeIndex < _stations.size();
> +
> +      // First, resolve chaining
> +      _resolveStandard();
> +
> +      // We have more stations than the max available, so we 
> have an overflow
> +      // for sure.
> +      if(activeIndex <= 0)
> +      {
> +        // Overflow to the following group only
> +        _resolveOverflowEnd(visibleStopCount);
> +        _stations = _stations.subList(0, visibleStopCount + 1);
> +      }
> +      else
> +      {
> +        // Get the visible group index
> +        int groupIndex = activeIndex / visibleStopCount;
> +        int startIndex = 0;
> +        int endIndex   = _stations.size();
> +        if(groupIndex > 0)
> +        {
> +          // We have a previous overflow
> +          startIndex = groupIndex * visibleStopCount - 1;
> +          _resolveOverflowStart(startIndex);
> +        }
> +
> +        int maxGroupIndex = (_stations.size() - 1) / 
> visibleStopCount;
> +
> +        if(groupIndex < maxGroupIndex)
> +        {
> +          // We have a next overflow
> +          int overflowIndex = (groupIndex + 1) * visibleStopCount;
> +
> +          // endIndex is exclusive
> +          endIndex = overflowIndex + 1;
> +
> +          _resolveOverflowEnd(overflowIndex);
> +        }
>  
> -    if (textValue != null && !station.isPreviousLink &&
> -        !station.isMoreLink)
> +        _stations = _stations.subList(startIndex, endIndex);
> +      }
> +    }
> +
> +    private void _resolveOverflowEnd(int index)
> +    {
> +      assert _stations != null;
> +      assert index >= 0;
> +      assert index < _stations.size();
> +
> +      Station station = _stations.get(index);
> +      station.setOverflowEnd(true);
> +      if(station.hasPrevious() && station.getPrevious().isDisabled())
> +      {
> +        // If previous stop is disabled, so is the overflow
> +        station.setDisabled(true);
> +      }
> +
> +      station.setNext(null);
> +    }
> +
> +    private void _resolveOverflowStart(int index)
> +    {
> +      assert _stations != null;
> +      assert index >= 0;
> +      assert index < _stations.size();
> +
> +      Station station = _stations.get(index);
> +      station.setOverflowStart(true);
> +      if(station.hasNext() && station.getNext().isDisabled())
> +      {
> +        // If next stop is disabled, so is the overflow
> +        station.setDisabled(true);
> +      }
> +
> +      station.setPrevious(null);
> +    }
> +
> +    private void _resolveStandard()
> +    {
> +      if(_stations.size() > 1)
> +      {
> +        Iterator<Station> iterator = _stations.iterator();
> +
> +        Station previous = null;
> +        Station current  = iterator.next();
> +        Station next     = iterator.next();
> +
> +        _updateStation(current, previous, next);
> +
> +        while(iterator.hasNext())
> +        {
> +          previous = current;
> +          current  = next;
> +          next     = iterator.next();
> +          _updateStation(current, previous, next);
> +        }
> +
> +        next.setPrevious(current);
> +      }
> +    }
> +
> +    private boolean _shouldRenderParentTrain(RenderingContext arc)
> +    {
> +      Object propValue =
> +        
> arc.getSkin().getProperty(SkinProperties.AF_TRAIN_RENDER_PAREN
> T_TRAIN);
> +
> +      if(propValue == null)
> +      {
> +        return DEFAULT_RENDER_PARENT_TRAIN;
> +      }
> +
> +      return Boolean.TRUE.equals(propValue);
> +    }
> +
> +    private void _updateStation(
> +        Station current,
> +        Station previous,
> +        Station next)
> +    {
> +      current.setPrevious(previous);
> +      current.setNext(next);
> +    }
> +
> +    private Object        _focusRowKey;
> +    private String        _formName;
> +    private Object        _initialRowKey;
> +    private boolean       _isSubTrain;
> +    private ParentTrain   _parent;
> +    private List<Station> _stations;
> +  }
> +
> +  private static class Station
> +  {
> +    public Station(
> +        Train  train,
> +        int    index,
> +        Object rowKey)
> +    {
> +      _rowIndex    = index;
> +      _rowKey      = rowKey;
> +      _active      = false;
> +      _visited     = false;
> +      _disabled    = false;
> +      _readOnly    = false;
> +      _parentEnd   = false;
> +      _parentStart = false;
> +      _train       = train;
> +    }
> +
> +    @SuppressWarnings("unchecked")
> +    public Station(
> +        Train       train,
> +        UIComponent stamp,
> +        int         index,
> +        Object      rowKey,
> +        boolean     active,
> +        boolean     visited)
> +    {
> +      Map<String, Object> attributes = stamp.getAttributes();
> +
> +      _rowIndex    = index;
> +      _rowKey      = rowKey;
> +      _active      = active;
> +      _visited     = visited;
> +      _disabled    = _getBooleanAttribute(attributes, 
> "disabled", false);
> +      _readOnly    = _getBooleanAttribute(attributes, 
> "readOnly", false);
> +      _parentEnd   = false;
> +      _parentStart = false;
> +      _train       = train;
> +    }
> +
> +    public String getBaseStyleClass()
>      {
> -      // if we are in screen reader mode, then we must 
> render more descriptive
> -      // text.
> -      // see bug 1801348 REMOVE ONE SET OF TRAIN TEXT IN 
> ACCESSIBLE MODE
> -      if (isScreenReaderMode(arc))
> +      if(isOverflowEnd())
> +      {
> +        return SkinSelectors.AF_TRAIN_OVERFLOW_END_STYLE_CLASS;
> +      }
> +      else if(isOverflowStart())
> +      {
> +        return SkinSelectors.AF_TRAIN_OVERFLOW_START_STYLE_CLASS;
> +      }
> +      else if(isParentStart())
> +      {
> +        return SkinSelectors.AF_TRAIN_PARENT_START_STYLE_CLASS;
> +      }
> +      else if(isParentEnd())
>        {
> -        currText = _getDisabledUserText(arc, station, textValue);
> +        return SkinSelectors.AF_TRAIN_PARENT_END_STYLE_CLASS;
>        }
>        else
>        {
> -        currText = textValue;
> +        return SkinSelectors.AF_TRAIN_STOP_STYLE_CLASS;
>        }
>      }
> -    else if (station.isPreviousLink)
> +
> +    public String getEndJoinState()
>      {
> -      currText = arc.getTranslatedString(_PREVIOUS_KEY);
> +      if(isOverflowEnd())
> +      {
> +        return null;
> +      }
> +      else if(!hasNext())
> +      {
> +        ParentTrain parent = _train.getParentTrain();
> +        if(parent != null && parent.hasParentEnd())
> +        {
> +          return _STATE_PARENT;
> +        }
> +        else
> +        {
> +          return null;
> +        }
> +      }
> +      else if(isDisabled() || getNext().isDisabled())
> +      {
> +        return _STATE_DISABLED;
> +      }
> +      else if(getNext().isVisited())
> +      {
> +        return _STATE_VISITED;
> +      }
> +      else
> +      {
> +        return _STATE_UNVISITED;
> +      }
>      }
> -    else if (station.isMoreLink)
> +
> +    public List<String> getIconNames()
>      {
> -      currText = arc.getTranslatedString(_MORE_KEY);
> +      if(isOverflowEnd())
> +      {
> +        return _getOverflowEndIconNames();
> +      }
> +      else if(isOverflowStart())
> +      {
> +        return _getOverflowStartIconNames();
> +      }
> +      else if(isParentStart())
> +      {
> +        return 
> Collections.singletonList(SkinSelectors.AF_TRAIN_PARENT_START_
> ICON_NAME);
> +      }
> +      else if(isParentEnd())
> +      {
> +        return 
> Collections.singletonList(SkinSelectors.AF_TRAIN_PARENT_END_IC
> ON_NAME);
> +      }
> +      else
> +      {
> +        return _getStopIconNames();
> +      }
>      }
> -    else
> -      currText = null;
> -
> -    return currText;
> -  }
> -
> -  private String _getDisabledUserText(
> -    RenderingContext arc,
> -    TrainRenderer.StationState station,
> -    String textString)
> -  {
> -    String altTextKey =
> -      station.isSelected? _ACTIVE_KEY: station.isVisited? 
> _VISITED_KEY:
> -                                       _NEXT_KEY;
> -
> -    String[] parameters = new String[]
> -      { textString };
> -
> -    String altText =
> -      
> XhtmlUtils.getFormattedString(arc.getTranslatedString(altTextKey),
> -                                    parameters);
> -    return altText;
> -  }
> -
> -  /**
> -   * Returns the max number of links to show
> -   */
> -  private int _getMaxLinks(
> -    RenderingContext arc,
> -    UIComponent component)
> -  {
> -    return _MAX_NUM_LINK_INDEX;
> -  }
> -
> -  private void _renderSubTrainRow(
> -    FacesContext context,
> -    RenderingContext arc,
> -    TrainRenderer.TrainState train,
> -    int length,
> -    ResponseWriter writer)
> -    throws IOException
> -  {
> -    boolean isRTL = arc.getLocaleContext().isRightToLeft();
> -
> -    writer.startElement("tr", null);
> -
> -    if (isRTL)
> -      _renderSubTrainCell(context, arc,
> -                          SkinSelectors.TRAIN_SUB_RIGHT_STYLE_CLASS,
> -                          writer);
> -    else
> -      _renderSubTrainCell(context, arc,
> -                          
> SkinSelectors.AF_PROCESS_TRAIN_SUB_START_STYLE_CLASS,
> -                          writer);
> -
> -    _renderSubTrainBlankCells(train, length, writer);
> -
> -    if (isRTL)
> -      _renderSubTrainCell(context, arc,
> -                          
> SkinSelectors.AF_PROCESS_TRAIN_SUB_START_STYLE_CLASS,
> -                          writer);
> -    else
> -      _renderSubTrainCell(context, arc,
> -                          SkinSelectors.TRAIN_SUB_RIGHT_STYLE_CLASS,
> -                          writer);
> -
> -    writer.endElement("tr");
> -  }
> -
> -  private void _renderSubTrainCell(
> -    FacesContext context,
> -    RenderingContext arc,
> -    String style,
> -    ResponseWriter writer)
> -    throws IOException
> -  {
> -    writer.startElement("td", null);
> -    renderStyleClass(context, arc, style);
> -    renderSpacer(context, arc, "14", "2");
> -    writer.endElement("td");
> -  }
> -
> -  /**
> -   * renders a td with colSpan equal to the number of 
> visible stations
> -   * including the Previous and More if they are there.
> -   * @param train
> -   * @param length
> -   * @param writer
> -   * @throws IOException
> -   */
> -  private void 
> _renderSubTrainBlankCells(TrainRenderer.TrainState train,
> -                                         int length, 
> ResponseWriter writer)
> -    throws IOException
> -  {
> -    writer.startElement("td", null);
> -
> -    // figure out the number of stations
> -    int startIndex = Math.max(0, train.startIndex - 1);
> -    int lastTrainIndex = train.startIndex + _MAX_NUM_LINK_INDEX;
> -    if (length <= lastTrainIndex)
> -      lastTrainIndex = length;
> -    else
> +
> +    public String getLabel()
>      {
> -      // when the length of train is larger than the visible
> -      // number of train stations, we render a More link.
> -      // so make room for the more
> -      // by adding one to the lastTrainIndex.
> -      lastTrainIndex++;
> -    }
> -    String numberOfStations =
> -      Integer.toString((lastTrainIndex - startIndex) * 2);
> -    writer.writeAttribute("colspan", numberOfStations, null);
> -    writer.endElement("td");
> -  }
> +      return _label;
> +    }
> +
> +    public Station getNext()
> +    {
> +      return _next;
> +    }
> +
> +    public Station getPrevious()
> +    {
> +      return _previous;
> +    }
> +
> +    public int getRowIndex()
> +    {
> +      return _rowIndex;
> +    }
> +
> +    public Object getRowKey()
> +    {
> +      return _rowKey;
> +    }
> +
> +    public String getStartJoinState()
> +    {
> +      if(isOverflowStart())
> +      {
> +        return null;
> +      }
> +      else if(!hasPrevious())
> +      {
> +        ParentTrain parent = _train.getParentTrain();
> +        if(parent != null && parent.hasParentStart())
> +        {
> +          return _STATE_PARENT;
> +        }
> +        else
> +        {
> +          return null;
> +        }
> +      }
> +      else if(isDisabled() || getPrevious().isDisabled())
> +      {
> +        return _STATE_DISABLED;
> +      }
> +      else if(isVisited())
> +      {
> +        return _STATE_VISITED;
> +      }
> +      else
> +      {
> +        return _STATE_UNVISITED;
> +      }
> +    }
> +
> +    public List<String> getStates()
> +    {
> +      List<String> states = new ArrayList<String>(5);
> +      if(isParentStart() || isParentEnd())
> +      {
> +        return states;
> +      }
> +
> +      if(isDisabled())
> +      {
> +        states.add(_STATE_DISABLED);
> +        return states;
> +      }
> +
> +      if(isActive())
> +      {
> +        states.add(_STATE_ACTIVE);
> +      }
> +      else if(isVisited())
> +      {
> +        states.add(_STATE_VISITED);
> +      }
> +      else
> +      {
> +        states.add(_STATE_UNVISITED);
> +      }
> +
> +      if(isReadOnly())
> +      {
> +        states.add(_STATE_READ_ONLY);
> +      }
> +
> +      return states;
> +    }
> +
> +    public boolean hasNext()
> +    {
> +      return _next != null;
> +    }
> +
> +    public boolean hasPrevious()
> +    {
> +      return _previous != null;
> +    }
>  
>  
> -  private void _renderHiddenFields(
> -    FacesContext context,
> -    RenderingContext arc,
> -    TrainState train)
> -    throws IOException
> -  {
> -    if ((train.formName != null) && supportsScripting(arc))
> +    /**
> +     * return the string to use for the text of the station
> +     * it is the text of the link or "Previous" or "More"
> +     */
> +    public void initLabel(
> +      RenderingContext arc,
> +      UIComponent      stamp)
>      {
> -      // render hidden fields to hold the form data
> -      FormData fData = arc.getFormData();
> -      if (fData != null)
> +      if(isOverflowStart())
>        {
> -        fData.addNeededValue(XhtmlConstants.EVENT_PARAM);
> -        fData.addNeededValue(XhtmlConstants.SOURCE_PARAM);
> -        fData.addNeededValue(XhtmlConstants.VALUE_PARAM);
> -        fData.addNeededValue(XhtmlConstants.SIZE_PARAM);
> +        _label = arc.getTranslatedString(_PREVIOUS_KEY);
> +      }
> +      else if(isOverflowEnd())
> +      {
> +        _label = arc.getTranslatedString(_MORE_KEY);
> +      }
> +      else
> +      {
> +        Object text = stamp.getAttributes().get("text");
> +        if(text != null)
> +        {
> +          _label = text.toString();
> +          if (isScreenReaderMode(arc))
> +          {
> +            _label = _getDisabledUserText(arc, _label);
> +          }
> +        }
> +        else
> +        {
> +          _label = null;
> +        }
>        }
> -
> -      // Render script submission code.
> -      ProcessUtils.renderNavSubmitScript(context, arc);
>      }
> -  }
> +
> +    public boolean isActive()
> +    {
> +      return _active;
> +    }
> +
> +    public boolean isDisabled()
> +    {
> +      return _disabled;
> +    }
> +
> +    public boolean isNextDisabled()
> +    {
> +      return hasNext() && _next.isDisabled();
> +    }
> +
> +    public boolean isOverflowEnd()
> +    {
> +      return _overflowEnd;
> +    }
> +
> +    public boolean isOverflowStart()
> +    {
> +      return _overflowStart;
> +    }
> +
> +    public boolean isParentEnd()
> +    {
> +      return _parentEnd;
> +    }
> +
> +    public boolean isParentStart()
> +    {
> +      return _parentStart;
> +    }
> +
> +    public boolean isPreviousDisabled()
> +    {
> +      return hasPrevious() && _previous.isDisabled();
> +    }
> +
> +    public boolean isReadOnly()
> +    {
> +      return _readOnly;
> +    }
> +
> +    public boolean isVisited()
> +    {
> +      return _visited;
> +    }
> +
> +    public void setDisabled(boolean disabled)
> +    {
> +      _disabled = disabled;
> +    }
> +
> +    public void setNext(Station next)
> +    {
> +      _next = next;
> +    }
> +
> +    public void setOverflowEnd(boolean overflowEnd)
> +    {
> +      _overflowEnd = overflowEnd;
> +    }
> +
> +    public void setOverflowStart(boolean overflowStart)
> +    {
> +      _overflowStart = overflowStart;
> +      _visited       = true;
> +    }
> +
> +    public void setParentEnd(boolean parentEnd)
> +    {
> +      _parentEnd = parentEnd;
> +    }
> +
> +    public void setParentStart(boolean parentStart)
> +    {
> +      _parentStart = parentStart;
> +    }
> +
> +    public void setPrevious(Station previous)
> +    {
> +      _previous = previous;
> +    }
> +
> +    public void setReadOnly(boolean readOnly)
> +    {
> +      _readOnly = readOnly;
> +    }
> +
> +    private boolean _getBooleanAttribute(
> +        Map<String, Object> attributes,
> +        String              attributeName,
> +        boolean             defaultValue)
> +    {
> +      Object value = attributes.get(attributeName);
> +      if(value == null)
> +      {
> +        return defaultValue;
> +      }
> +
> +      return Boolean.TRUE.equals(value);
> +    }
>  
> +    private String _getDisabledUserText(
> +      RenderingContext arc,
> +      String           text)
> +    {
> +      String altTextKey;
> +      if(isActive())
> +      {
> +        altTextKey = _ACTIVE_KEY;
> +      }
> +      else if(isVisited())
> +      {
> +        altTextKey = _VISITED_KEY;
> +      }
> +      else
> +      {
> +        altTextKey = _NEXT_KEY;
> +      }
>  
> -  private boolean _setNewPath(UIXProcess component)
> -  {
> -    Object focusPath = component.getFocusRowKey();
> -    component.setRowKey(focusPath);
> -    return true;
> +      String altText =
> +        
> XhtmlUtils.getFormattedString(arc.getTranslatedString(altTextKey),
> +                                      new String[]{text});
> +
> +      return altText;
> +    }
> +
> +    private List<String> _getIconNames(String baseSelector)
> +    {
> +      LinkedList<String> names = new LinkedList<String>();
> +
> +      StringBuilder builder = new StringBuilder(64);
> +      builder.append(baseSelector);
> +
> +      int suffixLength = SkinSelectors.ICON_SUFFIX.length();
> +      int baseIndex    = builder.length();
> +
> +      builder.append(SkinSelectors.ICON_SUFFIX);
> +      names.addFirst(builder.toString());
> +      builder.delete(baseIndex, baseIndex + suffixLength);
> +
> +      if(isDisabled())
> +      {
> +        builder.append(_SUFFIX_DISABLED);
> +        builder.append(SkinSelectors.ICON_SUFFIX);
> +        names.addFirst(builder.toString());
> +      }
> +      else
> +      {
> +        if(isActive())
> +        {
> +          builder.append(_SUFFIX_ACTIVE);
> +        }
> +        else if(isVisited())
> +        {
> +          builder.append(_SUFFIX_VISITED);
> +        }
> +        else
> +        {
> +          builder.append(_SUFFIX_UNVISITED);
> +        }
> +
> +        baseIndex = builder.length();
> +
> +        builder.append(SkinSelectors.ICON_SUFFIX);
> +        names.addFirst(builder.toString());
> +        builder.delete(baseIndex, baseIndex + suffixLength);
> +
> +        if(isReadOnly())
> +        {
> +          builder.append(_SUFFIX_READ_ONLY);
> +          builder.append(SkinSelectors.ICON_SUFFIX);
> +          names.addFirst(builder.toString());
> +        }
> +      }
> +
> +      return names;
> +    }
> +
> +    private List<String> _getOverflowEndIconNames()
> +    {
> +      return 
> _getIconNames(SkinSelectors.AF_TRAIN_OVERFLOW_END_STYLE_CLASS);
> +    }
> +
> +    private List<String> _getOverflowStartIconNames()
> +    {
> +      return 
> _getIconNames(SkinSelectors.AF_TRAIN_OVERFLOW_START_STYLE_CLASS);
> +    }
> +
> +    private List<String> _getStopIconNames()
> +    {
> +      return _getIconNames(SkinSelectors.AF_TRAIN_STOP_STYLE_CLASS);
> +    }
> +
> +    private boolean _active;       // Is this station the active one?
> +    private boolean _disabled;     // Disabled attribute
> +    private boolean _overflowEnd; // Is this station the 
> next step set link?
> +    private boolean _overflowStart; // Is this station the 
> prev step set link?
> +    private boolean _parentEnd;    // Is this station a parent end?
> +    private boolean _parentStart;  // Is this station a parent start?
> +    private boolean _readOnly;     // Read only attribute
> +    private boolean _visited;      // Is this station visited?
> +
> +    private int _rowIndex; // Row index
> +
> +    private Object _rowKey; // Row key
> +
> +    private String _label; // This station's label
> +
> +    private Station _next;
> +    private Station _previous;
> +
> +    private Train _train;
>    }
> -
> -  protected static class TrainState
> +
> +  private static class ParentTrain
>    {
> -    public TrainState()
> +    public ParentTrain(
> +        RenderingContext arc,
> +        UIXProcess       process,
> +        UIComponent      stamp,
> +        Train            train)
> +    {
> +      List<Station> stations     = train.getStations();
> +      int           stationCount = stations.size();
> +
> +      boolean hasParentStart = !stations.get(0).isOverflowStart();
> +      boolean hasParentEnd   = !stations.get(stationCount - 
> 1).isOverflowEnd();
> +
> +      if(hasParentStart || hasParentEnd)
> +      {
> +        Object parentStartRowKey = process.getContainerRowKey();
> +        process.setRowKey(parentStartRowKey);
> +        int rowIndex = process.getRowIndex();
> +        if(hasParentStart)
> +        {
> +          _parentStart = new Station(train, rowIndex, 
> parentStartRowKey);
> +          _parentStart.setParentStart(true);
> +          _parentStart.initLabel(arc, stamp);
> +        }
> +
> +        rowIndex = rowIndex + 1;
> +
> +        // Check if the parent has more steps, render it 
> only if it does
> +        hasParentEnd = rowIndex < process.getRowCount();
> +        if(hasParentEnd)
> +        {
> +          process.setRowIndex(rowIndex);
> +          _parentEnd = new Station(train, rowIndex, 
> process.getRowKey());
> +          _parentEnd.setParentEnd(true);
> +          _parentEnd.initLabel(arc, stamp);
> +        }
> +
> +        // Restore the model
> +        process.setRowKey(train.getInitialRowKey());
> +      }
> +    }
> +
> +    public Station getParentEnd()
>      {
> -      station = new TrainRenderer.StationState();
> +      return _parentEnd;
>      }
> -    public int startIndex;
> -    public int maxVisitedIndex;
> -    public int selectedIndex;
> -    public boolean subTrain;
> -    public String formName;
> -    public String id;
> -    public TrainRenderer.StationState station;
> -  }
> -
> -  protected static class StationState
> -  {
> -
> -    public boolean isSelected;
> -    // is this the station that is right AFTER the selected station.
> -    public boolean isNext;
> -    public boolean isVisited; // has this station been 
> visited already?
> -    public boolean isPreviousLink; // is this the Previous link?
> -    public boolean isMoreLink; // is this the More link?
> -    public boolean isDisabled; // is this station disabled?
> -    public boolean isNextDisabled; // is the next station disabled?
> -    public boolean isPrevDisabled; // is the previous 
> station disabled?
> -    public boolean isNextVisited; // is the next station visited?
> -    public int index; // the index of this node
> -  } //end StationState
> +
> +    public Station getParentStart()
> +    {
> +      return _parentStart;
> +    }
> +
> +    public boolean hasParentEnd()
> +    {
> +      return _parentEnd != null;
> +    }
> +
> +    public boolean hasParentStart()
> +    {
> +      return _parentStart != null;
> +    }
> +
> +    private Station _parentEnd;
> +    private Station _parentStart;
> +  }
>  
> -  private static final int  _MAX_NUM_LINK_INDEX =
> -    6; //number of visible links
> +  /**
> +   * Gives the amount of visible stops that get rendered by 
> default if no
> +   * amount is specified by the -ora-visible-stop-count skin 
> property.
> +   */
> +  public static final int DEFAULT_MAX_VISIBLE_STOP_COUNT  = 6;
> +
> +  /**
> +   * Determines if the parent train of sub-trains should be 
> rendered by
> +   * default if not specified by the 
> -ora-render-parent-train skin property.
> +   */
> +  public static final boolean DEFAULT_RENDER_PARENT_TRAIN = false;
> +
> +  private static final String _STATE_ACTIVE    = 
> SkinSelectors.STATE_PREFIX + "Selected";
> +  private static final String _STATE_DISABLED  = 
> SkinSelectors.STATE_PREFIX + "Disabled";
> +  private static final String _STATE_PARENT    = 
> SkinSelectors.STATE_PREFIX + "Parent";
> +  private static final String _STATE_READ_ONLY = 
> SkinSelectors.STATE_PREFIX + "ReadOnly";
> +  private static final String _STATE_UNVISITED = 
> SkinSelectors.STATE_PREFIX + "Unvisited";
> +  private static final String _STATE_VISITED   = 
> SkinSelectors.STATE_PREFIX + "Visited";
> +
> +  private static final String _SUFFIX_CONTENT    = "-content";
> +  private static final String _SUFFIX_ICON_CELL  = "-icon-cell";
> +
> +  private static final String _SUFFIX_ACTIVE     = ":selected";
> +  private static final String _SUFFIX_DISABLED   = ":disabled";
> +  private static final String _SUFFIX_READ_ONLY  = ":read-only";
> +  private static final String _SUFFIX_UNVISITED  = ":unvisited";
> +  private static final String _SUFFIX_VISITED    = ":visited";
>  
>    /**
> - * The following keys are used to get at the corresponding translated
> - * strings.
> - */
> +   * The following keys are used to get at the corresponding 
> translated
> +   * strings.
> +   */
>    private static final String _VISITED_KEY = "af_train.VISITED_TIP";
>    private static final String _ACTIVE_KEY = "af_train.ACTIVE_TIP";
>    private static final String _NEXT_KEY = "af_train.NEXT_TIP";
> @@ -800,23 +1866,22 @@
>  
>    private static final TrinidadLogger _LOG =
>      TrinidadLogger.createTrinidadLogger(TrainRenderer.class);
> -
> -  // for now keep the OraLink/OraDisabledLink styles on the 'a', and
> -  // append train link style class.
> -  private static final Map<String, String> _RESOURCE_KEY_MAP =
> -    new HashMap<String, String>();
> -  private static final String _TRAIN_DISABLED_LINK =
> -    SkinSelectors.LINK_DISABLED_STYLE_CLASS + " " +
> -    SkinSelectors.AF_PROCESS_TRAIN_LINK_STYLE_CLASS;
> -  private static final String _TRAIN_ENABLED_LINK =
> -    SkinSelectors.LINK_STYLE_CLASS + " " +
> -    SkinSelectors.AF_PROCESS_TRAIN_LINK_STYLE_CLASS;
> -
> -  static {
> -    _RESOURCE_KEY_MAP.put(SkinSelectors.LINK_DISABLED_STYLE_CLASS,
> -                          _TRAIN_DISABLED_LINK);
> -    _RESOURCE_KEY_MAP.put(SkinSelectors.LINK_STYLE_CLASS,
> -                          _TRAIN_ENABLED_LINK);
> +
> +  private static final String[] _EMPTY_STRING_ARRAY;
> +
> +  private static final Map<String, String> _RESOURCE_KEY_MAP;
> +
> +  static
> +  {
> +    _EMPTY_STRING_ARRAY = new String[0];
> +
> +    // Not adding the base link classes as before, those are 
> a nuisance
> +    // while defining the skin since oyu cannot inhibit them 
> as they're
> +    // on the same level as the train selectors.
> +    _RESOURCE_KEY_MAP = new TreeMap<String, String>();
> +    _RESOURCE_KEY_MAP.put(SkinSelectors.LINK_STYLE_CLASS,
> +                          SkinSelectors.AF_TRAIN_LINK_STYLE_CLASS);
> +    _RESOURCE_KEY_MAP.put(SkinSelectors.LINK_DISABLED_STYLE_CLASS,
> +                          SkinSelectors.AF_TRAIN_LINK_STYLE_CLASS);
>    }
> -
>  }
> 
> Modified: 
> incubator/adffaces/trunk/trinidad/trinidad-impl/src/main/java/
org/apache/myfaces/trinidadinternal/renderkit/core/xhtml/SkinProperties.j> ava
> URL: 
> http://svn.apache.org/viewvc/incubator/adffaces/trunk/trinidad
> /trinidad-impl/src/main/java/org/apache/myfaces/trinidadintern
al/renderkit/core/xhtml/SkinProperties.java?view=diff&rev=451772&r1=> 451771&r2=451772
> ==============================================================
> ================
> --- 
> incubator/adffaces/trunk/trinidad/trinidad-impl/src/main/java/
org/apache/myfaces/trinidadinternal/renderkit/core/xhtml/SkinProperties.j> ava (original)
> +++ 
> incubator/adffaces/trunk/trinidad/trinidad-impl/src/main/java/
org/apache/myfaces/trinidadinternal/renderkit/core/xhtml/SkinProperties.j> ava Sun Oct  1 10:26:55 2006
> @@ -39,14 +39,18 @@
>    // FIXME: Name inconsistency, should be AF_PANEL_HEADER
>    public static final String AF_PANELHEADER_INDENT_CONTENT =
>      "af|panelHeader-ora-indent-content";
> +  public static final String AF_PANEL_BORDER_LAYOUT_SPACER_WIDTH =
> +    "af|panelBorderLayout-ora-spacer-width";
>    public static final String AF_PANEL_LIST_DEFAULT_COLUMNS =
>      "af|panelList-ora-default-columns";
>    public static final String AF_TABLE_REPEAT_CONTROL_BAR =
>      "af|table-ora-repeat-control-bar";
>    public static final String AF_TABLE_SELECTION_BAR_IN_TABLE =
>      "af|table-ora-selection-bar-in-table";
> +  public static final String AF_TRAIN_RENDER_PARENT_TRAIN =
> +    "af|train-ora-render-parent-train";
> +  public static final String AF_TRAIN_VISIBLE_STOP_COUNT =
> +    "af|train-ora-visible-stop-count";
>    public static final String AF_TREE_TABLE_SPACER_WIDTH =
>      "af|treeTable-ora-spacer-width";
> -  public static final String AF_PANEL_BORDER_LAYOUT_SPACER_WIDTH =
> -    "af|panelBorderLayout-ora-spacer-width";
>  }
> 
> 
> 
> 


Mime
View raw message