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