1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.apache.myfaces.renderkit.html;
17
18 import org.apache.myfaces.renderkit.JSFAttr;
19 import org.apache.myfaces.renderkit.RendererUtils;
20 import org.apache.myfaces.util.ArrayUtils;
21 import org.apache.myfaces.util.StringUtils;
22
23 import org.apache.commons.logging.Log;
24 import org.apache.commons.logging.LogFactory;
25
26 import javax.faces.component.UIColumn;
27 import javax.faces.component.UIComponent;
28 import javax.faces.component.UIData;
29 import javax.faces.component.html.HtmlDataTable;
30 import javax.faces.context.FacesContext;
31 import javax.faces.context.ResponseWriter;
32 import java.io.IOException;
33 import java.util.Iterator;
34 import java.util.List;
35 import java.util.NoSuchElementException;
36
37 /***
38 * Common methods for renderers for components that subclass the standard
39 * JSF HtmlDataTable component.
40 *
41 * @author Thomas Spiegl (latest modification by $Author: skitching $)
42 * @version $Revision: 358448 $ $Date: 2005-12-22 02:52:45 +0000 (Thu, 22 Dec 2005) $
43 */
44 public class HtmlTableRendererBase extends HtmlRenderer
45 {
46 /*** Header facet name. */
47 protected static final String HEADER_FACET_NAME = "header";
48
49 /*** Footer facet name. */
50 protected static final String FOOTER_FACET_NAME = "footer";
51
52 /*** The logger. */
53 private static final Log log = LogFactory.getLog(HtmlTableRendererBase.class);
54
55 /***
56 * @see javax.faces.render.Renderer#getRendersChildren()
57 */
58 public boolean getRendersChildren()
59 {
60 return true;
61 }
62
63 /***
64 * Render the necessary bits that come before any actual <i>rows</i> in the table.
65 *
66 * @see javax.faces.render.Renderer#encodeBegin(FacesContext, UIComponent)
67 */
68 public void encodeBegin(FacesContext facesContext, UIComponent uiComponent) throws IOException
69 {
70 RendererUtils.checkParamValidity(facesContext, uiComponent, UIData.class);
71
72 ResponseWriter writer = facesContext.getResponseWriter();
73
74 beforeTable(facesContext, (UIData) uiComponent);
75
76 HtmlRendererUtils.writePrettyLineSeparator(facesContext);
77 writer.startElement(HTML.TABLE_ELEM, uiComponent);
78 HtmlRendererUtils.writeIdIfNecessary(writer, uiComponent, facesContext);
79 HtmlRendererUtils.renderHTMLAttributes(writer, uiComponent, HTML.TABLE_PASSTHROUGH_ATTRIBUTES);
80 }
81
82 /***
83 * Render the TBODY section of the html table. See also method encodeInnerHtml.
84 *
85 * @see javax.faces.render.Renderer#encodeChildren(FacesContext, UIComponent)
86 */
87 public void encodeChildren(FacesContext facesContext, UIComponent component) throws IOException
88 {
89 RendererUtils.checkParamValidity(facesContext, component, UIData.class);
90
91 ResponseWriter writer = facesContext.getResponseWriter();
92
93 beforeBody(facesContext, (UIData) component);
94
95 HtmlRendererUtils.writePrettyLineSeparator(facesContext);
96 writer.startElement(HTML.TBODY_ELEM, component);
97 writer.writeAttribute(HTML.ID_ATTR, component.getClientId(facesContext)+":tbody_element", null);
98
99 encodeInnerHtml(facesContext, component);
100
101 writer.endElement(HTML.TBODY_ELEM);
102
103 afterBody(facesContext, (UIData) component);
104 }
105
106 /***
107 * Renders everything inside the TBODY tag by iterating over the row objects
108 * between offsets first and first+rows and applying the UIColumn components
109 * to those objects.
110 * <p>
111 * This method is separated from the encodeChildren so that it can be overridden by
112 * subclasses. One class that uses this functionality is autoUpdateDataTable.
113 */
114 public void encodeInnerHtml(FacesContext facesContext, UIComponent component)throws IOException{
115
116 UIData uiData = (UIData) component;
117 ResponseWriter writer = facesContext.getResponseWriter();
118
119 String rowClasses;
120 String columnClasses;
121 if (component instanceof HtmlDataTable)
122 {
123 rowClasses = ((HtmlDataTable) component).getRowClasses();
124 columnClasses = ((HtmlDataTable) component).getColumnClasses();
125 }
126 else
127 {
128 rowClasses = (String) component.getAttributes().get(JSFAttr.ROW_CLASSES_ATTR);
129 columnClasses = (String) component.getAttributes().get(JSFAttr.COLUMN_CLASSES_ATTR);
130 }
131 Iterator rowStyleIterator = new StyleIterator(rowClasses);
132 StyleIterator columnStyleIterator = new StyleIterator(columnClasses);
133
134 int first = uiData.getFirst();
135 int rows = uiData.getRows();
136 int rowCount = uiData.getRowCount();
137 if (rows <= 0)
138 {
139 rows = rowCount - first;
140 }
141 int last = first + rows;
142 if (last > rowCount)
143 last = rowCount;
144
145 for (int i = first; i < last; i++)
146 {
147 uiData.setRowIndex(i);
148 if (!uiData.isRowAvailable())
149 {
150 log.error("Row is not available. Rowindex = " + i);
151 return;
152 }
153 columnStyleIterator.reset();
154
155 beforeRow(facesContext, uiData);
156
157 HtmlRendererUtils.writePrettyLineSeparator(facesContext);
158 renderRowStart(facesContext, writer, uiData, rowStyleIterator);
159
160 List children = getChildren(component);
161 for (int j = 0, size = getChildCount(component); j < size; j++)
162 {
163 UIComponent child = (UIComponent) children.get(j);
164 if(child.isRendered())
165 {
166 encodeColumnChild(facesContext, writer, uiData, child, columnStyleIterator);
167 }
168 }
169 renderRowEnd(facesContext, writer, uiData);
170
171 afterRow(facesContext, uiData);
172 }
173 }
174
175 protected void encodeColumnChild(FacesContext facesContext, ResponseWriter writer,
176 UIData uiData, UIComponent component, Iterator columnStyleIterator) throws IOException
177 {
178 if (component instanceof UIColumn)
179 {
180 renderColumnBody(facesContext, writer, uiData, component, columnStyleIterator);
181 }
182 }
183
184 /***
185 * Renders the body of a given <code>UIColumn</code> (everything but
186 * the header and footer facets). This emits a TD cell, whose contents
187 * are the result of calling encodeBegin, encodeChildren and
188 * encodeEnd methods on the component (or its associated renderer).
189 *
190 * @param facesContext the <code>FacesContext</code>.
191 * @param writer the <code>ResponseWriter</code>.
192 * @param uiData the <code>UIData</code> being rendered.
193 * @param component the <code>UIComponent</code> to render.
194 * @param columnStyleIterator the styleClass of the <code>UIColumn</code> or <code>null</code> if
195 * there is none.
196 * @throws IOException if an exception occurs.
197 */
198 protected void renderColumnBody(
199 FacesContext facesContext,
200 ResponseWriter writer,
201 UIData uiData,
202 UIComponent component,
203 Iterator columnStyleIterator) throws IOException
204 {
205 writer.startElement(HTML.TD_ELEM, uiData);
206 if (columnStyleIterator.hasNext())
207 {
208 writer.writeAttribute(HTML.CLASS_ATTR, columnStyleIterator.next(), null);
209 }
210
211 RendererUtils.renderChild(facesContext, component);
212 writer.endElement(HTML.TD_ELEM);
213 }
214
215 /***
216 * Renders the start of a new row of body content.
217 * @param facesContext the <code>FacesContext</code>.
218 * @param writer the <code>ResponseWriter</code>.
219 * @param uiData the <code>UIData</code> being rendered.
220 * @param rowStyleIterator te styleClass of the row or <code>null</code> if there is none.
221 * @throws IOException if an exceptoin occurs.
222 */
223 protected void renderRowStart(
224 FacesContext facesContext,
225 ResponseWriter writer,
226 UIData uiData,
227 Iterator rowStyleIterator) throws IOException
228 {
229 writer.startElement(HTML.TR_ELEM, uiData);
230
231 renderRowStyle(facesContext, writer, uiData, rowStyleIterator);
232
233 Object rowId = uiData.getAttributes().get(JSFAttr.ROW_ID);
234
235 if (rowId != null)
236 {
237 writer.writeAttribute(HTML.ID_ATTR, rowId.toString(), null);
238 }
239 }
240
241 protected void renderRowStyle(FacesContext facesContext, ResponseWriter writer, UIData uiData, Iterator rowStyleIterator) throws IOException
242 {
243 if (rowStyleIterator.hasNext())
244 {
245 writer.writeAttribute(HTML.CLASS_ATTR, rowStyleIterator.next(), null);
246 }
247 }
248
249 /***
250 * Renders the end of a row of body content.
251 * @param facesContext the <code>FacesContext</code>.
252 * @param writer the <code>ResponseWriter</code>.
253 * @param uiData the <code>UIData</code> being rendered.
254 * @throws IOException if an exceptoin occurs.
255 */
256 protected void renderRowEnd(
257 FacesContext facesContext,
258 ResponseWriter writer,
259 UIData uiData) throws IOException
260 {
261 writer.endElement(HTML.TR_ELEM);
262 }
263
264 /***
265 * Perform any operations necessary immediately before the TABLE start tag
266 * is output.
267 *
268 * @param facesContext the <code>FacesContext</code>.
269 * @param uiData the <code>UIData</code> being rendered.
270 */
271 protected void beforeTable(FacesContext facesContext, UIData uiData) throws IOException
272 {
273 }
274
275 /***
276 * Perform any operations necessary after TABLE start tag is output
277 * but before the TBODY start tag.
278 * <p>
279 * This method generates the THEAD/TFOOT sections of a table if there
280 * are any header or footer facets defined on the table or on any child
281 * UIColumn component.
282 *
283 * @param facesContext the <code>FacesContext</code>.
284 * @param uiData the <code>UIData</code> being rendered.
285 */
286 protected void beforeBody(FacesContext facesContext, UIData uiData) throws IOException
287 {
288 ResponseWriter writer = facesContext.getResponseWriter();
289 renderFacet(facesContext, writer, uiData, true);
290 renderFacet(facesContext, writer, uiData, false);
291 }
292
293 /***
294 * Perform any operations necessary immediately before each TR start tag
295 * is output.
296 *
297 * @param facesContext the <code>FacesContext</code>.
298 * @param uiData the <code>UIData</code> being rendered.
299 */
300 protected void beforeRow(FacesContext facesContext, UIData uiData) throws IOException
301 {
302 }
303
304 /***
305 * Perform any operations necessary immediately after each TR end tag
306 * is output.
307 *
308 * @param facesContext the <code>FacesContext</code>.
309 * @param uiData the <code>UIData</code> being rendered.
310 */
311 protected void afterRow(FacesContext facesContext, UIData uiData) throws IOException
312 {
313 }
314
315 /***
316 * Perform any operations necessary immediately after the TBODY end tag
317 * is output.
318 *
319 * @param facesContext the <code>FacesContext</code>.
320 * @param uiData the <code>UIData</code> being rendered.
321 */
322 protected void afterBody(FacesContext facesContext, UIData uiData) throws IOException
323 {
324 }
325
326 /***
327 * Perform any operations necessary immediately after the TABLE end tag
328 * is output.
329 *
330 * @param facesContext the <code>FacesContext</code>.
331 * @param uiData the <code>UIData</code> being rendered.
332 */
333 protected void afterTable(FacesContext facesContext, UIData uiData) throws IOException
334 {
335 }
336
337 /***
338 * @see javax.faces.render.Renderer#encodeEnd(FacesContext, UIComponent)
339 */
340 public void encodeEnd(FacesContext facesContext, UIComponent uiComponent) throws IOException
341 {
342 RendererUtils.checkParamValidity(facesContext, uiComponent, UIData.class);
343
344 ResponseWriter writer = facesContext.getResponseWriter();
345 writer.endElement(HTML.TABLE_ELEM);
346 HtmlRendererUtils.writePrettyLineSeparator(facesContext);
347
348 afterTable(facesContext, (UIData) uiComponent);
349 }
350
351 /***
352 * Renders either the header or the footer facets for the UIData component
353 * and all the child UIColumn components, as a THEAD or TFOOT element
354 * containing TR (row) elements.
355 * <p>
356 * If there is a header or footer attached to the UIData then that is
357 * rendered as a TR element whose COLSPAN is the sum of all rendered
358 * columns in the table. This allows that header/footer to take up the
359 * entire width of the table.
360 * <p>
361 * If any child column has a header or footer then a TR is rendered
362 * with a TH cell for each column child.
363 *
364 * @param facesContext the <code>FacesContext</code>.
365 * @param writer the <code>ResponseWriter</code>.
366 * @param component the UIData component
367 * @param header whether this is the header facet (if not, then the footer facet).
368 * @throws IOException if an exception occurs.
369 */
370 protected void renderFacet(FacesContext facesContext, ResponseWriter writer,
371 UIComponent component, boolean header)
372 throws IOException
373 {
374 int colspan = 0;
375 boolean hasColumnFacet = false;
376 for (Iterator it = getChildren(component).iterator(); it.hasNext();)
377 {
378 UIComponent uiComponent = (UIComponent) it.next();
379 if(uiComponent.isRendered())
380 {
381
382 colspan += determineChildColSpan(uiComponent);
383
384
385
386 if (!hasColumnFacet)
387 {
388 hasColumnFacet = hasFacet(header, uiComponent);
389 }
390 }
391 }
392
393 UIComponent facet = header ? (UIComponent) component.getFacets().get(HEADER_FACET_NAME)
394 : (UIComponent) component.getFacets().get(FOOTER_FACET_NAME);
395 if (facet != null || hasColumnFacet)
396 {
397
398
399 String elemName = header ? HTML.THEAD_ELEM : HTML.TFOOT_ELEM;
400
401 HtmlRendererUtils.writePrettyLineSeparator(facesContext);
402 writer.startElement(elemName, component);
403 if (header)
404 {
405 String headerStyleClass = getHeaderClass(component);
406 if (facet != null)
407 renderTableHeaderRow(facesContext, writer, component, facet, headerStyleClass, colspan);
408 if (hasColumnFacet)
409 renderColumnHeaderRow(facesContext, writer, component, headerStyleClass);
410 }
411 else
412 {
413 String footerStyleClass = getFooterClass(component);
414 if (hasColumnFacet)
415 renderColumnFooterRow(facesContext, writer, component, footerStyleClass);
416 if (facet != null)
417 renderTableFooterRow(facesContext, writer, component, facet, footerStyleClass, colspan);
418 }
419 writer.endElement(elemName);
420 }
421 }
422
423 /***
424 * @param header
425 * @param uiComponent
426 * @return boolean
427 */
428 protected boolean hasFacet(boolean header, UIComponent uiComponent)
429 {
430 if (uiComponent instanceof UIColumn)
431 {
432 UIColumn uiColumn = (UIColumn) uiComponent;
433 return header ? uiColumn.getHeader() != null : uiColumn.getFooter() != null;
434 }
435 return false;
436 }
437
438 /***
439 * Calculate the number of columns the specified child component will span
440 * when rendered.
441 * <p>
442 * Normally, this is a fairly simple calculation: a UIColumn component
443 * is rendered as one column, every other child type is not rendered
444 * (ie spans zero columns). However custom subclasses of this renderer may
445 * override this method to handle cases where a single component renders
446 * as multiple columns.
447 */
448 protected int determineChildColSpan(UIComponent uiComponent)
449 {
450 if (uiComponent instanceof UIColumn)
451 {
452 return 1;
453 }
454 return 0;
455 }
456
457 /***
458 * Renders the header row of the table being rendered.
459 * @param facesContext the <code>FacesContext</code>.
460 * @param writer the <code>ResponseWriter</code>.
461 * @param component the <code>UIComponent</code> for whom a table is being rendered.
462 * @param headerFacet the facet for the header.
463 * @param headerStyleClass the styleClass of the header.
464 * @param colspan the number of columns the header should span. Typically, this is
465 * the number of columns in the table.
466 * @throws IOException if an exception occurs.
467 */
468 protected void renderTableHeaderRow(FacesContext facesContext, ResponseWriter writer, UIComponent component,
469 UIComponent headerFacet, String headerStyleClass, int colspan) throws IOException
470 {
471 renderTableHeaderOrFooterRow(facesContext, writer, component, headerFacet, headerStyleClass, HTML.TH_ELEM,
472 colspan);
473 }
474
475 /***
476 * Renders the footer row of the table being rendered.
477 * @param facesContext the <code>FacesContext</code>.
478 * @param writer the <code>ResponseWriter</code>.
479 * @param component the <code>UIComponent</code> for whom a table is being rendered.
480 * @param footerFacet the facet for the footer.
481 * @param footerStyleClass the styleClass of the footer.
482 * @param colspan the number of columns the header should span. Typically, this is
483 * the number of columns in the table.
484 * @throws IOException if an exception occurs.
485 */
486 protected void renderTableFooterRow(FacesContext facesContext, ResponseWriter writer, UIComponent component,
487 UIComponent footerFacet, String footerStyleClass, int colspan) throws IOException
488 {
489 renderTableHeaderOrFooterRow(facesContext, writer, component, footerFacet, footerStyleClass, HTML.TD_ELEM,
490 colspan);
491 }
492
493 /***
494 * Renders the header row for the columns, which is a separate row from the header row for the
495 * <code>UIData</code> header facet.
496 *
497 * @param facesContext the <code>FacesContext</code>.
498 * @param writer the <code>ResponseWriter</code>.
499 * @param component the UIData component for whom a table is being rendered.
500 * @param headerStyleClass the styleClass of the header
501 * @throws IOException if an exception occurs.
502 */
503 protected void renderColumnHeaderRow(FacesContext facesContext, ResponseWriter writer, UIComponent component,
504 String headerStyleClass) throws IOException
505 {
506 renderColumnHeaderOrFooterRow(facesContext, writer, component, headerStyleClass, true);
507 }
508
509 /***
510 * Renders the footer row for the columns, which is a separate row from the footer row for the
511 * <code>UIData</code> footer facet.
512 * @param facesContext the <code>FacesContext</code>.
513 * @param writer the <code>ResponseWriter</code>.
514 * @param component the <code>UIComponent</code> for whom a table is being rendered.
515 * @param footerStyleClass the styleClass of the footerStyleClass
516 * @throws IOException if an exception occurs.
517 */
518 protected void renderColumnFooterRow(FacesContext facesContext, ResponseWriter writer, UIComponent component,
519 String footerStyleClass) throws IOException
520 {
521 renderColumnHeaderOrFooterRow(facesContext, writer, component, footerStyleClass, false);
522 }
523
524 private void renderTableHeaderOrFooterRow(FacesContext facesContext, ResponseWriter writer, UIComponent component,
525 UIComponent facet, String styleClass, String colElementName, int colspan) throws IOException
526 {
527 HtmlRendererUtils.writePrettyLineSeparator(facesContext);
528 writer.startElement(HTML.TR_ELEM, component);
529 writer.startElement(colElementName, component);
530 if (colElementName.equals(HTML.TH_ELEM))
531 {
532 writer.writeAttribute(HTML.SCOPE_ATTR, HTML.SCOPE_COLGROUP_VALUE, null);
533 }
534 writer.writeAttribute(HTML.COLSPAN_ATTR, new Integer(colspan), null);
535 if (styleClass != null)
536 {
537 writer.writeAttribute(HTML.CLASS_ATTR, styleClass, null);
538 }
539 if (facet != null)
540 {
541 RendererUtils.renderChild(facesContext, facet);
542 }
543 writer.endElement(colElementName);
544 writer.endElement(HTML.TR_ELEM);
545 }
546
547 /***
548 * @param component the UIData component for whom a table is being rendered.
549 */
550 private void renderColumnHeaderOrFooterRow(FacesContext facesContext, ResponseWriter writer,
551 UIComponent component, String styleClass, boolean header) throws IOException
552 {
553 HtmlRendererUtils.writePrettyLineSeparator(facesContext);
554
555 writer.startElement(HTML.TR_ELEM, component);
556 for (Iterator it = getChildren(component).iterator(); it.hasNext();)
557 {
558 UIComponent uiComponent = (UIComponent) it.next();
559 if(uiComponent.isRendered())
560 {
561 renderColumnChildHeaderOrFooterRow(facesContext, writer, uiComponent, styleClass, header);
562 }
563 }
564 writer.endElement(HTML.TR_ELEM);
565 }
566
567 protected void renderColumnChildHeaderOrFooterRow(FacesContext facesContext,
568 ResponseWriter writer, UIComponent uiComponent, String styleClass, boolean header) throws IOException
569 {
570 if (uiComponent instanceof UIColumn)
571 {
572 if (header)
573 {
574 renderColumnHeaderCell(facesContext, writer, uiComponent,
575 ((UIColumn) uiComponent).getHeader(), styleClass, 0);
576 }
577 else
578 {
579 renderColumnFooterCell(facesContext, writer, uiComponent,
580 ((UIColumn) uiComponent).getFooter(), styleClass, 0);
581 }
582 }
583 }
584
585 /***
586 * Renders the header facet for the given <code>UIColumn</code>.
587 * @param facesContext the <code>FacesContext</code>.
588 * @param writer the <code>ResponseWriter</code>.
589 * @param uiColumn the <code>UIColumn</code>.
590 * @param headerStyleClass the styleClass of the header facet.
591 * @param colspan the colspan for the tableData element in which the header facet
592 * will be wrapped.
593 * @throws IOException
594 */
595 protected void renderColumnHeaderCell(FacesContext facesContext, ResponseWriter writer, UIColumn uiColumn,
596 String headerStyleClass, int colspan) throws IOException
597 {
598 renderColumnHeaderCell(facesContext, writer, uiColumn, uiColumn.getHeader(), headerStyleClass, colspan);
599 }
600
601 /***
602 * Renders a TH cell within a TR within a THEAD section. If the specified
603 * UIColumn object does have a header facet, then that facet is rendered
604 * within the cell, otherwise the cell is left blank (though any specified
605 * style class is still applied to empty cells).
606 *
607 * @param facesContext the <code>FacesContext</code>.
608 * @param writer the <code>ResponseWriter</code>.
609 * @param uiComponent the <code>UIComponent</code> to render the facet for.
610 * @param facet the <code>UIComponent</code> to render as facet.
611 * @param headerStyleClass the styleClass of the header facet.
612 * @param colspan the colspan for the tableData element in which the header facet
613 * will be wrapped.
614 * @throws IOException
615 */
616 protected void renderColumnHeaderCell(FacesContext facesContext, ResponseWriter writer, UIComponent uiComponent,
617 UIComponent facet, String headerStyleClass, int colspan) throws IOException
618 {
619 writer.startElement(HTML.TH_ELEM, uiComponent);
620 if (colspan > 1)
621 {
622 writer.writeAttribute(HTML.COLSPAN_ATTR, new Integer(colspan), null);
623 }
624 if (headerStyleClass != null)
625 {
626 writer.writeAttribute(HTML.CLASS_ATTR, headerStyleClass, null);
627 }
628 if (facet != null)
629 {
630 RendererUtils.renderChild(facesContext, facet);
631 }
632 writer.endElement(HTML.TH_ELEM);
633 }
634
635 /***
636 * Renders the footer facet for the given <code>UIColumn</code>.
637 * @param facesContext the <code>FacesContext</code>.
638 * @param writer the <code>ResponseWriter</code>.
639 * @param uiColumn the <code>UIComponent</code>.
640 * @param footerStyleClass the styleClass of the footer facet.
641 * @param colspan the colspan for the tableData element in which the footer facet
642 * will be wrapped.
643 * @throws IOException
644 */
645 protected void renderColumnFooterCell(FacesContext facesContext, ResponseWriter writer, UIColumn uiColumn,
646 String footerStyleClass, int colspan) throws IOException
647 {
648 renderColumnFooterCell(facesContext, writer, uiColumn, uiColumn.getFooter(), footerStyleClass, colspan);
649 }
650
651 /***
652 * Renders the footer facet for the given <code>UIColumn</code>.
653 * @param facesContext the <code>FacesContext</code>.
654 * @param writer the <code>ResponseWriter</code>.
655 * @param uiComponent the <code>UIComponent</code> to render the facet for.
656 * @param facet the <code>UIComponent</code> to render as facet.
657 * @param footerStyleClass the styleClass of the footer facet.
658 * @param colspan the colspan for the tableData element in which the footer facet
659 * will be wrapped.
660 * @throws IOException
661 */
662 protected void renderColumnFooterCell(FacesContext facesContext, ResponseWriter writer, UIComponent uiComponent,
663 UIComponent facet, String footerStyleClass, int colspan) throws IOException
664 {
665 writer.startElement(HTML.TD_ELEM, uiComponent);
666 if (colspan > 1)
667 {
668 writer.writeAttribute(HTML.COLSPAN_ATTR, new Integer(colspan), null);
669 }
670 if (footerStyleClass != null)
671 {
672 writer.writeAttribute(HTML.CLASS_ATTR, footerStyleClass, null);
673 }
674 if (facet != null)
675 {
676 RendererUtils.renderChild(facesContext, facet);
677 }
678 writer.endElement(HTML.TD_ELEM);
679 }
680
681 /***
682 * Gets the headerClass attribute of the given <code>UIComponent</code>.
683 * @param component the <code>UIComponent</code>.
684 * @return the headerClass attribute of the given <code>UIComponent</code>.
685 */
686 protected static String getHeaderClass(UIComponent component)
687 {
688 if (component instanceof HtmlDataTable)
689 {
690 return ((HtmlDataTable) component).getHeaderClass();
691 }
692 else
693 {
694 return (String) component.getAttributes().get(JSFAttr.HEADER_CLASS_ATTR);
695 }
696 }
697
698 /***
699 * Gets the footerClass attribute of the given <code>UIComponent</code>.
700 * @param component the <code>UIComponent</code>.
701 * @return the footerClass attribute of the given <code>UIComponent</code>.
702 */
703 protected static String getFooterClass(UIComponent component)
704 {
705 if (component instanceof HtmlDataTable)
706 {
707 return ((HtmlDataTable) component).getFooterClass();
708 }
709 else
710 {
711 return (String) component.getAttributes().get(JSFAttr.FOOTER_CLASS_ATTR);
712 }
713 }
714
715
716
717
718 private static class StyleIterator implements Iterator
719 {
720
721
722
723 private String[] _style;
724 private int _idx = 0;
725
726
727
728 StyleIterator(String styles)
729 {
730 _style = (styles == null) ? ArrayUtils.EMPTY_STRING_ARRAY : StringUtils.trim(StringUtils
731 .splitShortString(styles, ','));
732 }
733
734 /***
735 * @see java.util.Iterator#hasNext()
736 */
737 public boolean hasNext()
738 {
739 return _style.length > 0;
740 }
741
742 /***
743 * @see java.util.Iterator#next()
744 */
745 public Object next()
746 {
747 if(hasNext())
748 {
749 return _style[_idx++ % _style.length];
750 }
751 throw new NoSuchElementException("no style defined");
752 }
753
754 /***
755 * @see java.util.Iterator#remove()
756 */
757 public void remove()
758 {
759 throw new UnsupportedOperationException("remove is not supported");
760 }
761
762 public void reset()
763 {
764 _idx = 0;
765 }
766 }
767
768 public void decode(FacesContext context, UIComponent component)
769 {
770 super.decode(context, component);
771 }
772
773 }