Coverage Report - org.apache.myfaces.shared.renderkit.html.HtmlTableRendererBase
 
Classes in this File Line Coverage Branch Coverage Complexity
HtmlTableRendererBase
0%
0/394
0%
0/228
3.241
HtmlTableRendererBase$Styles
0%
0/14
0%
0/14
3.241
 
 1  
 /*
 2  
  * Licensed to the Apache Software Foundation (ASF) under one
 3  
  * or more contributor license agreements.  See the NOTICE file
 4  
  * distributed with this work for additional information
 5  
  * regarding copyright ownership.  The ASF licenses this file
 6  
  * to you under the Apache License, Version 2.0 (the
 7  
  * "License"); you may not use this file except in compliance
 8  
  * with the License.  You may obtain a copy of the License at
 9  
  *
 10  
  *   http://www.apache.org/licenses/LICENSE-2.0
 11  
  *
 12  
  * Unless required by applicable law or agreed to in writing,
 13  
  * software distributed under the License is distributed on an
 14  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 15  
  * KIND, either express or implied.  See the License for the
 16  
  * specific language governing permissions and limitations
 17  
  * under the License.
 18  
  */
 19  
 package org.apache.myfaces.shared.renderkit.html;
 20  
 
 21  
 import java.io.IOException;
 22  
 import java.util.List;
 23  
 import java.util.Map;
 24  
 import java.util.logging.Logger;
 25  
 
 26  
 import javax.faces.component.UIColumn;
 27  
 import javax.faces.component.UIComponent;
 28  
 import javax.faces.component.UIData;
 29  
 import javax.faces.component.behavior.ClientBehavior;
 30  
 import javax.faces.component.behavior.ClientBehaviorHolder;
 31  
 import javax.faces.component.html.HtmlColumn;
 32  
 import javax.faces.component.html.HtmlDataTable;
 33  
 import javax.faces.context.FacesContext;
 34  
 import javax.faces.context.ResponseWriter;
 35  
 
 36  
 import org.apache.myfaces.shared.renderkit.JSFAttr;
 37  
 import org.apache.myfaces.shared.renderkit.RendererUtils;
 38  
 import org.apache.myfaces.shared.renderkit.html.util.ResourceUtils;
 39  
 import org.apache.myfaces.shared.util.ArrayUtils;
 40  
 import org.apache.myfaces.shared.util.StringUtils;
 41  
 
 42  
 /**
 43  
  * Common methods for renderers for components that subclass the standard
 44  
  * JSF HtmlDataTable component.
 45  
  */
 46  0
 public class HtmlTableRendererBase extends HtmlRenderer
 47  
 {
 48  
     /** Header facet name. */
 49  
     protected static final String HEADER_FACET_NAME = "header";
 50  
 
 51  
     /** Footer facet name. */
 52  
     protected static final String FOOTER_FACET_NAME = "footer";
 53  
 
 54  
     protected static final String CAPTION_FACET_NAME = "caption";
 55  
     
 56  
     /** The logger. */
 57  
     //private static final Log log = LogFactory.getLog(HtmlTableRendererBase.class);
 58  0
     private static final Logger log = Logger.getLogger(HtmlTableRendererBase.class.getName());
 59  
     
 60  0
     private static final Integer[] ZERO_INT_ARRAY = new Integer[]{0};
 61  
 
 62  
     /**
 63  
      * @param component dataTable
 64  
      * @return number of layout columns
 65  
      */
 66  
     protected int getNewspaperColumns(UIComponent component)
 67  
     {
 68  0
         return 1;
 69  
     }
 70  
 
 71  
     /**
 72  
      * @param component dataTable
 73  
      * @return component to display between layout columns
 74  
      */
 75  
     protected UIComponent getNewspaperTableSpacer(UIComponent component)
 76  
     {
 77  0
         return null;
 78  
     }
 79  
 
 80  
     /**
 81  
      * @param component dataTable
 82  
      * @return whether dataTable has component to display between layout columns
 83  
      */
 84  
     protected boolean hasNewspaperTableSpacer(UIComponent component)
 85  
     {
 86  0
         return false;
 87  
     }
 88  
 
 89  
     /**
 90  
      * @param component dataTable
 91  
      * @return whether dataTable has newspaper columns layed out horizontally
 92  
      */
 93  
     protected boolean isNewspaperHorizontalOrientation(UIComponent component)
 94  
     {
 95  0
         return false;
 96  
     }
 97  
 
 98  
     /**
 99  
      * @see javax.faces.render.Renderer#getRendersChildren()
 100  
      */
 101  
     public boolean getRendersChildren()
 102  
     {
 103  0
         return true;
 104  
     }
 105  
 
 106  
     /**
 107  
      * Render the necessary bits that come before any actual <i>rows</i> in the table.
 108  
      * 
 109  
      * @see javax.faces.render.Renderer#encodeBegin(FacesContext, UIComponent)
 110  
      */
 111  
     public void encodeBegin(FacesContext facesContext, UIComponent uiComponent) throws IOException
 112  
     {
 113  0
         RendererUtils.checkParamValidity(facesContext, uiComponent, UIData.class);
 114  
 
 115  0
         Map<String, List<ClientBehavior>> behaviors = null;
 116  0
         if (uiComponent instanceof ClientBehaviorHolder)
 117  
         {
 118  0
             behaviors = ((ClientBehaviorHolder) uiComponent).getClientBehaviors();
 119  0
             if (!behaviors.isEmpty())
 120  
             {
 121  0
                 ResourceUtils.renderDefaultJsfJsInlineIfNecessary(facesContext, facesContext.getResponseWriter());
 122  
             }
 123  
         }
 124  
         
 125  0
         beforeTable(facesContext, (UIData) uiComponent);
 126  
 
 127  0
         startTable(facesContext, uiComponent);
 128  0
     }
 129  
 
 130  
     /**
 131  
      * actually render the start of the table
 132  
      */
 133  
     protected void startTable(FacesContext facesContext, UIComponent uiComponent) throws IOException
 134  
     {
 135  0
         ResponseWriter writer = facesContext.getResponseWriter();
 136  0
         writer.startElement(HTML.TABLE_ELEM, uiComponent);
 137  
         
 138  0
         Map<String, List<ClientBehavior>> behaviors = null;
 139  0
         if (uiComponent instanceof ClientBehaviorHolder)
 140  
         {
 141  0
             behaviors = ((ClientBehaviorHolder) uiComponent).getClientBehaviors();
 142  0
             if (!behaviors.isEmpty())
 143  
             {
 144  0
                 HtmlRendererUtils.writeIdAndName(writer, uiComponent, facesContext);
 145  
             }
 146  
             else
 147  
             {
 148  0
                 HtmlRendererUtils.writeIdIfNecessary(writer, uiComponent, facesContext);
 149  
             }
 150  0
             if (behaviors.isEmpty() && isCommonPropertiesOptimizationEnabled(facesContext))
 151  
             {
 152  0
                 CommonPropertyUtils.renderEventProperties(writer, 
 153  
                         CommonPropertyUtils.getCommonPropertiesMarked(uiComponent), uiComponent);
 154  
             }
 155  
             else
 156  
             {
 157  0
                 if (isCommonEventsOptimizationEnabled(facesContext))
 158  
                 {
 159  0
                     CommonEventUtils.renderBehaviorizedEventHandlers(facesContext, writer, 
 160  
                            CommonPropertyUtils.getCommonPropertiesMarked(uiComponent),
 161  
                            CommonEventUtils.getCommonEventsMarked(uiComponent), uiComponent, behaviors);
 162  
                 }
 163  
                 else
 164  
                 {
 165  0
                     HtmlRendererUtils.renderBehaviorizedEventHandlers(facesContext, writer, uiComponent, behaviors);
 166  
                 }
 167  
             }
 168  0
             if (isCommonPropertiesOptimizationEnabled(facesContext))
 169  
             {
 170  0
                 HtmlRendererUtils.renderHTMLAttributes(writer, uiComponent, HTML.TABLE_ATTRIBUTES);
 171  0
                 CommonPropertyUtils.renderCommonPassthroughPropertiesWithoutEvents(writer, 
 172  
                         CommonPropertyUtils.getCommonPropertiesMarked(uiComponent), uiComponent);
 173  
             }
 174  
             else
 175  
             {
 176  0
                 HtmlRendererUtils.renderHTMLAttributes(writer, uiComponent, 
 177  
                         HTML.TABLE_PASSTHROUGH_ATTRIBUTES_WITHOUT_EVENTS);
 178  
             }
 179  
         }
 180  
         else
 181  
         {
 182  0
             HtmlRendererUtils.writeIdIfNecessary(writer, uiComponent, facesContext);
 183  0
             if (isCommonPropertiesOptimizationEnabled(facesContext))
 184  
             {
 185  0
                 HtmlRendererUtils.renderHTMLAttributes(writer, uiComponent, HTML.TABLE_ATTRIBUTES);
 186  0
                 CommonPropertyUtils.renderCommonPassthroughProperties(writer, 
 187  
                         CommonPropertyUtils.getCommonPropertiesMarked(uiComponent), uiComponent);
 188  
             }
 189  
             else
 190  
             {
 191  0
                 HtmlRendererUtils.renderHTMLAttributes(writer, uiComponent, 
 192  
                         HTML.TABLE_PASSTHROUGH_ATTRIBUTES);
 193  
             }
 194  
         }
 195  0
     }
 196  
 
 197  
     /**
 198  
      * Render the TBODY section of the html table. See also method encodeInnerHtml.
 199  
      * 
 200  
      * @see javax.faces.render.Renderer#encodeChildren(FacesContext, UIComponent)
 201  
      */
 202  
     public void encodeChildren(FacesContext facesContext, UIComponent component) throws IOException
 203  
     {
 204  0
         RendererUtils.checkParamValidity(facesContext, component, UIData.class);
 205  
 
 206  0
         beforeBody(facesContext, (UIData) component);
 207  
 
 208  0
         encodeInnerHtml(facesContext, component);
 209  
 
 210  0
         afterBody(facesContext, (UIData) component);
 211  0
     }
 212  
 
 213  
     /**
 214  
      * Renders the caption facet.
 215  
      * @param facesContext the <code>FacesContext</code>.
 216  
      * @param writer the <code>ResponseWriter</code>.
 217  
      * @param component the parent <code>UIComponent</code> containing the facets.
 218  
      * @throws IOException if an exception occurs.
 219  
      */
 220  
     protected void renderCaptionFacet(FacesContext facesContext, ResponseWriter writer, UIComponent component)
 221  
             throws IOException
 222  
     {
 223  0
         HtmlRendererUtils.renderTableCaption(facesContext, writer, component);
 224  0
     }  
 225  
     
 226  
     /**
 227  
      * Renders the colgroups facet.
 228  
      * @param facesContext the <code>FacesContext</code>.
 229  
      * @param writer the <code>ResponseWriter</code>.
 230  
      * @param component the parent <code>UIComponent</code> containing the facets.
 231  
      * @throws IOException if an exception occurs.
 232  
      * @since 2.0
 233  
      */
 234  
     protected void renderColgroupsFacet(FacesContext facesContext, ResponseWriter writer, UIComponent component)
 235  
             throws IOException
 236  
     {
 237  0
         UIComponent colgroupsFacet = component.getFacet("colgroups");
 238  0
         if (colgroupsFacet == null)
 239  
         {
 240  
             // no facet to be rendered
 241  0
             return;
 242  
         }
 243  
         // render the facet
 244  
         //RendererUtils.renderChild(facesContext, colgroupsFacet);
 245  0
         colgroupsFacet.encodeAll(facesContext);
 246  0
     } 
 247  
     
 248  
     /**
 249  
      * Gets styles for the specified component.
 250  
      */
 251  
     protected static Styles getStyles(UIData uiData)
 252  
     {
 253  
         String rowClasses;
 254  
         String columnClasses;
 255  0
         if(uiData instanceof HtmlDataTable) 
 256  
         {
 257  0
             rowClasses = ((HtmlDataTable)uiData).getRowClasses();
 258  0
             columnClasses = ((HtmlDataTable)uiData).getColumnClasses();
 259  
         }
 260  
         else
 261  
         {
 262  0
             rowClasses = (String)uiData.getAttributes().get(JSFAttr.ROW_CLASSES_ATTR);
 263  0
             columnClasses = (String)uiData.getAttributes().get(JSFAttr.COLUMN_CLASSES_ATTR);
 264  
         }
 265  0
         return new Styles(rowClasses, columnClasses);
 266  
     }
 267  
 
 268  
     /**
 269  
      * Class manages the styles from String lists.
 270  
      */
 271  0
     protected static class Styles
 272  
     {
 273  
 
 274  
         private String[] _columnStyle;
 275  
         private String[] _rowStyle;
 276  
 
 277  
         Styles(String rowStyles, String columnStyles)
 278  0
         {
 279  0
             _rowStyle = (rowStyles == null)
 280  
                 ? ArrayUtils.EMPTY_STRING_ARRAY
 281  
                 : StringUtils.trim(
 282  
                     StringUtils.splitShortString(rowStyles, ','));
 283  0
             _columnStyle = (columnStyles == null)
 284  
                 ? ArrayUtils.EMPTY_STRING_ARRAY
 285  
                 : StringUtils.trim(
 286  
                     StringUtils.splitShortString(columnStyles, ','));
 287  0
         }
 288  
 
 289  
         public String getRowStyle(int idx)
 290  
         {
 291  0
             if(!hasRowStyle())
 292  
             {
 293  0
                 return null;
 294  
             }
 295  0
             return _rowStyle[idx % _rowStyle.length];
 296  
         }
 297  
 
 298  
         public String getColumnStyle(int idx)
 299  
         {
 300  0
             if(!hasColumnStyle())
 301  
             {
 302  0
                 return null;
 303  
             }
 304  
             //return _columnStyle[idx % _columnStyle.length];
 305  0
             if (idx < _columnStyle.length)
 306  
             {
 307  0
                 return _columnStyle[idx];
 308  
             }
 309  0
             return null;   
 310  
         }
 311  
 
 312  
         public boolean hasRowStyle()
 313  
         {
 314  0
             return _rowStyle.length > 0;
 315  
         }
 316  
 
 317  
         public boolean hasColumnStyle()
 318  
         {
 319  0
             return _columnStyle.length > 0;
 320  
         }
 321  
     }
 322  
 
 323  
     private Integer[] getBodyRows(FacesContext facesContext, UIComponent component)
 324  
     {
 325  0
         Integer[] bodyrows = null;
 326  0
         String bodyrowsAttr = (String) component.getAttributes().get(JSFAttr.BODYROWS_ATTR);
 327  0
         if(bodyrowsAttr != null && !"".equals(bodyrowsAttr)) 
 328  
         {   
 329  0
             String[] bodyrowsString = StringUtils.trim(StringUtils.splitShortString(bodyrowsAttr, ','));
 330  
             // parsing with no exception handling, because of JSF-spec: 
 331  
             // "If present, this must be a comma separated list of integers."
 332  0
             bodyrows = new Integer[bodyrowsString.length];
 333  0
             for(int i = 0; i < bodyrowsString.length; i++) 
 334  
             {
 335  0
                 bodyrows[i] = Integer.valueOf(bodyrowsString[i]);
 336  
             }
 337  
             
 338  0
         }
 339  
         else
 340  
         {
 341  0
             bodyrows = ZERO_INT_ARRAY;
 342  
         }
 343  0
         return bodyrows;
 344  
     }
 345  
 
 346  
     /**
 347  
      * Renders everything inside the TBODY tag by iterating over the row objects
 348  
      * between offsets first and first+rows and applying the UIColumn components
 349  
      * to those objects. 
 350  
      * <p>
 351  
      * This method is separated from the encodeChildren so that it can be overridden by
 352  
      * subclasses. One class that uses this functionality is autoUpdateDataTable.
 353  
      */
 354  
      public void encodeInnerHtml(FacesContext facesContext, UIComponent component)throws IOException
 355  
      {
 356  0
         UIData uiData = (UIData) component;
 357  0
         ResponseWriter writer = facesContext.getResponseWriter();
 358  
 
 359  0
         int rowCount = uiData.getRowCount();
 360  
 
 361  0
         int newspaperColumns = getNewspaperColumns(component);
 362  
 
 363  0
         if (rowCount == -1 && newspaperColumns == 1)
 364  
         {
 365  0
             encodeInnerHtmlUnknownRowCount(facesContext, component);
 366  0
             return;
 367  
         }
 368  
         
 369  0
         if (rowCount == 0)
 370  
         {
 371  
             //nothing to render, to get valid xhtml we render an empty dummy row
 372  0
             writer.startElement(HTML.TBODY_ELEM, null); // uiData);
 373  0
             writer.writeAttribute(HTML.ID_ATTR, component.getClientId(facesContext) + ":tbody_element", null);
 374  0
             writer.startElement(HTML.TR_ELEM, null); // uiData);
 375  0
             writer.startElement(HTML.TD_ELEM, null); // uiData);
 376  0
             writer.endElement(HTML.TD_ELEM);
 377  0
             writer.endElement(HTML.TR_ELEM);
 378  0
             writer.endElement(HTML.TBODY_ELEM);
 379  0
             return;
 380  
         }
 381  
 
 382  
         // begin the table
 383  
         // get the CSS styles
 384  0
         Styles styles = getStyles(uiData);
 385  
 
 386  0
         int first = uiData.getFirst();
 387  0
         int rows = uiData.getRows();
 388  
         int last;
 389  
 
 390  0
         if (rows <= 0)
 391  
         {
 392  0
            last = rowCount;
 393  
         }
 394  
         else
 395  
         {
 396  0
            last = first + rows;
 397  0
            if (last > rowCount)
 398  
            {
 399  0
                last = rowCount;
 400  
            }
 401  
         }
 402  
 
 403  
         int newspaperRows;
 404  0
         if((last - first) % newspaperColumns == 0)
 405  
         {
 406  0
             newspaperRows = (last - first) / newspaperColumns;
 407  
         }
 408  
         else
 409  
         {
 410  0
             newspaperRows = ((last - first) / newspaperColumns) + 1;
 411  
         }
 412  0
         boolean newspaperHorizontalOrientation = isNewspaperHorizontalOrientation(component);
 413  
         
 414  
         // get the row indizes for which a new TBODY element should be created
 415  0
         Integer[] bodyrows = getBodyRows(facesContext, component);
 416  0
         int bodyrowsCount = 0;
 417  
 
 418  
         // walk through the newspaper rows
 419  0
         for(int nr = 0; nr < newspaperRows; nr++)
 420  
         {
 421  0
             boolean rowStartRendered = false;
 422  
             // walk through the newspaper columns
 423  0
             for(int nc = 0; nc < newspaperColumns; nc++)
 424  
             {
 425  
 
 426  
                 // the current row in the 'real' table
 427  
                 int currentRow;
 428  0
                 if (newspaperHorizontalOrientation)
 429  
                 {
 430  0
                     currentRow = nr * newspaperColumns + nc + first;
 431  
                 }
 432  
                 else
 433  
                 {
 434  0
                     currentRow = nc * newspaperRows + nr + first;
 435  
                 }
 436  
                 
 437  
                 // if this row is not to be rendered
 438  0
                 if(currentRow >= last)
 439  
                 {
 440  0
                     continue;
 441  
                 }
 442  
 
 443  
                 // bail if any row does not exist
 444  0
                 uiData.setRowIndex(currentRow);
 445  0
                 if(!uiData.isRowAvailable())
 446  
                 {
 447  0
                     log.severe("Row is not available. Rowindex = " + currentRow);
 448  0
                     break;
 449  
                 }
 450  
     
 451  0
                 if (nc == 0)
 452  
                 {
 453  
                     // first column in table, start new row
 454  0
                     beforeRow(facesContext, uiData);
 455  
 
 456  
                     // is the current row listed in the bodyrows attribute
 457  0
                     if(ArrayUtils.contains(bodyrows, currentRow))  
 458  
                     {
 459  
                         // close any preopened TBODY element first
 460  0
                         if(bodyrowsCount != 0) 
 461  
                         {
 462  0
                             writer.endElement(HTML.TBODY_ELEM);
 463  
                         }
 464  0
                         writer.startElement(HTML.TBODY_ELEM, null); // uiData); 
 465  
                         // Do not attach bodyrowsCount to the first TBODY element, because of backward compatibility
 466  0
                         writer.writeAttribute(HTML.ID_ATTR, component.getClientId(facesContext) + ":tbody_element" + 
 467  
                             (bodyrowsCount == 0 ? "" : bodyrowsCount), null);
 468  0
                         bodyrowsCount++;
 469  
                     }
 470  
                     
 471  0
                     renderRowStart(facesContext, writer, uiData, styles, nr);
 472  0
                     rowStartRendered = true;
 473  
                 }
 474  
 
 475  0
                 List children = null;
 476  0
                 int columnStyleIndex = 0;
 477  0
                 for (int j = 0, size = getChildCount(component); j < size; j++)
 478  
                 {
 479  0
                     if (children == null)
 480  
                     {
 481  0
                         children = getChildren(component);
 482  
                     }
 483  0
                     UIComponent child = (UIComponent) children.get(j);
 484  0
                     if (child.isRendered())
 485  
                     {
 486  0
                         boolean columnRendering = child instanceof UIColumn;
 487  
                         
 488  0
                         if (columnRendering)
 489  
                         {
 490  0
                             beforeColumn(facesContext, uiData, columnStyleIndex);
 491  
                         }
 492  
                            
 493  0
                         encodeColumnChild(facesContext, writer, uiData, child, 
 494  
                                 styles, nc * uiData.getChildCount() + columnStyleIndex);
 495  
                        
 496  0
                         if (columnRendering)
 497  
                         {
 498  0
                             afterColumn(facesContext, uiData, columnStyleIndex);
 499  
                         }
 500  0
                         columnStyleIndex = columnStyleIndex + 
 501  
                             getColumnCountForComponent(facesContext, uiData, child);
 502  
                     }
 503  
                 }
 504  
 
 505  0
                 if (hasNewspaperTableSpacer(uiData))
 506  
                 {
 507  
                     // draw the spacer facet
 508  0
                     if(nc < newspaperColumns - 1)
 509  
                     {
 510  0
                         renderSpacerCell(facesContext, writer, uiData);
 511  
                     }
 512  
                 }
 513  
             }
 514  0
             if (rowStartRendered)
 515  
             {
 516  0
                 renderRowEnd(facesContext, writer, uiData);
 517  0
                 afterRow(facesContext, uiData);
 518  
             }
 519  
         }
 520  
         
 521  0
         if(bodyrowsCount != 0)
 522  
         {
 523  
             // close the last TBODY element
 524  0
             writer.endElement(HTML.TBODY_ELEM);
 525  
         }
 526  0
     }
 527  
      
 528  
     private void encodeInnerHtmlUnknownRowCount(FacesContext facesContext, UIComponent component)throws IOException
 529  
     {
 530  0
         UIData uiData = (UIData) component;
 531  0
         ResponseWriter writer = facesContext.getResponseWriter();
 532  
 
 533  0
         Styles styles = getStyles(uiData);
 534  
         
 535  0
         Integer[] bodyrows = getBodyRows(facesContext, component);
 536  0
         int bodyrowsCount = 0;
 537  
         
 538  0
         int first = uiData.getFirst();
 539  0
         int rows = uiData.getRows();
 540  0
         int currentRow = first;
 541  0
         boolean isRowRendered = false;
 542  
         
 543  
         while(true)
 544  
         {
 545  0
             uiData.setRowIndex(currentRow);
 546  0
             if (!uiData.isRowAvailable())
 547  
             {
 548  0
                 break;
 549  
             }
 550  
             
 551  0
             isRowRendered = true;
 552  
             
 553  
             // first column in table, start new row
 554  0
             beforeRow(facesContext, uiData);
 555  
 
 556  
             // is the current row listed in the bodyrows attribute
 557  0
             if(ArrayUtils.contains(bodyrows, currentRow))  
 558  
             {
 559  
                 // close any preopened TBODY element first
 560  0
                 if(bodyrowsCount != 0) 
 561  
                 {
 562  0
                     writer.endElement(HTML.TBODY_ELEM);
 563  
                 }
 564  0
                 writer.startElement(HTML.TBODY_ELEM, null); // uiData); 
 565  
                 // Do not attach bodyrowsCount to the first TBODY element, because of backward compatibility
 566  0
                 writer.writeAttribute(HTML.ID_ATTR, component.getClientId(facesContext) + ":tbody_element" + 
 567  
                     (bodyrowsCount == 0 ? "" : bodyrowsCount), null);
 568  0
                 bodyrowsCount++;
 569  
             }
 570  
             
 571  0
             renderRowStart(facesContext, writer, uiData, styles, currentRow);
 572  
             
 573  0
             List<UIComponent> children = null;
 574  0
             int columnStyleIndex = 0;
 575  0
             for (int j = 0, size = getChildCount(component); j < size; j++)
 576  
             {
 577  0
                 if (children == null)
 578  
                 {
 579  0
                     children = getChildren(component);
 580  
                 }
 581  0
                 UIComponent child = (UIComponent) children.get(j);
 582  0
                 if (child.isRendered())
 583  
                 {
 584  0
                     boolean columnRendering = child instanceof UIColumn;
 585  
                     
 586  0
                     if (columnRendering)
 587  
                     {
 588  0
                         beforeColumn(facesContext, uiData, columnStyleIndex);
 589  
                     }
 590  
                        
 591  0
                     encodeColumnChild(facesContext, writer, uiData, child, 
 592  
                             styles, columnStyleIndex);
 593  
                    
 594  0
                     if (columnRendering)
 595  
                     {
 596  0
                         afterColumn(facesContext, uiData, columnStyleIndex);
 597  
                     }
 598  0
                     columnStyleIndex = columnStyleIndex + 
 599  
                             getColumnCountForComponent(facesContext, uiData, child);
 600  
                 }
 601  
             }
 602  
 
 603  0
             renderRowEnd(facesContext, writer, uiData);
 604  0
             afterRow(facesContext, uiData);
 605  
             
 606  0
             currentRow++;
 607  
 
 608  0
             if (rows > 0 && currentRow-first > rows )
 609  
             {
 610  0
                 break;
 611  
             }
 612  0
         }
 613  
         
 614  0
         if (!isRowRendered)
 615  
         {
 616  
             //nothing to render, to get valid xhtml we render an empty dummy row
 617  0
             writer.startElement(HTML.TBODY_ELEM, null); // uiData);
 618  0
             writer.writeAttribute(HTML.ID_ATTR, component.getClientId(facesContext) + ":tbody_element", null);
 619  0
             writer.startElement(HTML.TR_ELEM, null); // uiData);
 620  0
             writer.startElement(HTML.TD_ELEM, null); // uiData);
 621  0
             writer.endElement(HTML.TD_ELEM);
 622  0
             writer.endElement(HTML.TR_ELEM);
 623  0
             writer.endElement(HTML.TBODY_ELEM);
 624  0
             return;
 625  
         }
 626  
 
 627  0
         if(bodyrowsCount != 0)
 628  
         {
 629  
             // close the last TBODY element
 630  0
             writer.endElement(HTML.TBODY_ELEM);
 631  
         }
 632  0
     }
 633  
 
 634  
     protected void encodeColumnChild(FacesContext facesContext, ResponseWriter writer,
 635  
         UIData uiData, UIComponent component, Styles styles, int columnStyleIndex) throws IOException
 636  
     {
 637  0
         if (component instanceof UIColumn)
 638  
         {            
 639  0
             renderColumnBody(facesContext, writer, uiData, component, styles, columnStyleIndex);            
 640  
         }
 641  0
     }
 642  
 
 643  
     /**
 644  
      * Renders the body of a given <code>UIColumn</code> (everything but
 645  
      * the header and footer facets). This emits a TD cell, whose contents
 646  
      * are the result of calling encodeBegin, encodeChildren and
 647  
      * encodeEnd methods on the component (or its associated renderer).
 648  
      * 
 649  
      * @param facesContext the <code>FacesContext</code>.
 650  
      * @param writer the <code>ResponseWriter</code>.
 651  
      * @param uiData the <code>UIData</code> being rendered.
 652  
      * @param component the <code>UIComponent</code> to render.
 653  
      * @throws IOException if an exception occurs.
 654  
      */
 655  
     protected void renderColumnBody(
 656  
             FacesContext facesContext,
 657  
             ResponseWriter writer,
 658  
             UIData uiData,
 659  
             UIComponent component,
 660  
             Styles styles, int columnStyleIndex) throws IOException
 661  
     {
 662  
         // Get the rowHeader attribute from the attribute map, because of MYFACES-1790
 663  0
         Object rowHeaderAttr = component.getAttributes().get(JSFAttr.ROW_HEADER_ATTR);
 664  0
         boolean rowHeader = rowHeaderAttr != null && ((Boolean) rowHeaderAttr);
 665  
         
 666  0
         if(rowHeader) 
 667  
         {
 668  0
             writer.startElement(HTML.TH_ELEM, null); // uiData);   
 669  0
             writer.writeAttribute(HTML.SCOPE_ATTR, HTML.SCOPE_ROW_VALUE, null);
 670  
         }
 671  
         else 
 672  
         {
 673  0
             writer.startElement(HTML.TD_ELEM, null); // uiData);
 674  
         }
 675  0
         if (styles.hasColumnStyle())
 676  
         {
 677  0
             writer.writeAttribute(HTML.CLASS_ATTR, styles.getColumnStyle(columnStyleIndex), null);
 678  
         }
 679  
         //RendererUtils.renderChild(facesContext, component);
 680  0
         component.encodeAll(facesContext);
 681  0
         if(rowHeader) 
 682  
         {
 683  0
             writer.endElement(HTML.TH_ELEM);   
 684  
         }
 685  
         else 
 686  
         {
 687  0
             writer.endElement(HTML.TD_ELEM);
 688  
         }
 689  0
     }
 690  
 
 691  
     /**
 692  
      * Renders the start of a new row of body content.
 693  
      * @param facesContext the <code>FacesContext</code>.
 694  
      * @param writer the <code>ResponseWriter</code>.
 695  
      * @param uiData the <code>UIData</code> being rendered.
 696  
      * @throws IOException if an exceptoin occurs.
 697  
      */
 698  
     protected void renderRowStart(
 699  
         FacesContext facesContext,
 700  
         ResponseWriter writer,
 701  
         UIData uiData,
 702  
         Styles styles, int rowStyleIndex) throws IOException
 703  
     {
 704  0
         writer.startElement(HTML.TR_ELEM, null); // uiData);
 705  
         
 706  0
         renderRowStyle(facesContext, writer, uiData, styles, rowStyleIndex);
 707  
         
 708  0
         Object rowId = uiData.getAttributes().get(org.apache.myfaces.shared.renderkit.JSFAttr.ROW_ID);
 709  
 
 710  0
         if (rowId != null)
 711  
         {
 712  0
             writer.writeAttribute(HTML.ID_ATTR, rowId.toString(), null);
 713  
         }
 714  0
     }
 715  
 
 716  
     protected void renderRowStyle(FacesContext facesContext, ResponseWriter writer, 
 717  
             UIData uiData, Styles styles, int rowStyleIndex) throws IOException
 718  
     {
 719  0
         if(styles.hasRowStyle())
 720  
         {
 721  0
             String rowStyle = styles.getRowStyle(rowStyleIndex);
 722  0
             writer.writeAttribute(HTML.CLASS_ATTR, rowStyle, null);
 723  
         }
 724  0
     }
 725  
 
 726  
     /**
 727  
      * Renders the end of a row of body content.
 728  
      * @param facesContext the <code>FacesContext</code>.
 729  
      * @param writer the <code>ResponseWriter</code>.
 730  
      * @param uiData the <code>UIData</code> being rendered.
 731  
      * @throws IOException if an exceptoin occurs.
 732  
      */
 733  
     protected void renderRowEnd(
 734  
         FacesContext facesContext,
 735  
         ResponseWriter writer,
 736  
         UIData uiData) throws IOException
 737  
     {
 738  0
         writer.endElement(HTML.TR_ELEM);
 739  0
     }
 740  
 
 741  
     /**
 742  
      * Perform any operations necessary immediately before the TABLE start tag
 743  
      * is output.
 744  
      *
 745  
      * @param facesContext the <code>FacesContext</code>.
 746  
      * @param uiData the <code>UIData</code> being rendered.
 747  
      */
 748  
     protected void beforeTable(FacesContext facesContext, UIData uiData) throws IOException
 749  
     {
 750  0
     }
 751  
 
 752  
     /**
 753  
      * Perform any operations necessary after TABLE start tag is output
 754  
      * but before the TBODY start tag.
 755  
      * <p>
 756  
      * This method generates the THEAD/TFOOT sections of a table if there
 757  
      * are any header or footer facets defined on the table or on any child
 758  
      * UIColumn component.
 759  
      *
 760  
      * @param facesContext the <code>FacesContext</code>.
 761  
      * @param uiData the <code>UIData</code> being rendered.
 762  
      */
 763  
     protected void beforeBody(FacesContext facesContext, UIData uiData) throws IOException
 764  
     {
 765  0
         ResponseWriter writer = facesContext.getResponseWriter();
 766  
 
 767  0
         renderCaptionFacet(facesContext, writer, uiData);
 768  0
         renderColgroupsFacet(facesContext, writer, uiData);
 769  0
         renderFacet(facesContext, writer, uiData, true);
 770  0
         renderFacet(facesContext, writer, uiData, false);
 771  0
     }
 772  
 
 773  
     /**
 774  
      * Perform any operations necessary immediately before each TR start tag
 775  
      * is output.
 776  
      *
 777  
      * @param facesContext the <code>FacesContext</code>.
 778  
      * @param uiData the <code>UIData</code> being rendered.
 779  
      */
 780  
     protected void beforeRow(FacesContext facesContext, UIData uiData) throws IOException
 781  
     {
 782  0
     }
 783  
 
 784  
     /**
 785  
      * Perform any operations necessary immediately after each TR end tag
 786  
      * is output.
 787  
      *
 788  
      * @param facesContext the <code>FacesContext</code>.
 789  
      * @param uiData the <code>UIData</code> being rendered.
 790  
      */
 791  
     protected void afterRow(FacesContext facesContext, UIData uiData) throws IOException
 792  
     {
 793  0
     }
 794  
     /**
 795  
      * Perform any operations necessary immediately before each column child is rendered
 796  
      *
 797  
      * @param facesContext the <code>FacesContext</code>.
 798  
      * @param uiData the <code>UIData</code> being rendered.
 799  
      * @param columnIndex the index of the currenly rendered column
 800  
      */
 801  
     protected void beforeColumn(FacesContext facesContext, UIData uiData, int columnIndex) throws IOException
 802  
     {        
 803  0
     }
 804  
     /**
 805  
      * Perform any operations necessary immediately after each column child is rendered
 806  
      *
 807  
      * @param facesContext the <code>FacesContext</code>.
 808  
      * @param uiData the <code>UIData</code> being rendered.
 809  
      * @param columnIndex the index of the currenly rendered column
 810  
      */
 811  
     protected void afterColumn(FacesContext facesContext, UIData uiData, int columnIndex) throws IOException
 812  
     {        
 813  0
     }
 814  
     /**
 815  
      * Indicates the number of columns the component represents. By default each UIColumn instance
 816  
      * is 1 column
 817  
      * @param facesContext
 818  
      * @param uiData
 819  
      * @param child
 820  
      * @return 
 821  
      */
 822  
     protected int getColumnCountForComponent(FacesContext facesContext, UIData uiData, UIComponent child)
 823  
     {
 824  0
         if (child instanceof UIColumn)
 825  
         {
 826  0
             return 1;
 827  
         }
 828  0
         return 0;
 829  
     }
 830  
     /**
 831  
      *Perform any operations necessary immediately before each column child's header or footer is rendered
 832  
      *
 833  
      * @param facesContext the <code>FacesContext</code>.
 834  
      * @param uiData the <code>UIData</code> being rendered.
 835  
      * @param header true if the header of the column child is rendered
 836  
      * @param columnIndex the index of the currenly rendered column
 837  
      */
 838  
     protected void beforeColumnHeaderOrFooter(FacesContext facesContext, UIData uiData, boolean header,
 839  
             int columnIndex) throws IOException
 840  
     {         
 841  0
     }
 842  
     /**
 843  
      * Perform any operations necessary immediately after each column child's header of footer is rendered
 844  
      *
 845  
      * @param facesContext the <code>FacesContext</code>.
 846  
      * @param uiData the <code>UIData</code> being rendered.
 847  
      * @param header true if the header of the column child is rendered
 848  
      * @param columnIndex the index of the currenly rendered column
 849  
      */
 850  
     protected void afterColumnHeaderOrFooter(FacesContext facesContext, UIData uiData, boolean header,
 851  
             int columnIndex) throws IOException
 852  
     {         
 853  0
     }
 854  
 
 855  
     /**
 856  
      * Perform any operations necessary in the TBODY start tag.
 857  
      *
 858  
      * @param facesContext the <code>FacesContext</code>.
 859  
      * @param uiData the <code>UIData</code> being rendered.
 860  
      */
 861  
     protected void inBodyStart(FacesContext facesContext, UIData uiData) throws IOException
 862  
     {
 863  0
     }
 864  
 
 865  
     /**
 866  
      * Perform any operations necessary immediately after the TBODY end tag
 867  
      * is output.
 868  
      *
 869  
      * @param facesContext the <code>FacesContext</code>.
 870  
      * @param uiData the <code>UIData</code> being rendered.
 871  
      */
 872  
     protected void afterBody(FacesContext facesContext, UIData uiData) throws IOException
 873  
     {
 874  0
     }
 875  
 
 876  
     /**
 877  
      * Perform any operations necessary immediately after the TABLE end tag
 878  
      * is output.
 879  
      *
 880  
      * @param facesContext the <code>FacesContext</code>.
 881  
      * @param uiData the <code>UIData</code> being rendered.
 882  
      */
 883  
     protected void afterTable(FacesContext facesContext, UIData uiData) throws IOException
 884  
     {
 885  0
     }
 886  
 
 887  
     /**
 888  
      * @see javax.faces.render.Renderer#encodeEnd(FacesContext, UIComponent)
 889  
      */
 890  
     public void encodeEnd(FacesContext facesContext, UIComponent uiComponent) throws IOException
 891  
     {
 892  0
         RendererUtils.checkParamValidity(facesContext, uiComponent, UIData.class);
 893  
 
 894  0
         endTable(facesContext, uiComponent);
 895  
 
 896  0
         afterTable(facesContext, (UIData) uiComponent);
 897  0
     }
 898  
 
 899  
     /**
 900  
      * actually render the end of the table
 901  
      */
 902  
     protected void endTable(FacesContext facesContext, UIComponent uiComponent) throws IOException
 903  
     {
 904  0
         ResponseWriter writer = facesContext.getResponseWriter();
 905  0
         writer.endElement(HTML.TABLE_ELEM);
 906  0
     }
 907  
 
 908  
     /**
 909  
      * Renders either the header or the footer facets for the UIData component
 910  
      * and all the child UIColumn components, as a THEAD or TFOOT element
 911  
      * containing TR (row) elements.
 912  
      * <p>
 913  
      * If there is a header or footer attached to the UIData then that is
 914  
      * rendered as a TR element whose COLSPAN is the sum of all rendered
 915  
      * columns in the table. This allows that header/footer to take up the
 916  
      * entire width of the table.
 917  
      * <p>
 918  
      * If any child column has a header or footer then a TR is rendered
 919  
      * with a TH cell for each column child. 
 920  
      * 
 921  
      * @param facesContext the <code>FacesContext</code>.
 922  
      * @param writer the <code>ResponseWriter</code>.
 923  
      * @param component the UIData component
 924  
      * @param header whether this is the header facet (if not, then the footer facet).
 925  
      * @throws IOException if an exception occurs.
 926  
      */
 927  
     protected void renderFacet(FacesContext facesContext, ResponseWriter writer,
 928  
             UIComponent component, boolean header)
 929  
             throws IOException
 930  
     {
 931  0
         int colspan = 0;
 932  0
         boolean hasColumnFacet = false;
 933  0
         int childCount = component.getChildCount();
 934  0
         for (int i = 0; i < childCount; i++)
 935  
         {
 936  0
             UIComponent uiComponent = component.getChildren().get(i);
 937  0
             if(uiComponent.isRendered())
 938  
             {
 939  
                 // a UIColumn has a span of 1, anything else has a span of 0
 940  0
                 colspan += determineChildColSpan(uiComponent);
 941  
 
 942  
                 // hasColumnFacet is true if *any* child column has a facet of
 943  
                 // the specified type.
 944  0
                 if (!hasColumnFacet)
 945  
                 {
 946  0
                     hasColumnFacet = hasFacet(header, uiComponent);
 947  
                 }
 948  
             }
 949  
         }
 950  
 
 951  
         
 952  0
         UIComponent facet = null;
 953  0
         if (component.getFacetCount() > 0)
 954  
         {
 955  0
             facet = header ? (UIComponent) component.getFacets().get(HEADER_FACET_NAME) 
 956  
                     : (UIComponent) component.getFacets().get(FOOTER_FACET_NAME);
 957  
         }
 958  0
         if (facet != null || hasColumnFacet)
 959  
         {
 960  
             // Header or Footer present on either the UIData or a column, so we
 961  
             // definitely need to render the THEAD or TFOOT section.
 962  0
             String elemName = determineHeaderFooterTag(facesContext, component, header);
 963  
 
 964  0
             if (elemName != null)
 965  
             {
 966  0
                 writer.startElement(elemName, null); // component);
 967  
             }
 968  0
             if (header)
 969  
             {
 970  0
                 String headerStyleClass = getHeaderClass(component);
 971  0
                 if (facet != null)
 972  
                 {
 973  0
                     renderTableHeaderRow(facesContext, writer, component, facet, headerStyleClass, colspan);
 974  
                 }
 975  0
                 if (hasColumnFacet)
 976  
                 {
 977  0
                     renderColumnHeaderRow(facesContext, writer, component, headerStyleClass);
 978  
                 }
 979  0
             }
 980  
             else
 981  
             {
 982  0
                 String footerStyleClass = getFooterClass(component);
 983  0
                 if (hasColumnFacet)
 984  
                 {
 985  0
                     renderColumnFooterRow(facesContext, writer, component, footerStyleClass);
 986  
                 }
 987  0
                 if (facet != null)
 988  
                 {
 989  0
                     renderTableFooterRow(facesContext, writer, component, facet, footerStyleClass, colspan);
 990  
                 }
 991  
             }
 992  0
             if (elemName != null)
 993  
             {
 994  0
                 writer.endElement(elemName);
 995  
             }
 996  
         }
 997  0
     }
 998  
 
 999  
     protected String determineHeaderFooterTag(FacesContext facesContext, UIComponent component, boolean header)
 1000  
     {
 1001  0
         return header ? HTML.THEAD_ELEM : HTML.TFOOT_ELEM;
 1002  
     }
 1003  
 
 1004  
     /**
 1005  
      * @param header
 1006  
      * @param uiComponent
 1007  
      * @return boolean
 1008  
      */
 1009  
     protected boolean hasFacet(boolean header, UIComponent uiComponent)
 1010  
     {
 1011  0
         if (uiComponent instanceof UIColumn)
 1012  
         {
 1013  0
             UIColumn uiColumn = (UIColumn) uiComponent;
 1014  0
             return header ? uiColumn.getHeader() != null : uiColumn.getFooter() != null;
 1015  
         }
 1016  0
         return false;
 1017  
     }
 1018  
 
 1019  
     /**
 1020  
      * Calculate the number of columns the specified child component will span
 1021  
      * when rendered.
 1022  
      * <p>
 1023  
      * Normally, this is a fairly simple calculation: a UIColumn component
 1024  
      * is rendered as one column, every other child type is not rendered
 1025  
      * (ie spans zero columns). However custom subclasses of this renderer may
 1026  
      * override this method to handle cases where a single component renders
 1027  
      * as multiple columns. 
 1028  
      */
 1029  
     protected int determineChildColSpan(UIComponent uiComponent)
 1030  
     {
 1031  0
         if (uiComponent instanceof UIColumn)
 1032  
         {
 1033  0
             return 1;
 1034  
         }
 1035  0
         return 0;
 1036  
     }
 1037  
 
 1038  
     /**
 1039  
      * Renders the header row of the table being rendered.
 1040  
      * @param facesContext the <code>FacesContext</code>.
 1041  
      * @param writer the <code>ResponseWriter</code>.
 1042  
      * @param component the <code>UIComponent</code> for whom a table is being rendered.
 1043  
      * @param headerFacet the facet for the header.
 1044  
      * @param headerStyleClass the styleClass of the header.
 1045  
      * @param colspan the number of columns the header should span.  Typically, this is
 1046  
      * the number of columns in the table.
 1047  
      * @throws IOException if an exception occurs.
 1048  
      */
 1049  
     protected void renderTableHeaderRow(FacesContext facesContext, ResponseWriter writer, UIComponent component,
 1050  
             UIComponent headerFacet, String headerStyleClass, int colspan) throws IOException
 1051  
     {
 1052  0
         renderTableHeaderOrFooterRow(facesContext, writer, component, headerFacet, headerStyleClass, 
 1053  
                 determineHeaderCellTag(facesContext, component),
 1054  
                 colspan, true);
 1055  0
     }
 1056  
 
 1057  
     /**
 1058  
      * Renders the footer row of the table being rendered.
 1059  
      * @param facesContext the <code>FacesContext</code>.
 1060  
      * @param writer the <code>ResponseWriter</code>.
 1061  
      * @param component the <code>UIComponent</code> for whom a table is being rendered.
 1062  
      * @param footerFacet the facet for the footer.
 1063  
      * @param footerStyleClass the styleClass of the footer.
 1064  
      * @param colspan the number of columns the header should span.  Typically, this is
 1065  
      * the number of columns in the table.
 1066  
      * @throws IOException if an exception occurs.
 1067  
      */
 1068  
     protected void renderTableFooterRow(FacesContext facesContext, ResponseWriter writer, UIComponent component,
 1069  
             UIComponent footerFacet, String footerStyleClass, int colspan) throws IOException
 1070  
     {
 1071  0
         renderTableHeaderOrFooterRow(facesContext, writer, component, footerFacet, footerStyleClass, HTML.TD_ELEM,
 1072  
                 colspan, false);
 1073  0
     }
 1074  
 
 1075  
     /**
 1076  
      * Renders the header row for the columns, which is a separate row from the header row for the
 1077  
      * <code>UIData</code> header facet.
 1078  
      * 
 1079  
      * @param facesContext the <code>FacesContext</code>.
 1080  
      * @param writer the <code>ResponseWriter</code>.
 1081  
      * @param component the UIData component for whom a table is being rendered.
 1082  
      * @param headerStyleClass the styleClass of the header
 1083  
      * @throws IOException if an exception occurs.
 1084  
      */
 1085  
     protected void renderColumnHeaderRow(FacesContext facesContext, ResponseWriter writer, UIComponent component,
 1086  
             String headerStyleClass) throws IOException
 1087  
     {
 1088  0
         renderColumnHeaderOrFooterRow(facesContext, writer, component, headerStyleClass, true);
 1089  0
     }
 1090  
 
 1091  
     /**
 1092  
      * Renders the footer row for the columns, which is a separate row from the footer row for the
 1093  
      * <code>UIData</code> footer facet.
 1094  
      * @param facesContext the <code>FacesContext</code>.
 1095  
      * @param writer the <code>ResponseWriter</code>.
 1096  
      * @param component the <code>UIComponent</code> for whom a table is being rendered.
 1097  
      * @param footerStyleClass the styleClass of the footerStyleClass
 1098  
      * @throws IOException if an exception occurs.
 1099  
      */
 1100  
     protected void renderColumnFooterRow(FacesContext facesContext, ResponseWriter writer, UIComponent component,
 1101  
             String footerStyleClass) throws IOException
 1102  
     {
 1103  0
         renderColumnHeaderOrFooterRow(facesContext, writer, component, footerStyleClass, false);
 1104  0
     }
 1105  
 
 1106  
     protected void renderTableHeaderOrFooterRow(FacesContext facesContext, ResponseWriter writer, 
 1107  
             UIComponent component,
 1108  
             UIComponent facet, String styleClass, String colElementName, int colspan, boolean isHeader)
 1109  
             throws IOException
 1110  
     {
 1111  0
         writer.startElement(HTML.TR_ELEM, null); // component);
 1112  0
         writer.startElement(colElementName, null); // component);
 1113  0
         if (colElementName.equals(determineHeaderCellTag(facesContext, component)) && isHeader)
 1114  
         {
 1115  0
             writer.writeAttribute(HTML.SCOPE_ATTR, HTML.SCOPE_COLGROUP_VALUE, null);
 1116  
         }
 1117  
 
 1118  
         // span all the table's columns
 1119  0
         int newsPaperColumns = getNewspaperColumns(component);
 1120  0
         int totalColumns = colspan * newsPaperColumns;
 1121  0
         if(hasNewspaperTableSpacer(component))
 1122  
         {
 1123  0
             totalColumns = totalColumns + newsPaperColumns - 1;
 1124  
         }
 1125  
         // Only render colspan if is > 0
 1126  0
         if (totalColumns > 0)
 1127  
         {
 1128  0
             writer.writeAttribute(HTML.COLSPAN_ATTR, Integer.valueOf(totalColumns), null);
 1129  
         }
 1130  0
         if (styleClass != null)
 1131  
         {
 1132  0
             writer.writeAttribute(HTML.CLASS_ATTR, styleClass, null);
 1133  
         }
 1134  0
         if (facet != null)
 1135  
         {
 1136  
             //RendererUtils.renderChild(facesContext, facet);
 1137  0
             facet.encodeAll(facesContext);
 1138  
         }
 1139  0
         writer.endElement(colElementName);
 1140  0
         writer.endElement(HTML.TR_ELEM);
 1141  0
     }
 1142  
 
 1143  
     /**
 1144  
      * @param component the UIData component for whom a table is being rendered.
 1145  
      */
 1146  
     private void renderColumnHeaderOrFooterRow(FacesContext facesContext, ResponseWriter writer,
 1147  
             UIComponent component, String styleClass, boolean header) throws IOException
 1148  
     {
 1149  
 
 1150  0
         writer.startElement(HTML.TR_ELEM, null); // component);
 1151  0
         int columnIndex = 0;
 1152  0
         int newspaperColumns = getNewspaperColumns(component);
 1153  0
         for(int nc = 0; nc < newspaperColumns; nc++)
 1154  
         {
 1155  0
             for (int i = 0, childCount = component.getChildCount(); i < childCount; i++)
 1156  
             {
 1157  0
                 UIComponent uiComponent = component.getChildren().get(i);
 1158  0
                 if (uiComponent.isRendered())
 1159  
                 {
 1160  0
                     if (component instanceof UIData && uiComponent instanceof UIColumn)
 1161  
                     {
 1162  0
                         beforeColumnHeaderOrFooter(facesContext, (UIData) component, header, columnIndex);
 1163  
                     }
 1164  
                 
 1165  0
                     renderColumnChildHeaderOrFooterRow(facesContext, writer, uiComponent, styleClass, header);
 1166  
                     
 1167  0
                     if (component instanceof UIData && uiComponent instanceof UIColumn)
 1168  
                     {
 1169  0
                         afterColumnHeaderOrFooter(facesContext, (UIData) component, header, columnIndex);
 1170  
                     }
 1171  
                 }
 1172  0
                 columnIndex += 1;
 1173  
             }
 1174  
 
 1175  0
             if (hasNewspaperTableSpacer(component))
 1176  
             {
 1177  
                 // draw the spacer facet
 1178  0
                 if(nc < newspaperColumns - 1)
 1179  
                 {
 1180  0
                     renderSpacerCell(facesContext, writer, component);
 1181  
                 }
 1182  
             }
 1183  
         }
 1184  0
         writer.endElement(HTML.TR_ELEM);
 1185  0
     }
 1186  
 
 1187  
       /**
 1188  
       * Renders a spacer between adjacent newspaper columns.
 1189  
       */
 1190  
     protected void renderSpacerCell(FacesContext facesContext, ResponseWriter writer, UIComponent component)
 1191  
         throws IOException 
 1192  
     {
 1193  0
         UIComponent spacer = getNewspaperTableSpacer(component);
 1194  0
         if(spacer == null)
 1195  
         {
 1196  0
             return;
 1197  
         }
 1198  
          
 1199  0
          writer.startElement(HTML.TD_ELEM, null); // component);
 1200  
          //RendererUtils.renderChild(facesContext, spacer);
 1201  0
          spacer.encodeAll(facesContext);
 1202  0
          writer.endElement(HTML.TD_ELEM);
 1203  0
      }
 1204  
 
 1205  
     protected void renderColumnChildHeaderOrFooterRow(FacesContext facesContext,
 1206  
         ResponseWriter writer, UIComponent uiComponent, String styleClass, boolean isHeader) throws IOException
 1207  
     {
 1208  0
         if (uiComponent instanceof UIColumn)
 1209  
         {
 1210  
             // allow column to override style class, new in JSF 1.2
 1211  0
             if (uiComponent instanceof HtmlColumn)
 1212  
             {
 1213  0
                 HtmlColumn column = (HtmlColumn)uiComponent;
 1214  0
                 if (isHeader && column.getHeaderClass()!=null)
 1215  
                 {
 1216  0
                     styleClass = column.getHeaderClass();
 1217  
                 }
 1218  0
                 else if (!isHeader && column.getFooterClass()!=null)
 1219  
                 {
 1220  0
                     styleClass = column.getFooterClass();
 1221  
                 }
 1222  0
             }
 1223  
             else
 1224  
             {
 1225  
                 //This code corrects MYFACES-1790, because HtmlColumnTag
 1226  
                 //has as component type javax.faces.Column, so as side
 1227  
                 //effect it not create HtmlColumn, it create UIColumn
 1228  
                 //classes.
 1229  0
                 UIColumn column = (UIColumn) uiComponent;                
 1230  0
                 if (isHeader)
 1231  
                 {
 1232  0
                     String headerClass = (String) column.getAttributes().get("headerClass");
 1233  0
                     if (headerClass != null)
 1234  
                     {
 1235  0
                         styleClass = (String) headerClass;
 1236  
                     }
 1237  0
                 }
 1238  
                 else
 1239  
                 {
 1240  0
                     String footerClass = (String) column.getAttributes().get("footerClass");
 1241  0
                     if (footerClass != null)
 1242  
                     {
 1243  0
                         styleClass = (String) footerClass;
 1244  
                     }
 1245  
                 }
 1246  
             }
 1247  
             
 1248  0
             if (isHeader)
 1249  
             {
 1250  0
                 renderColumnHeaderCell(facesContext, writer, uiComponent,
 1251  
                     ((UIColumn) uiComponent).getHeader(), styleClass, 0);
 1252  
             }
 1253  
             else
 1254  
             {
 1255  0
                 renderColumnFooterCell(facesContext, writer, uiComponent,
 1256  
                     ((UIColumn) uiComponent).getFooter(), styleClass, 0);
 1257  
             }
 1258  
         }
 1259  0
     }
 1260  
 
 1261  
     /**
 1262  
      * Renders the header facet for the given <code>UIColumn</code>.
 1263  
      * @param facesContext the <code>FacesContext</code>.
 1264  
      * @param writer the <code>ResponseWriter</code>.
 1265  
      * @param uiColumn the <code>UIColumn</code>.
 1266  
      * @param headerStyleClass the styleClass of the header facet.
 1267  
      * @param colspan the colspan for the tableData element in which the header facet
 1268  
      * will be wrapped.
 1269  
      * @throws IOException
 1270  
      */
 1271  
     protected void renderColumnHeaderCell(FacesContext facesContext, ResponseWriter writer, UIColumn uiColumn,
 1272  
         String headerStyleClass, int colspan) throws IOException
 1273  
     {
 1274  0
         renderColumnHeaderCell(facesContext, writer, uiColumn, uiColumn.getHeader(), headerStyleClass, colspan);
 1275  0
     }
 1276  
 
 1277  
     /**
 1278  
      * Renders a TH cell within a TR within a THEAD section. If the specified
 1279  
      * UIColumn object does have a header facet, then that facet is rendered
 1280  
      * within the cell, otherwise the cell is left blank (though any specified
 1281  
      * style class is still applied to empty cells).
 1282  
      * 
 1283  
      * @param facesContext the <code>FacesContext</code>.
 1284  
      * @param writer the <code>ResponseWriter</code>.
 1285  
      * @param uiComponent the <code>UIComponent</code> to render the facet for.
 1286  
      * @param facet the <code>UIComponent</code> to render as facet.
 1287  
      * @param headerStyleClass the styleClass of the header facet.
 1288  
      * @param colspan the colspan for the tableData element in which the header facet
 1289  
      * will be wrapped.
 1290  
      * @throws IOException
 1291  
      */
 1292  
     protected void renderColumnHeaderCell(FacesContext facesContext, ResponseWriter writer, UIComponent uiComponent,
 1293  
             UIComponent facet, String headerStyleClass, int colspan) throws IOException
 1294  
     {
 1295  0
         writer.startElement(determineHeaderCellTag(facesContext, uiComponent.getParent()), null); // uiComponent);
 1296  0
         if (colspan > 1)
 1297  
         {
 1298  0
             writer.writeAttribute(HTML.COLSPAN_ATTR, Integer.valueOf(colspan), null);
 1299  
         }
 1300  0
         if (headerStyleClass != null)
 1301  
         {
 1302  0
             writer.writeAttribute(HTML.CLASS_ATTR, headerStyleClass, null);
 1303  
         }
 1304  
 
 1305  0
         writer.writeAttribute(HTML.SCOPE_ATTR, "col", null);
 1306  
 
 1307  0
         if (facet != null)
 1308  
         {
 1309  
             //RendererUtils.renderChild(facesContext, facet);
 1310  0
             facet.encodeAll(facesContext);
 1311  
         }
 1312  0
         writer.endElement(determineHeaderCellTag(facesContext, uiComponent.getParent()));
 1313  0
     }
 1314  
 
 1315  
     protected String determineHeaderCellTag(FacesContext facesContext, UIComponent uiComponent)
 1316  
     {
 1317  0
         return HTML.TH_ELEM;
 1318  
     }
 1319  
 
 1320  
     /**
 1321  
      * Renders the footer facet for the given <code>UIColumn</code>.
 1322  
      * @param facesContext the <code>FacesContext</code>.
 1323  
      * @param writer the <code>ResponseWriter</code>.
 1324  
      * @param uiColumn the <code>UIComponent</code>.
 1325  
      * @param footerStyleClass the styleClass of the footer facet.
 1326  
      * @param colspan the colspan for the tableData element in which the footer facet
 1327  
      * will be wrapped.
 1328  
      * @throws IOException
 1329  
      */
 1330  
     protected void renderColumnFooterCell(FacesContext facesContext, ResponseWriter writer, UIColumn uiColumn,
 1331  
         String footerStyleClass, int colspan) throws IOException
 1332  
     {
 1333  0
       renderColumnFooterCell(facesContext, writer, uiColumn, uiColumn.getFooter(), footerStyleClass, colspan);
 1334  0
     }
 1335  
 
 1336  
     /**
 1337  
      * Renders the footer facet for the given <code>UIColumn</code>.
 1338  
      * @param facesContext the <code>FacesContext</code>.
 1339  
      * @param writer the <code>ResponseWriter</code>.
 1340  
      * @param uiComponent the <code>UIComponent</code> to render the facet for.
 1341  
      * @param facet the <code>UIComponent</code> to render as facet.
 1342  
      * @param footerStyleClass the styleClass of the footer facet.
 1343  
      * @param colspan the colspan for the tableData element in which the footer facet
 1344  
      * will be wrapped.
 1345  
      * @throws IOException
 1346  
      */
 1347  
     protected void renderColumnFooterCell(FacesContext facesContext, ResponseWriter writer, UIComponent uiComponent,
 1348  
         UIComponent facet, String footerStyleClass, int colspan) throws IOException
 1349  
     {
 1350  0
         writer.startElement(HTML.TD_ELEM, null); // uiComponent);
 1351  0
         if (colspan > 1)
 1352  
         {
 1353  0
             writer.writeAttribute(HTML.COLSPAN_ATTR, Integer.valueOf(colspan), null);
 1354  
         }
 1355  0
         if (footerStyleClass != null)
 1356  
         {
 1357  0
             writer.writeAttribute(HTML.CLASS_ATTR, footerStyleClass, null);
 1358  
         }
 1359  0
         if (facet != null)
 1360  
         {
 1361  
             //RendererUtils.renderChild(facesContext, facet);
 1362  0
             facet.encodeAll(facesContext);
 1363  
         }
 1364  0
         writer.endElement(HTML.TD_ELEM);
 1365  0
     }
 1366  
 
 1367  
     /**
 1368  
      * Gets the headerClass attribute of the given <code>UIComponent</code>.
 1369  
      * @param component the <code>UIComponent</code>.
 1370  
      * @return the headerClass attribute of the given <code>UIComponent</code>.
 1371  
      */
 1372  
     protected static String getHeaderClass(UIComponent component)
 1373  
     {
 1374  0
         if (component instanceof HtmlDataTable)
 1375  
         {
 1376  0
             return ((HtmlDataTable) component).getHeaderClass();
 1377  
         }
 1378  
         else
 1379  
         {
 1380  0
             return (String) component.getAttributes().get(
 1381  
                     org.apache.myfaces.shared.renderkit.JSFAttr.HEADER_CLASS_ATTR);
 1382  
         }
 1383  
     }
 1384  
 
 1385  
     /**
 1386  
      * Gets the footerClass attribute of the given <code>UIComponent</code>.
 1387  
      * @param component the <code>UIComponent</code>.
 1388  
      * @return the footerClass attribute of the given <code>UIComponent</code>.
 1389  
      */
 1390  
     protected static String getFooterClass(UIComponent component)
 1391  
     {
 1392  0
         if (component instanceof HtmlDataTable)
 1393  
         {
 1394  0
             return ((HtmlDataTable) component).getFooterClass();
 1395  
         }
 1396  
         else
 1397  
         {
 1398  0
             return (String) component.getAttributes().get(
 1399  
                     org.apache.myfaces.shared.renderkit.JSFAttr.FOOTER_CLASS_ATTR);
 1400  
         }
 1401  
     }
 1402  
 
 1403  
     public void decode(FacesContext context, UIComponent component)
 1404  
     {
 1405  0
         super.decode(context, component);
 1406  
         
 1407  0
         HtmlRendererUtils.decodeClientBehaviors(context, component);
 1408  0
     }
 1409  
 
 1410  
 }