Coverage Report - org.apache.myfaces.shared_impl.renderkit.html.HtmlTableRendererBase
 
Classes in this File Line Coverage Branch Coverage Complexity
HtmlTableRendererBase
0%
0/273
0%
0/146
2.333
HtmlTableRendererBase$Styles
0%
0/12
0%
0/12
2.333
 
 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_impl.renderkit.html;
 20  
 
 21  
 import org.apache.commons.logging.Log;
 22  
 import org.apache.commons.logging.LogFactory;
 23  
 import org.apache.myfaces.shared_impl.renderkit.JSFAttr;
 24  
 import org.apache.myfaces.shared_impl.renderkit.RendererUtils;
 25  
 import org.apache.myfaces.shared_impl.util.ArrayUtils;
 26  
 import org.apache.myfaces.shared_impl.util.StringUtils;
 27  
 
 28  
 import javax.el.ValueExpression;
 29  
 import javax.faces.component.UIColumn;
 30  
 import javax.faces.component.UIComponent;
 31  
 import javax.faces.component.UIData;
 32  
 import javax.faces.component.html.HtmlColumn;
 33  
 import javax.faces.component.html.HtmlDataTable;
 34  
 import javax.faces.context.FacesContext;
 35  
 import javax.faces.context.ResponseWriter;
 36  
 import java.io.IOException;
 37  
 import java.util.Iterator;
 38  
 import java.util.List;
 39  
 
 40  
 /**
 41  
  * Common methods for renderers for components that subclass the standard
 42  
  * JSF HtmlDataTable component.
 43  
  * 
 44  
  * @author Thomas Spiegl (latest modification by $Author: lu4242 $)
 45  
  * @version $Revision: 779397 $ $Date: 2009-05-27 21:07:38 -0500 (Wed, 27 May 2009) $
 46  
  */
 47  0
 public class HtmlTableRendererBase extends HtmlRenderer
 48  
 {
 49  
     /** Header facet name. */
 50  
     protected static final String HEADER_FACET_NAME = "header";
 51  
 
 52  
     /** Footer facet name. */
 53  
     protected static final String FOOTER_FACET_NAME = "footer";
 54  
 
 55  
     protected static final String CAPTION_FACET_NAME = "caption";
 56  
     
 57  
     /** The logger. */
 58  0
     private static final Log log = LogFactory.getLog(HtmlTableRendererBase.class);
 59  
 
 60  
     /**
 61  
      * @param component dataTable
 62  
      * @return number of layout columns
 63  
      */
 64  
     protected int getNewspaperColumns(UIComponent component) {
 65  0
         return 1;
 66  
     }
 67  
 
 68  
     /**
 69  
      * @param component dataTable
 70  
      * @return component to display between layout columns
 71  
      */
 72  
     protected UIComponent getNewspaperTableSpacer(UIComponent component) {
 73  0
         return null;
 74  
     }
 75  
 
 76  
     /**
 77  
      * @param component dataTable
 78  
      * @return whether dataTable has component to display between layout columns
 79  
      */
 80  
     protected boolean hasNewspaperTableSpacer(UIComponent component) {
 81  0
         return false;
 82  
     }
 83  
 
 84  
     /**
 85  
      * @param component dataTable
 86  
      * @return whether dataTable has newspaper columns layed out horizontally
 87  
      */
 88  
     protected boolean isNewspaperHorizontalOrientation(UIComponent component) {
 89  0
         return false;
 90  
     }
 91  
 
 92  
     /**
 93  
      * @see javax.faces.render.Renderer#getRendersChildren()
 94  
      */
 95  
     public boolean getRendersChildren()
 96  
     {
 97  0
         return true;
 98  
     }
 99  
 
 100  
     /**
 101  
      * Render the necessary bits that come before any actual <i>rows</i> in the table.
 102  
      * 
 103  
      * @see javax.faces.render.Renderer#encodeBegin(FacesContext, UIComponent)
 104  
      */
 105  
     public void encodeBegin(FacesContext facesContext, UIComponent uiComponent) throws IOException
 106  
     {
 107  0
         RendererUtils.checkParamValidity(facesContext, uiComponent, UIData.class);
 108  
 
 109  0
         beforeTable(facesContext, (UIData) uiComponent);
 110  
 
 111  0
         startTable(facesContext, uiComponent);
 112  0
     }
 113  
 
 114  
     /**
 115  
      * actually render the start of the table
 116  
      */
 117  
     protected void startTable(FacesContext facesContext, UIComponent uiComponent) throws IOException
 118  
     {
 119  0
         ResponseWriter writer = facesContext.getResponseWriter();
 120  0
         HtmlRendererUtils.writePrettyLineSeparator(facesContext);
 121  0
         writer.startElement(HTML.TABLE_ELEM, uiComponent);
 122  0
         HtmlRendererUtils.writeIdIfNecessary(writer, uiComponent, facesContext);
 123  0
         HtmlRendererUtils.renderHTMLAttributes(writer, uiComponent, org.apache.myfaces.shared_impl.renderkit.html.HTML.TABLE_PASSTHROUGH_ATTRIBUTES);
 124  0
     }
 125  
 
 126  
     /**
 127  
      * Render the TBODY section of the html table. See also method encodeInnerHtml.
 128  
      * 
 129  
      * @see javax.faces.render.Renderer#encodeChildren(FacesContext, UIComponent)
 130  
      */
 131  
     public void encodeChildren(FacesContext facesContext, UIComponent component) throws IOException
 132  
     {
 133  0
         RendererUtils.checkParamValidity(facesContext, component, UIData.class);
 134  
 
 135  0
         ResponseWriter writer = facesContext.getResponseWriter();
 136  
 
 137  0
         beforeBody(facesContext, (UIData) component);
 138  
 
 139  0
         HtmlRendererUtils.writePrettyLineSeparator(facesContext);
 140  0
         writer.startElement(HTML.TBODY_ELEM, component);
 141  0
         writer.writeAttribute(HTML.ID_ATTR, component.getClientId(facesContext)+":tbody_element", null);
 142  
 
 143  0
         encodeInnerHtml(facesContext, component);
 144  
 
 145  0
         writer.endElement(HTML.TBODY_ELEM);
 146  
 
 147  0
         afterBody(facesContext, (UIData) component);
 148  0
     }
 149  
 
 150  
     /**
 151  
      * Renders the caption facet.
 152  
      * @param facesContext the <code>FacesContext</code>.
 153  
      * @param writer the <code>ResponseWriter</code>.
 154  
      * @param component the parent <code>UIComponent</code> containing the facets.
 155  
      * @throws IOException if an exception occurs.
 156  
      */
 157  
     protected void renderCaptionFacet(FacesContext facesContext, ResponseWriter writer, UIComponent component)
 158  
             throws IOException
 159  
     {
 160  0
         HtmlRendererUtils.renderTableCaption(facesContext, writer, component);
 161  0
     }    
 162  
     
 163  
     /**
 164  
      * Gets styles for the specified component.
 165  
      */
 166  
     protected static Styles getStyles(UIData uiData) {
 167  
         String rowClasses;
 168  
         String columnClasses;
 169  0
         if(uiData instanceof HtmlDataTable) {
 170  0
             rowClasses = ((HtmlDataTable)uiData).getRowClasses();
 171  0
             columnClasses = ((HtmlDataTable)uiData).getColumnClasses();
 172  
         } else {
 173  0
             rowClasses = (String)uiData.getAttributes().get(JSFAttr.ROW_CLASSES_ATTR);
 174  0
             columnClasses = (String)uiData.getAttributes().get(JSFAttr.COLUMN_CLASSES_ATTR);
 175  
         }
 176  0
         return new Styles(rowClasses, columnClasses);
 177  
     }
 178  
 
 179  
     /**
 180  
      * Class manages the styles from String lists.
 181  
      */
 182  0
     protected static class Styles {
 183  
 
 184  
         private String[] _columnStyle;
 185  
         private String[] _rowStyle;
 186  
 
 187  0
         Styles(String rowStyles, String columnStyles) {
 188  0
             _rowStyle = (rowStyles == null)
 189  
                 ? ArrayUtils.EMPTY_STRING_ARRAY
 190  
                 : StringUtils.trim(
 191  
                     StringUtils.splitShortString(rowStyles, ','));
 192  0
             _columnStyle = (columnStyles == null)
 193  
                 ? ArrayUtils.EMPTY_STRING_ARRAY
 194  
                 : StringUtils.trim(
 195  
                     StringUtils.splitShortString(columnStyles, ','));
 196  0
         }
 197  
 
 198  
         public String getRowStyle(int idx) {
 199  0
             if(!hasRowStyle()) {
 200  0
                 return null;
 201  
             }
 202  0
             return _rowStyle[idx % _rowStyle.length];
 203  
         }
 204  
 
 205  
         public String getColumnStyle(int idx) {
 206  0
             if(!hasColumnStyle()) {
 207  0
                 return null;
 208  
             }
 209  0
             return _columnStyle[idx % _columnStyle.length];
 210  
         }
 211  
 
 212  
         public boolean hasRowStyle() {
 213  0
             return _rowStyle.length > 0;
 214  
         }
 215  
 
 216  
         public boolean hasColumnStyle() {
 217  0
             return _columnStyle.length > 0;
 218  
         }
 219  
     }
 220  
 
 221  
     /**
 222  
      * Renders everything inside the TBODY tag by iterating over the row objects
 223  
      * between offsets first and first+rows and applying the UIColumn components
 224  
      * to those objects. 
 225  
      * <p>
 226  
      * This method is separated from the encodeChildren so that it can be overridden by
 227  
      * subclasses. One class that uses this functionality is autoUpdateDataTable.
 228  
      */
 229  
      public void encodeInnerHtml(FacesContext facesContext, UIComponent component)throws IOException{
 230  
 
 231  0
         UIData uiData = (UIData) component;
 232  0
         ResponseWriter writer = facesContext.getResponseWriter();
 233  
 
 234  0
         int rowCount = uiData.getRowCount();
 235  
 
 236  0
         if (rowCount == 0) {
 237  
             //nothing to render, to get valid xhtml we render an empty dummy row
 238  0
             writer.startElement(HTML.TR_ELEM, uiData);
 239  0
             writer.startElement(HTML.TD_ELEM, uiData);
 240  0
             writer.endElement(HTML.TD_ELEM);
 241  0
             writer.endElement(HTML.TR_ELEM);
 242  0
             return;
 243  
         }
 244  
 
 245  
         // begin the table
 246  
         // get the CSS styles
 247  0
         Styles styles = getStyles(uiData);
 248  
 
 249  0
         int first = uiData.getFirst();
 250  0
         int rows = uiData.getRows();
 251  
         int last;
 252  
 
 253  0
         if (rows <= 0)
 254  
         {
 255  0
            last = rowCount;
 256  
         }
 257  
         else
 258  
         {
 259  0
            last = first + rows;
 260  0
            if (last > rowCount)
 261  
            {
 262  0
                last = rowCount;
 263  
            }
 264  
         }
 265  
 
 266  0
         int newspaperColumns = getNewspaperColumns(component);
 267  
         int newspaperRows;
 268  0
         if((last - first) % newspaperColumns == 0)
 269  0
             newspaperRows = (last - first) / newspaperColumns;
 270  0
         else newspaperRows = ((last - first) / newspaperColumns) + 1;
 271  0
         boolean newspaperHorizontalOrientation = isNewspaperHorizontalOrientation(component);
 272  
 
 273  
         // walk through the newspaper rows
 274  0
         for(int nr = 0; nr < newspaperRows; nr++)
 275  
         {
 276  0
             beforeRow(facesContext, uiData);
 277  
 
 278  
             // walk through the newspaper columns
 279  0
             for(int nc = 0; nc < newspaperColumns; nc++) {
 280  
 
 281  
                 // the current row in the 'real' table
 282  
                 int currentRow;
 283  0
                 if (newspaperHorizontalOrientation)
 284  0
                     currentRow = nr * newspaperColumns + nc + first;
 285  
                 else
 286  0
                     currentRow = nc * newspaperRows + nr + first;
 287  
                 
 288  
                 // if this row is not to be rendered
 289  0
                 if(currentRow >= last) continue;
 290  
 
 291  
                 // bail if any row does not exist
 292  0
                 uiData.setRowIndex(currentRow);
 293  0
                 if(!uiData.isRowAvailable()) {
 294  0
                     log.error("Row is not available. Rowindex = " + currentRow);
 295  0
                     break;
 296  
                 }
 297  
     
 298  0
                 if (nc == 0) {
 299  
                     // first column in table, start new row
 300  0
                     beforeRow(facesContext, uiData);
 301  
 
 302  0
                     HtmlRendererUtils.writePrettyLineSeparator(facesContext);
 303  0
                     renderRowStart(facesContext, writer, uiData, styles, nr);
 304  
                 }
 305  
 
 306  0
                 List children = getChildren(component);
 307  0
                 for (int j = 0, size = getChildCount(component); j < size; j++)
 308  
                 {
 309  0
                     UIComponent child = (UIComponent) children.get(j);
 310  0
                     if (child.isRendered())
 311  
                     {
 312  0
                         boolean columnRendering = child instanceof UIColumn;
 313  
                         
 314  0
                         if (columnRendering)
 315  0
                             beforeColumn(facesContext, uiData, j);
 316  
                            
 317  0
                         encodeColumnChild(facesContext, writer, uiData, child, styles, nc * uiData.getChildCount() + j);                    
 318  
                        
 319  0
                         if (columnRendering)
 320  0
                             afterColumn(facesContext, uiData, j);
 321  
                     }
 322  
                 }
 323  
 
 324  0
                 if (hasNewspaperTableSpacer(uiData))
 325  
                 {
 326  
                     // draw the spacer facet
 327  0
                     if(nc < newspaperColumns - 1) renderSpacerCell(facesContext, writer, uiData);
 328  
                 }
 329  
             }
 330  0
             renderRowEnd(facesContext, writer, uiData);
 331  
 
 332  0
             afterRow(facesContext, uiData);
 333  
         }
 334  0
     }
 335  
 
 336  
     protected void encodeColumnChild(FacesContext facesContext, ResponseWriter writer,
 337  
         UIData uiData, UIComponent component, Styles styles, int columnStyleIndex) throws IOException
 338  
     {
 339  0
         if (component instanceof UIColumn)
 340  
         {            
 341  0
             renderColumnBody(facesContext, writer, uiData, component, styles, columnStyleIndex);            
 342  
         }
 343  0
     }
 344  
 
 345  
     /**
 346  
      * Renders the body of a given <code>UIColumn</code> (everything but
 347  
      * the header and footer facets). This emits a TD cell, whose contents
 348  
      * are the result of calling encodeBegin, encodeChildren and
 349  
      * encodeEnd methods on the component (or its associated renderer).
 350  
      * 
 351  
      * @param facesContext the <code>FacesContext</code>.
 352  
      * @param writer the <code>ResponseWriter</code>.
 353  
      * @param uiData the <code>UIData</code> being rendered.
 354  
      * @param component the <code>UIComponent</code> to render.
 355  
      * @throws IOException if an exception occurs.
 356  
      */
 357  
     protected void renderColumnBody(
 358  
             FacesContext facesContext,
 359  
             ResponseWriter writer,
 360  
             UIData uiData,
 361  
             UIComponent component,
 362  
             Styles styles, int columnStyleIndex) throws IOException
 363  
     {
 364  0
         writer.startElement(HTML.TD_ELEM, uiData);
 365  0
         if (styles.hasColumnStyle())
 366  
         {
 367  0
             writer.writeAttribute(HTML.CLASS_ATTR, styles.getColumnStyle(columnStyleIndex), null);
 368  
         }
 369  
     
 370  0
         RendererUtils.renderChild(facesContext, component);
 371  0
         writer.endElement(HTML.TD_ELEM);
 372  0
     }
 373  
 
 374  
     /**
 375  
      * Renders the start of a new row of body content.
 376  
      * @param facesContext the <code>FacesContext</code>.
 377  
      * @param writer the <code>ResponseWriter</code>.
 378  
      * @param uiData the <code>UIData</code> being rendered.
 379  
      * @throws IOException if an exceptoin occurs.
 380  
      */
 381  
     protected void renderRowStart(
 382  
         FacesContext facesContext,
 383  
         ResponseWriter writer,
 384  
         UIData uiData,
 385  
         Styles styles, int rowStyleIndex) throws IOException
 386  
     {
 387  0
         writer.startElement(HTML.TR_ELEM, uiData);
 388  
         
 389  0
         renderRowStyle(facesContext, writer, uiData, styles, rowStyleIndex);
 390  
         
 391  0
         Object rowId = uiData.getAttributes().get(org.apache.myfaces.shared_impl.renderkit.JSFAttr.ROW_ID);
 392  
 
 393  0
         if (rowId != null)
 394  
         {
 395  0
             writer.writeAttribute(HTML.ID_ATTR, rowId.toString(), null);
 396  
         }
 397  0
     }
 398  
 
 399  
     protected void renderRowStyle(FacesContext facesContext, ResponseWriter writer, UIData uiData, Styles styles, int rowStyleIndex) throws IOException
 400  
     {
 401  0
         if(styles.hasRowStyle()) {
 402  0
             String rowStyle = styles.getRowStyle(rowStyleIndex);
 403  0
             writer.writeAttribute(HTML.CLASS_ATTR, rowStyle, null);
 404  
         }
 405  0
     }
 406  
 
 407  
     /**
 408  
      * Renders the end of a row of body content.
 409  
      * @param facesContext the <code>FacesContext</code>.
 410  
      * @param writer the <code>ResponseWriter</code>.
 411  
      * @param uiData the <code>UIData</code> being rendered.
 412  
      * @throws IOException if an exceptoin occurs.
 413  
      */
 414  
     protected void renderRowEnd(
 415  
         FacesContext facesContext,
 416  
         ResponseWriter writer,
 417  
         UIData uiData) throws IOException
 418  
     {
 419  0
         writer.endElement(HTML.TR_ELEM);
 420  0
     }
 421  
 
 422  
     /**
 423  
      * Perform any operations necessary immediately before the TABLE start tag
 424  
      * is output.
 425  
      *
 426  
      * @param facesContext the <code>FacesContext</code>.
 427  
      * @param uiData the <code>UIData</code> being rendered.
 428  
      */
 429  
     protected void beforeTable(FacesContext facesContext, UIData uiData) throws IOException
 430  
     {
 431  0
     }
 432  
 
 433  
     /**
 434  
      * Perform any operations necessary after TABLE start tag is output
 435  
      * but before the TBODY start tag.
 436  
      * <p>
 437  
      * This method generates the THEAD/TFOOT sections of a table if there
 438  
      * are any header or footer facets defined on the table or on any child
 439  
      * UIColumn component.
 440  
      *
 441  
      * @param facesContext the <code>FacesContext</code>.
 442  
      * @param uiData the <code>UIData</code> being rendered.
 443  
      */
 444  
     protected void beforeBody(FacesContext facesContext, UIData uiData) throws IOException
 445  
     {
 446  0
         ResponseWriter writer = facesContext.getResponseWriter();
 447  
 
 448  0
         renderCaptionFacet(facesContext, writer, uiData);
 449  0
         renderFacet(facesContext, writer, uiData, true);
 450  0
         renderFacet(facesContext, writer, uiData, false);
 451  0
     }
 452  
 
 453  
     /**
 454  
      * Perform any operations necessary immediately before each TR start tag
 455  
      * is output.
 456  
      *
 457  
      * @param facesContext the <code>FacesContext</code>.
 458  
      * @param uiData the <code>UIData</code> being rendered.
 459  
      */
 460  
     protected void beforeRow(FacesContext facesContext, UIData uiData) throws IOException
 461  
     {
 462  0
     }
 463  
 
 464  
     /**
 465  
      * Perform any operations necessary immediately after each TR end tag
 466  
      * is output.
 467  
      *
 468  
      * @param facesContext the <code>FacesContext</code>.
 469  
      * @param uiData the <code>UIData</code> being rendered.
 470  
      */
 471  
     protected void afterRow(FacesContext facesContext, UIData uiData) throws IOException
 472  
     {
 473  0
     }
 474  
     /**
 475  
      * Perform any operations necessary immediately before each column child is rendered
 476  
      *
 477  
      * @param facesContext the <code>FacesContext</code>.
 478  
      * @param uiData the <code>UIData</code> being rendered.
 479  
      * @param columnIndex the index of the currenly rendered column
 480  
      */
 481  
     protected void beforeColumn(FacesContext facesContext, UIData uiData, int columnIndex) throws IOException
 482  
     {        
 483  0
     }
 484  
     /**
 485  
      * Perform any operations necessary immediately after each column child is rendered
 486  
      *
 487  
      * @param facesContext the <code>FacesContext</code>.
 488  
      * @param uiData the <code>UIData</code> being rendered.
 489  
      * @param columnIndex the index of the currenly rendered column
 490  
      */
 491  
     protected void afterColumn(FacesContext facesContext, UIData uiData, int columnIndex) throws IOException
 492  
     {        
 493  0
     }
 494  
     /**
 495  
      *Perform any operations necessary immediately before each column child's header or footer is rendered
 496  
      *
 497  
      * @param facesContext the <code>FacesContext</code>.
 498  
      * @param uiData the <code>UIData</code> being rendered.
 499  
      * @param header true if the header of the column child is rendered
 500  
      * @param columnIndex the index of the currenly rendered column
 501  
      */
 502  
     protected void beforeColumnHeaderOrFooter(FacesContext facesContext, UIData uiData, boolean header, int columnIndex) throws IOException
 503  
     {         
 504  0
     }
 505  
     /**
 506  
      * Perform any operations necessary immediately after each column child's header of footer is rendered
 507  
      *
 508  
      * @param facesContext the <code>FacesContext</code>.
 509  
      * @param uiData the <code>UIData</code> being rendered.
 510  
      * @param header true if the header of the column child is rendered
 511  
      * @param columnIndex the index of the currenly rendered column
 512  
      */
 513  
     protected void afterColumnHeaderOrFooter(FacesContext facesContext, UIData uiData, boolean header, int columnIndex) throws IOException
 514  
     {         
 515  0
     }
 516  
 
 517  
     /**
 518  
      * Perform any operations necessary in the TBODY start tag.
 519  
      *
 520  
      * @param facesContext the <code>FacesContext</code>.
 521  
      * @param uiData the <code>UIData</code> being rendered.
 522  
      */
 523  
     protected void inBodyStart(FacesContext facesContext, UIData uiData) throws IOException
 524  
     {
 525  0
     }
 526  
 
 527  
     /**
 528  
      * Perform any operations necessary immediately after the TBODY end tag
 529  
      * is output.
 530  
      *
 531  
      * @param facesContext the <code>FacesContext</code>.
 532  
      * @param uiData the <code>UIData</code> being rendered.
 533  
      */
 534  
     protected void afterBody(FacesContext facesContext, UIData uiData) throws IOException
 535  
     {
 536  0
     }
 537  
 
 538  
     /**
 539  
      * Perform any operations necessary immediately after the TABLE end tag
 540  
      * is output.
 541  
      *
 542  
      * @param facesContext the <code>FacesContext</code>.
 543  
      * @param uiData the <code>UIData</code> being rendered.
 544  
      */
 545  
     protected void afterTable(FacesContext facesContext, UIData uiData) throws IOException
 546  
     {
 547  0
     }
 548  
 
 549  
     /**
 550  
      * @see javax.faces.render.Renderer#encodeEnd(FacesContext, UIComponent)
 551  
      */
 552  
     public void encodeEnd(FacesContext facesContext, UIComponent uiComponent) throws IOException
 553  
     {
 554  0
         RendererUtils.checkParamValidity(facesContext, uiComponent, UIData.class);
 555  
 
 556  0
         endTable(facesContext, uiComponent);
 557  
 
 558  0
         afterTable(facesContext, (UIData) uiComponent);
 559  0
     }
 560  
 
 561  
     /**
 562  
      * actually render the end of the table
 563  
      */
 564  
     protected void endTable(FacesContext facesContext, UIComponent uiComponent) throws IOException
 565  
     {
 566  0
         ResponseWriter writer = facesContext.getResponseWriter();
 567  0
         writer.endElement(HTML.TABLE_ELEM);
 568  0
         HtmlRendererUtils.writePrettyLineSeparator(facesContext);
 569  0
     }
 570  
 
 571  
     /**
 572  
      * Renders either the header or the footer facets for the UIData component
 573  
      * and all the child UIColumn components, as a THEAD or TFOOT element
 574  
      * containing TR (row) elements.
 575  
      * <p>
 576  
      * If there is a header or footer attached to the UIData then that is
 577  
      * rendered as a TR element whose COLSPAN is the sum of all rendered
 578  
      * columns in the table. This allows that header/footer to take up the
 579  
      * entire width of the table.
 580  
      * <p>
 581  
      * If any child column has a header or footer then a TR is rendered
 582  
      * with a TH cell for each column child. 
 583  
      * 
 584  
      * @param facesContext the <code>FacesContext</code>.
 585  
      * @param writer the <code>ResponseWriter</code>.
 586  
      * @param component the UIData component
 587  
      * @param header whether this is the header facet (if not, then the footer facet).
 588  
      * @throws IOException if an exception occurs.
 589  
      */
 590  
     protected void renderFacet(FacesContext facesContext, ResponseWriter writer,
 591  
             UIComponent component, boolean header)
 592  
             throws IOException
 593  
     {
 594  0
         int colspan = 0;
 595  0
         boolean hasColumnFacet = false;
 596  0
         for (Iterator it = getChildren(component).iterator(); it.hasNext();)
 597  
         {
 598  0
             UIComponent uiComponent = (UIComponent) it.next();
 599  0
             if(uiComponent.isRendered())
 600  
             {
 601  
                 // a UIColumn has a span of 1, anything else has a span of 0
 602  0
                 colspan += determineChildColSpan(uiComponent);
 603  
 
 604  
                 // hasColumnFacet is true if *any* child column has a facet of
 605  
                 // the specified type.
 606  0
                 if (!hasColumnFacet)
 607  
                 {
 608  0
                      hasColumnFacet = hasFacet(header, uiComponent);
 609  
                 }
 610  
             }
 611  0
         }
 612  
 
 613  0
         UIComponent facet = header ? (UIComponent) component.getFacets().get(HEADER_FACET_NAME)
 614  
                 : (UIComponent) component.getFacets().get(FOOTER_FACET_NAME);
 615  0
         if (facet != null || hasColumnFacet)
 616  
         {
 617  
             // Header or Footer present on either the UIData or a column, so we
 618  
             // definitely need to render the THEAD or TFOOT section.
 619  0
             String elemName = determineHeaderFooterTag(facesContext, component, header);
 620  
 
 621  0
             HtmlRendererUtils.writePrettyLineSeparator(facesContext);
 622  0
             if (elemName != null)
 623  
             {
 624  0
                 writer.startElement(elemName, component);
 625  
             }
 626  0
             if (header)
 627  
             {
 628  0
                 String headerStyleClass = getHeaderClass(component);
 629  0
                 if (facet != null)
 630  0
                     renderTableHeaderRow(facesContext, writer, component, facet, headerStyleClass, colspan);
 631  0
                 if (hasColumnFacet)
 632  0
                     renderColumnHeaderRow(facesContext, writer, component, headerStyleClass);
 633  0
             }
 634  
             else
 635  
             {
 636  0
                 String footerStyleClass = getFooterClass(component);
 637  0
                 if (hasColumnFacet)
 638  0
                     renderColumnFooterRow(facesContext, writer, component, footerStyleClass);
 639  0
                 if (facet != null)
 640  0
                     renderTableFooterRow(facesContext, writer, component, facet, footerStyleClass, colspan);
 641  
             }
 642  0
             if (elemName != null)
 643  
             {
 644  0
                 writer.endElement(elemName);
 645  
             }
 646  
         }
 647  0
     }
 648  
 
 649  
     protected String determineHeaderFooterTag(FacesContext facesContext, UIComponent component, boolean header)
 650  
     {
 651  0
         return header ? HTML.THEAD_ELEM : HTML.TFOOT_ELEM;
 652  
     }
 653  
 
 654  
     /**
 655  
      * @param header
 656  
      * @param uiComponent
 657  
      * @return boolean
 658  
      */
 659  
     protected boolean hasFacet(boolean header, UIComponent uiComponent)
 660  
     {
 661  0
         if (uiComponent instanceof UIColumn)
 662  
         {
 663  0
             UIColumn uiColumn = (UIColumn) uiComponent;
 664  0
             return header ? uiColumn.getHeader() != null : uiColumn.getFooter() != null;
 665  
         }
 666  0
         return false;
 667  
     }
 668  
 
 669  
     /**
 670  
      * Calculate the number of columns the specified child component will span
 671  
      * when rendered.
 672  
      * <p>
 673  
      * Normally, this is a fairly simple calculation: a UIColumn component
 674  
      * is rendered as one column, every other child type is not rendered
 675  
      * (ie spans zero columns). However custom subclasses of this renderer may
 676  
      * override this method to handle cases where a single component renders
 677  
      * as multiple columns. 
 678  
      */
 679  
     protected int determineChildColSpan(UIComponent uiComponent)
 680  
     {
 681  0
         if (uiComponent instanceof UIColumn)
 682  
         {
 683  0
             return 1;
 684  
         }
 685  0
         return 0;
 686  
     }
 687  
 
 688  
     /**
 689  
      * Renders the header row of the table being rendered.
 690  
      * @param facesContext the <code>FacesContext</code>.
 691  
      * @param writer the <code>ResponseWriter</code>.
 692  
      * @param component the <code>UIComponent</code> for whom a table is being rendered.
 693  
      * @param headerFacet the facet for the header.
 694  
      * @param headerStyleClass the styleClass of the header.
 695  
      * @param colspan the number of columns the header should span.  Typically, this is
 696  
      * the number of columns in the table.
 697  
      * @throws IOException if an exception occurs.
 698  
      */
 699  
     protected void renderTableHeaderRow(FacesContext facesContext, ResponseWriter writer, UIComponent component,
 700  
             UIComponent headerFacet, String headerStyleClass, int colspan) throws IOException
 701  
     {
 702  0
         renderTableHeaderOrFooterRow(facesContext, writer, component, headerFacet, headerStyleClass, determineHeaderCellTag(facesContext, component),
 703  
                 colspan, true);
 704  0
     }
 705  
 
 706  
     /**
 707  
      * Renders the footer row of the table being rendered.
 708  
      * @param facesContext the <code>FacesContext</code>.
 709  
      * @param writer the <code>ResponseWriter</code>.
 710  
      * @param component the <code>UIComponent</code> for whom a table is being rendered.
 711  
      * @param footerFacet the facet for the footer.
 712  
      * @param footerStyleClass the styleClass of the footer.
 713  
      * @param colspan the number of columns the header should span.  Typically, this is
 714  
      * the number of columns in the table.
 715  
      * @throws IOException if an exception occurs.
 716  
      */
 717  
     protected void renderTableFooterRow(FacesContext facesContext, ResponseWriter writer, UIComponent component,
 718  
             UIComponent footerFacet, String footerStyleClass, int colspan) throws IOException
 719  
     {
 720  0
         renderTableHeaderOrFooterRow(facesContext, writer, component, footerFacet, footerStyleClass, HTML.TD_ELEM,
 721  
                 colspan, false);
 722  0
     }
 723  
 
 724  
     /**
 725  
      * Renders the header row for the columns, which is a separate row from the header row for the
 726  
      * <code>UIData</code> header facet.
 727  
      * 
 728  
      * @param facesContext the <code>FacesContext</code>.
 729  
      * @param writer the <code>ResponseWriter</code>.
 730  
      * @param component the UIData component for whom a table is being rendered.
 731  
      * @param headerStyleClass the styleClass of the header
 732  
      * @throws IOException if an exception occurs.
 733  
      */
 734  
     protected void renderColumnHeaderRow(FacesContext facesContext, ResponseWriter writer, UIComponent component,
 735  
             String headerStyleClass) throws IOException
 736  
     {
 737  0
         renderColumnHeaderOrFooterRow(facesContext, writer, component, headerStyleClass, true);
 738  0
     }
 739  
 
 740  
     /**
 741  
      * Renders the footer row for the columns, which is a separate row from the footer row for the
 742  
      * <code>UIData</code> footer facet.
 743  
      * @param facesContext the <code>FacesContext</code>.
 744  
      * @param writer the <code>ResponseWriter</code>.
 745  
      * @param component the <code>UIComponent</code> for whom a table is being rendered.
 746  
      * @param footerStyleClass the styleClass of the footerStyleClass
 747  
      * @throws IOException if an exception occurs.
 748  
      */
 749  
     protected void renderColumnFooterRow(FacesContext facesContext, ResponseWriter writer, UIComponent component,
 750  
             String footerStyleClass) throws IOException
 751  
     {
 752  0
         renderColumnHeaderOrFooterRow(facesContext, writer, component, footerStyleClass, false);
 753  0
     }
 754  
 
 755  
     protected void renderTableHeaderOrFooterRow(FacesContext facesContext, ResponseWriter writer, UIComponent component,
 756  
             UIComponent facet, String styleClass, String colElementName, int colspan, boolean isHeader) throws IOException
 757  
     {
 758  0
         HtmlRendererUtils.writePrettyLineSeparator(facesContext);
 759  0
         writer.startElement(HTML.TR_ELEM, component);
 760  0
         writer.startElement(colElementName, component);
 761  0
         if (colElementName.equals(determineHeaderCellTag(facesContext, component)) && isHeader)
 762  
         {
 763  0
             writer.writeAttribute(HTML.SCOPE_ATTR, HTML.SCOPE_COLGROUP_VALUE, null);
 764  
         }
 765  
 
 766  
         // span all the table's columns
 767  0
         int newsPaperColumns = getNewspaperColumns(component);
 768  0
         int totalColumns = colspan * newsPaperColumns;
 769  0
         if(hasNewspaperTableSpacer(component))
 770  
         {
 771  0
             totalColumns = totalColumns + newsPaperColumns - 1;
 772  
         }
 773  0
         writer.writeAttribute(HTML.COLSPAN_ATTR, new Integer(totalColumns), null);
 774  0
         if (styleClass != null)
 775  
         {
 776  0
             writer.writeAttribute(HTML.CLASS_ATTR, styleClass, null);
 777  
         }
 778  0
         if (facet != null)
 779  
         {
 780  0
             RendererUtils.renderChild(facesContext, facet);
 781  
         }
 782  0
         writer.endElement(colElementName);
 783  0
         writer.endElement(HTML.TR_ELEM);
 784  0
     }
 785  
 
 786  
     /**
 787  
      * @param component the UIData component for whom a table is being rendered.
 788  
      */
 789  
     private void renderColumnHeaderOrFooterRow(FacesContext facesContext, ResponseWriter writer,
 790  
             UIComponent component, String styleClass, boolean header) throws IOException
 791  
     {
 792  0
         HtmlRendererUtils.writePrettyLineSeparator(facesContext);
 793  
 
 794  0
         writer.startElement(HTML.TR_ELEM, component);
 795  0
         int columnIndex = 0;
 796  0
         int newspaperColumns = getNewspaperColumns(component);
 797  0
         for(int nc = 0; nc < newspaperColumns; nc++)
 798  
         {
 799  0
             for (Iterator it = getChildren(component).iterator(); it.hasNext();)
 800  
             {
 801  0
                 UIComponent uiComponent = (UIComponent) it.next();
 802  0
                 if (uiComponent.isRendered())
 803  
                 {
 804  0
                     if (component instanceof UIData && uiComponent instanceof UIColumn)
 805  0
                         beforeColumnHeaderOrFooter(facesContext, (UIData)component, header, columnIndex);
 806  
                 
 807  0
                     renderColumnChildHeaderOrFooterRow(facesContext, writer, uiComponent, styleClass, header);
 808  
                     
 809  0
                     if (component instanceof UIData && uiComponent instanceof UIColumn)
 810  0
                         afterColumnHeaderOrFooter(facesContext, (UIData)component, header, columnIndex);
 811  
                 }
 812  0
                 columnIndex += 1;
 813  0
             }
 814  
 
 815  0
             if (hasNewspaperTableSpacer(component))
 816  
             {
 817  
                 // draw the spacer facet
 818  0
                 if(nc < newspaperColumns - 1) renderSpacerCell(facesContext, writer, component);
 819  
             }
 820  
         }
 821  0
         writer.endElement(HTML.TR_ELEM);
 822  0
     }
 823  
 
 824  
       /**
 825  
       * Renders a spacer between adjacent newspaper columns.
 826  
       */
 827  
     protected void renderSpacerCell(FacesContext facesContext, ResponseWriter writer, UIComponent component) throws IOException {
 828  0
         UIComponent spacer = getNewspaperTableSpacer(component);
 829  0
         if(spacer == null) return;
 830  
          
 831  0
          writer.startElement(HTML.TD_ELEM, component);
 832  0
          RendererUtils.renderChild(facesContext, spacer);
 833  0
          writer.endElement(HTML.TD_ELEM);
 834  0
      }
 835  
 
 836  
     protected void renderColumnChildHeaderOrFooterRow(FacesContext facesContext,
 837  
         ResponseWriter writer, UIComponent uiComponent, String styleClass, boolean isHeader) throws IOException
 838  
     {
 839  0
         if (uiComponent instanceof UIColumn)
 840  
         {
 841  
             // allow column to override style class, new in JSF 1.2
 842  0
             if (uiComponent instanceof HtmlColumn) {
 843  0
                 HtmlColumn column = (HtmlColumn)uiComponent;
 844  0
                 if (isHeader && column.getHeaderClass()!=null)
 845  0
                     styleClass = column.getHeaderClass();
 846  0
                 else if (!isHeader && column.getFooterClass()!=null)
 847  0
                     styleClass = column.getFooterClass();
 848  0
             }else{
 849  
                 //This code corrects MYFACES-1790, because HtmlColumnTag
 850  
                 //has as component type javax.faces.Column, so as side
 851  
                 //effect it not create HtmlColumn, it create UIColumn
 852  
                 //classes.
 853  0
                 UIColumn column = (UIColumn) uiComponent;                
 854  0
                 if (isHeader){
 855  0
                     String headerClass = (String) column.getAttributes().get("headerClass");
 856  0
                     if (headerClass != null){
 857  0
                         styleClass = (String) headerClass;
 858  
                     }
 859  0
                 }else{
 860  0
                     String footerClass = (String) column.getAttributes().get("footerClass");
 861  0
                     if (footerClass != null){
 862  0
                         styleClass = (String) footerClass;
 863  
                     }
 864  
                 }
 865  
             }
 866  
             
 867  0
             if (isHeader)
 868  
             {
 869  0
                 renderColumnHeaderCell(facesContext, writer, uiComponent,
 870  
                     ((UIColumn) uiComponent).getHeader(), styleClass, 0);
 871  
             }
 872  
             else
 873  
             {
 874  0
                 renderColumnFooterCell(facesContext, writer, uiComponent,
 875  
                     ((UIColumn) uiComponent).getFooter(), styleClass, 0);
 876  
             }
 877  
         }
 878  0
     }
 879  
 
 880  
     /**
 881  
      * Renders the header facet for the given <code>UIColumn</code>.
 882  
      * @param facesContext the <code>FacesContext</code>.
 883  
      * @param writer the <code>ResponseWriter</code>.
 884  
      * @param uiColumn the <code>UIColumn</code>.
 885  
      * @param headerStyleClass the styleClass of the header facet.
 886  
      * @param colspan the colspan for the tableData element in which the header facet
 887  
      * will be wrapped.
 888  
      * @throws IOException
 889  
      */
 890  
     protected void renderColumnHeaderCell(FacesContext facesContext, ResponseWriter writer, UIColumn uiColumn,
 891  
         String headerStyleClass, int colspan) throws IOException
 892  
     {
 893  0
         renderColumnHeaderCell(facesContext, writer, uiColumn, uiColumn.getHeader(), headerStyleClass, colspan);
 894  0
     }
 895  
 
 896  
     /**
 897  
      * Renders a TH cell within a TR within a THEAD section. If the specified
 898  
      * UIColumn object does have a header facet, then that facet is rendered
 899  
      * within the cell, otherwise the cell is left blank (though any specified
 900  
      * style class is still applied to empty cells).
 901  
      * 
 902  
      * @param facesContext the <code>FacesContext</code>.
 903  
      * @param writer the <code>ResponseWriter</code>.
 904  
      * @param uiComponent the <code>UIComponent</code> to render the facet for.
 905  
      * @param facet the <code>UIComponent</code> to render as facet.
 906  
      * @param headerStyleClass the styleClass of the header facet.
 907  
      * @param colspan the colspan for the tableData element in which the header facet
 908  
      * will be wrapped.
 909  
      * @throws IOException
 910  
      */
 911  
     protected void renderColumnHeaderCell(FacesContext facesContext, ResponseWriter writer, UIComponent uiComponent,
 912  
             UIComponent facet, String headerStyleClass, int colspan) throws IOException
 913  
     {
 914  0
         writer.startElement(determineHeaderCellTag(facesContext, uiComponent.getParent()), uiComponent);
 915  0
         if (colspan > 1)
 916  
         {
 917  0
             writer.writeAttribute(HTML.COLSPAN_ATTR, new Integer(colspan), null);
 918  
         }
 919  0
         if (headerStyleClass != null)
 920  
         {
 921  0
             writer.writeAttribute(HTML.CLASS_ATTR, headerStyleClass, null);
 922  
         }
 923  
 
 924  0
         writer.writeAttribute(HTML.SCOPE_ATTR, "col", null);
 925  
 
 926  0
         if (facet != null)
 927  
         {
 928  0
             RendererUtils.renderChild(facesContext, facet);
 929  
         }
 930  0
         writer.endElement(determineHeaderCellTag(facesContext, uiComponent.getParent()));
 931  0
     }
 932  
 
 933  
     protected String determineHeaderCellTag(FacesContext facesContext, UIComponent uiComponent)
 934  
     {
 935  0
         return HTML.TH_ELEM;
 936  
     }
 937  
 
 938  
     /**
 939  
      * Renders the footer facet for the given <code>UIColumn</code>.
 940  
      * @param facesContext the <code>FacesContext</code>.
 941  
      * @param writer the <code>ResponseWriter</code>.
 942  
      * @param uiColumn the <code>UIComponent</code>.
 943  
      * @param footerStyleClass the styleClass of the footer facet.
 944  
      * @param colspan the colspan for the tableData element in which the footer facet
 945  
      * will be wrapped.
 946  
      * @throws IOException
 947  
      */
 948  
     protected void renderColumnFooterCell(FacesContext facesContext, ResponseWriter writer, UIColumn uiColumn,
 949  
         String footerStyleClass, int colspan) throws IOException
 950  
     {
 951  0
       renderColumnFooterCell(facesContext, writer, uiColumn, uiColumn.getFooter(), footerStyleClass, colspan);
 952  0
     }
 953  
 
 954  
     /**
 955  
      * Renders the footer facet for the given <code>UIColumn</code>.
 956  
      * @param facesContext the <code>FacesContext</code>.
 957  
      * @param writer the <code>ResponseWriter</code>.
 958  
      * @param uiComponent the <code>UIComponent</code> to render the facet for.
 959  
      * @param facet the <code>UIComponent</code> to render as facet.
 960  
      * @param footerStyleClass the styleClass of the footer facet.
 961  
      * @param colspan the colspan for the tableData element in which the footer facet
 962  
      * will be wrapped.
 963  
      * @throws IOException
 964  
      */
 965  
     protected void renderColumnFooterCell(FacesContext facesContext, ResponseWriter writer, UIComponent uiComponent,
 966  
         UIComponent facet, String footerStyleClass, int colspan) throws IOException
 967  
     {
 968  0
         writer.startElement(HTML.TD_ELEM, uiComponent);
 969  0
         if (colspan > 1)
 970  
         {
 971  0
             writer.writeAttribute(HTML.COLSPAN_ATTR, new Integer(colspan), null);
 972  
         }
 973  0
         if (footerStyleClass != null)
 974  
         {
 975  0
             writer.writeAttribute(HTML.CLASS_ATTR, footerStyleClass, null);
 976  
         }
 977  0
         if (facet != null)
 978  
         {
 979  0
             RendererUtils.renderChild(facesContext, facet);
 980  
         }
 981  0
         writer.endElement(HTML.TD_ELEM);
 982  0
     }
 983  
 
 984  
     /**
 985  
      * Gets the headerClass attribute of the given <code>UIComponent</code>.
 986  
      * @param component the <code>UIComponent</code>.
 987  
      * @return the headerClass attribute of the given <code>UIComponent</code>.
 988  
      */
 989  
     protected static String getHeaderClass(UIComponent component)
 990  
     {
 991  0
         if (component instanceof HtmlDataTable)
 992  
         {
 993  0
             return ((HtmlDataTable) component).getHeaderClass();
 994  
         }
 995  
         else
 996  
         {
 997  0
             return (String) component.getAttributes().get(org.apache.myfaces.shared_impl.renderkit.JSFAttr.HEADER_CLASS_ATTR);
 998  
         }
 999  
     }
 1000  
 
 1001  
     /**
 1002  
      * Gets the footerClass attribute of the given <code>UIComponent</code>.
 1003  
      * @param component the <code>UIComponent</code>.
 1004  
      * @return the footerClass attribute of the given <code>UIComponent</code>.
 1005  
      */
 1006  
     protected static String getFooterClass(UIComponent component)
 1007  
     {
 1008  0
         if (component instanceof HtmlDataTable)
 1009  
         {
 1010  0
             return ((HtmlDataTable) component).getFooterClass();
 1011  
         }
 1012  
         else
 1013  
         {
 1014  0
             return (String) component.getAttributes().get(org.apache.myfaces.shared_impl.renderkit.JSFAttr.FOOTER_CLASS_ATTR);
 1015  
         }
 1016  
     }
 1017  
 
 1018  
     public void decode(FacesContext context, UIComponent component)
 1019  
     {
 1020  0
         super.decode(context, component);
 1021  0
     }
 1022  
 
 1023  
 }