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
20 package org.apache.myfaces.renderkit.html.ext;
21
22 import java.io.IOException;
23 import java.util.Iterator;
24 import java.util.List;
25 import java.util.Map;
26
27 import javax.faces.component.UIComponent;
28 import javax.faces.component.UIData;
29 import javax.faces.context.FacesContext;
30 import javax.faces.context.ResponseWriter;
31
32 import org.apache.commons.logging.Log;
33 import org.apache.commons.logging.LogFactory;
34 import org.apache.myfaces.component.html.ext.HtmlDataTable;
35 import org.apache.myfaces.component.NewspaperTable;
36 import org.apache.myfaces.custom.column.HtmlColumn;
37 import org.apache.myfaces.custom.column.HtmlSimpleColumn;
38 import org.apache.myfaces.custom.crosstable.UIColumns;
39 import org.apache.myfaces.renderkit.html.util.ColumnInfo;
40 import org.apache.myfaces.renderkit.html.util.RowInfo;
41 import org.apache.myfaces.renderkit.html.util.TableContext;
42 //import org.apache.myfaces.shared_tomahawk.renderkit.html.HtmlTableRendererBase.Styles;
43 import org.apache.myfaces.shared_tomahawk.renderkit.JSFAttr;
44 import org.apache.myfaces.shared_tomahawk.renderkit.RendererUtils;
45 import org.apache.myfaces.shared_tomahawk.renderkit.html.HTML;
46 import org.apache.myfaces.shared_tomahawk.renderkit.html.HtmlRendererUtils;
47 import org.apache.myfaces.shared_tomahawk.renderkit.html.HtmlTableRendererBase;
48 import org.apache.myfaces.shared_tomahawk.util.ArrayUtils;
49
50 import javax.faces.component.ValueHolder;
51 import javax.faces.convert.Converter;
52 import java.util;
53
54 /**
55 * Renderer for the Tomahawk extended HtmlDataTable component.
56 *
57 * @author Manfred Geiler (latest modification by $Author: paulsp $)
58 * @version $Revision: 491565 $ $Date: 2007-01-01 13:54:00 +0100 (Mo, 01 Jän 2007) $
59 */
60 public class HtmlTableRenderer extends HtmlTableRendererBase
61 {
62 private static final Log log = LogFactory.getLog(HtmlTableRenderer.class);
63
64 /** DetailStamp facet name. */
65 public static final String DETAIL_STAMP_FACET_NAME = "detailStamp";
66 private static final String BODY_STYLE_CLASS = "bodyStyleClass";
67 private static final String BODY_STYLE = "bodyStyle";
68
69 /**
70 * @param component dataTable
71 * @return number of layout columns
72 */
73 protected int getNewspaperColumns(UIComponent component) {
74 if (component instanceof NewspaperTable)
75 {
76 // the number of slices to break the table up into */
77 NewspaperTable newspaperTable = (NewspaperTable)component;
78 return newspaperTable.getNewspaperColumns();
79 }
80 return super.getNewspaperColumns(component);
81 }
82
83 /**
84 * @param component dataTable
85 * @return component to display between layout columns
86 */
87 protected UIComponent getNewspaperTableSpacer(UIComponent component) {
88 if (component instanceof NewspaperTable)
89 {
90 // the number of slices to break the table up into */
91 NewspaperTable newspaperTable = (NewspaperTable)component;
92 return newspaperTable.getSpacer();
93 }
94 return super.getNewspaperTableSpacer(component);
95 }
96
97 /**
98 * @param component dataTable
99 * @return whether dataTable has component to display between layout columns
100 */
101 protected boolean hasNewspaperTableSpacer(UIComponent component) {
102 if (null != getNewspaperTableSpacer(component))
103 {
104 return true;
105 }
106 return super.hasNewspaperTableSpacer(component);
107 }
108
109 /**
110 * @param component dataTable
111 * @return if the orientation of the has newspaper columns is horizontal
112 */
113 protected boolean isNewspaperHorizontalOrientation(UIComponent component) {
114 if (component instanceof NewspaperTable)
115 {
116 // get the value of the newspaperOrientation attribute, any value besides horizontal
117 // means vertical, the default
118 NewspaperTable newspaperTable = (NewspaperTable)component;
119 return NewspaperTable.NEWSPAPER_HORIZONTAL_ORIENTATION.equals(newspaperTable.getNewspaperOrientation());
120 }
121 return super.isNewspaperHorizontalOrientation(component);
122 }
123
124 protected void afterRow(FacesContext facesContext, UIData uiData) throws IOException {
125 super.afterRow(facesContext, uiData);
126
127 renderDetailRow(facesContext, uiData);
128 }
129
130 /**
131 *
132 * @param facesContext
133 * @param uiData
134 * @throws IOException
135 */
136 private void renderDetailRow(FacesContext facesContext, UIData uiData) throws IOException {
137 UIComponent detailStampFacet = uiData.getFacet(DETAIL_STAMP_FACET_NAME);
138
139 if(uiData instanceof HtmlDataTable ){
140 HtmlDataTable htmlDataTable = (HtmlDataTable)uiData;
141
142 if(htmlDataTable.isCurrentDetailExpanded()){
143 ResponseWriter writer = facesContext.getResponseWriter();
144 writer.startElement(HTML.TR_ELEM,uiData);
145 writer.startElement(HTML.TD_ELEM,uiData);
146 writer.writeAttribute(HTML.COLSPAN_ATTR,new Integer(uiData.getChildren().size()) ,null);
147
148 if(detailStampFacet!=null){
149 RendererUtils.renderChild(facesContext, detailStampFacet);
150 }
151
152 writer.endElement(HTML.TD_ELEM);
153 writer.endElement(HTML.TR_ELEM);
154 }
155 }
156 }
157
158 /**
159 * @see org.apache.myfaces.shared_tomahawk.renderkit.html.HtmlTableRendererBase#encodeBegin(javax.faces.context.FacesContext, javax.faces.component.UIComponent)
160 */
161 public void encodeBegin(FacesContext facesContext, UIComponent uiComponent) throws IOException
162 {
163 if (uiComponent instanceof HtmlDataTable)
164 {
165 HtmlDataTable htmlDataTable = (HtmlDataTable) uiComponent;
166 if (htmlDataTable.isRenderedIfEmpty() || htmlDataTable.getRowCount() > 0)
167 {
168 super.encodeBegin(facesContext, uiComponent);
169 }
170 }
171 else
172 {
173 super.encodeBegin(facesContext, uiComponent);
174 }
175 }
176
177 /**
178 * @see org.apache.myfaces.shared_tomahawk.renderkit.html.HtmlTableRendererBase#encodeChildren(javax.faces.context.FacesContext, javax.faces.component.UIComponent)
179 */
180 public void encodeChildren(FacesContext facesContext, UIComponent component) throws IOException
181 {
182 if (component instanceof HtmlDataTable)
183 {
184 HtmlDataTable htmlDataTable = (HtmlDataTable) component;
185 if (htmlDataTable.isRenderedIfEmpty() || htmlDataTable.getRowCount() > 0)
186 {
187 super.encodeChildren(facesContext, component);
188 }
189 }
190 else
191 {
192 super.encodeChildren(facesContext, component);
193 }
194 }
195
196 private boolean isGroupedTable(UIData uiData)
197 {
198 if(uiData instanceof HtmlDataTable)
199 {
200 List children = getChildren(uiData);
201 for (int j = 0, size = getChildCount(uiData); j < size; j++)
202 {
203 UIComponent child = (UIComponent) children.get(j);
204 if(child instanceof HtmlSimpleColumn)
205 {
206 HtmlSimpleColumn column = (HtmlSimpleColumn) child;
207 if(column.isGroupBy())return true;
208 }
209 }
210 }
211
212 return false; //To change body of created methods use File | Settings | File Templates.
213 }
214
215 protected void beforeBody(FacesContext facesContext, UIData uiData) throws IOException
216 {
217 if(isGroupedTable(uiData))
218 {
219 createColumnInfos((HtmlDataTable) uiData, facesContext);
220 }
221 super.beforeBody(facesContext,uiData);
222 }
223
224 private void createColumnInfos(HtmlDataTable htmlDataTable, FacesContext facesContext)
225 throws IOException
226 {
227 int first = htmlDataTable.getFirst();
228 int rows = htmlDataTable.getRows();
229 int last;
230 int currentRowSpan=-1;
231 int currentRowInfoIndex=-1;
232
233 TableContext tableContext=htmlDataTable.getTableContext();
234 RowInfo rowInfo=null;
235 ColumnInfo columnInfo=null;
236 HtmlSimpleColumn currentColumn=null;
237 Map groupHashTable = new HashMap();
238
239 if (rows <= 0)
240 {
241 last = htmlDataTable.getRowCount();
242 }
243 else
244 {
245 last = first + rows;
246 }
247
248
249 //Loop over the Children Columns to find the Columns with groupBy Attribute true
250 List children = getChildren(htmlDataTable);
251 int nChildren = getChildCount(htmlDataTable);
252
253 for (int j = 0, size = nChildren; j < size; j++)
254 {
255 UIComponent child = (UIComponent) children.get(j);
256 if(child instanceof HtmlSimpleColumn)
257 {
258 currentColumn = (HtmlSimpleColumn) child;
259 if(currentColumn.isGroupBy())
260 {
261 groupHashTable.put(new Integer(j),"");
262 }
263 }
264 }
265
266 boolean groupEndReached = false;
267
268 for (int rowIndex = first; last==-1 || rowIndex < last; rowIndex++)
269 {
270 htmlDataTable.setRowIndex(rowIndex);
271 rowInfo = new RowInfo();
272 //scrolled past the last row
273 if (!htmlDataTable.isRowAvailable())
274 break;
275
276 Set groupIndexList = groupHashTable.keySet();
277 StringBuffer currentColumnContent = null;
278 for(Iterator it = groupIndexList.iterator(); it.hasNext(); )
279 {
280 currentColumnContent = new StringBuffer();
281 Integer currentIndex=(Integer) it.next();
282 currentColumn = (HtmlSimpleColumn) children.get(currentIndex.intValue());
283 List currentColumnChildren = currentColumn.getChildren();
284 for (int j = 0, size = currentColumnChildren.size(); j < size; j++)
285 {
286 UIComponent currentColumnChild = (UIComponent) currentColumnChildren.get(j);
287 if (currentColumnChild.isRendered() && currentColumnChild instanceof ValueHolder)
288 {
289 Object value = ((ValueHolder) currentColumnChild).getValue();
290 if (value != null) {
291 Converter converter =
292 HtmlRendererUtils.findUIOutputConverterFailSafe(facesContext, currentColumnChild);
293 currentColumnContent.append(
294 RendererUtils.getConvertedStringValue(facesContext, currentColumnChild,
295 converter, value)); // TODO converter
296 }
297 }
298 }
299 if (currentColumnContent.toString().compareTo(
300 (groupHashTable.get(currentIndex)).toString())!=0 &&
301 currentRowInfoIndex > -1)
302 {
303 groupEndReached = true;
304 groupHashTable.put(currentIndex,currentColumnContent);
305 }
306 else if(currentRowInfoIndex == -1)
307 {
308 groupHashTable.put(currentIndex,currentColumnContent);
309 }
310 }
311 currentRowSpan++;
312
313
314 for (int j = 0, size = nChildren; j < size; j++)
315 {
316 columnInfo = new ColumnInfo();
317 if(groupHashTable.containsKey(new Integer(j))) // Column is groupBy
318 {
319 if(currentRowSpan > 0)
320 {
321 if(groupEndReached)
322 {
323 ((ColumnInfo)
324 ((RowInfo)
325 tableContext.getRowInfos().get(currentRowInfoIndex-currentRowSpan+1)).
326 getColumnInfos().get(j)).
327 setRowSpan(currentRowSpan);
328 columnInfo.setStyle(htmlDataTable.getRowGroupStyle());
329 columnInfo.setStyleClass(htmlDataTable.getRowGroupStyleClass());
330 }
331 else
332 {
333 columnInfo.setRendered(false);
334 }
335 }
336 else
337 {
338 columnInfo.setStyle(htmlDataTable.getRowGroupStyle());
339 columnInfo.setStyleClass(htmlDataTable.getRowGroupStyleClass());
340 }
341
342 }
343 else // Column is not group by
344 {
345 if(groupEndReached)
346 {
347 ((ColumnInfo)
348 ((RowInfo)
349 tableContext.getRowInfos().get(currentRowInfoIndex)).
350 getColumnInfos().get(j)).
351 setStyle(htmlDataTable.getRowGroupStyle());
352 ((ColumnInfo)
353 ((RowInfo)
354 tableContext.getRowInfos().get(currentRowInfoIndex)).
355 getColumnInfos().get(j)).
356 setStyleClass(htmlDataTable.getRowGroupStyleClass());
357 }
358 }
359 rowInfo.getColumnInfos().add(columnInfo);
360 }
361 if(groupEndReached)
362 {
363 currentRowSpan=0;
364 groupEndReached = false;
365 }
366 tableContext.getRowInfos().add(rowInfo);
367 currentRowInfoIndex++;
368 }
369 for (int j = 0, size = nChildren; j < size; j++)
370 {
371 if(groupHashTable.containsKey(new Integer(j))) // Column is groupBy
372 {
373 ((ColumnInfo)
374 ((RowInfo)
375 tableContext.getRowInfos().get(currentRowInfoIndex-currentRowSpan)).
376 getColumnInfos().get(j)).
377 setRowSpan(currentRowSpan+1);
378 }
379 else // Column is not group by
380 {
381 ((ColumnInfo)
382 ((RowInfo)
383 tableContext.getRowInfos().get(currentRowInfoIndex)).
384 getColumnInfos().get(j)).
385 setStyle(htmlDataTable.getRowGroupStyle());
386 ((ColumnInfo)
387 ((RowInfo)
388 tableContext.getRowInfos().get(currentRowInfoIndex)).
389 getColumnInfos().get(j)).
390 setStyleClass(htmlDataTable.getRowGroupStyleClass());
391 }
392 }
393
394 htmlDataTable.setRowIndex(-1);
395 }
396
397
398 /**
399 * @see org.apache.myfaces.shared_tomahawk.renderkit.html.HtmlTableRendererBase#encodeEnd(javax.faces.context.FacesContext, javax.faces.component.UIComponent)
400 */
401 public void encodeEnd(FacesContext facesContext, UIComponent uiComponent) throws IOException
402 {
403 if (uiComponent instanceof HtmlDataTable)
404 {
405 HtmlDataTable htmlDataTable = (HtmlDataTable) uiComponent;
406 if (htmlDataTable.isRenderedIfEmpty() || htmlDataTable.getRowCount() > 0)
407 {
408 super.encodeEnd(facesContext, uiComponent);
409 }
410 }
411 else
412 {
413 super.encodeEnd(facesContext, uiComponent);
414 }
415 }
416
417 protected void renderRowStart(FacesContext facesContext,
418 ResponseWriter writer, UIData uiData, Styles styles, int rowStyleIndex)
419 throws IOException
420 {
421 super.renderRowStart(facesContext, writer, uiData, styles, rowStyleIndex);
422
423 // get event handlers from component
424 HtmlDataTable table = (HtmlDataTable) uiData;
425
426 renderRowAttribute(writer, HTML.ONCLICK_ATTR, table.getRowOnClick());
427 renderRowAttribute(writer, HTML.ONDBLCLICK_ATTR, table.getRowOnDblClick());
428 renderRowAttribute(writer, HTML.ONKEYDOWN_ATTR, table.getRowOnKeyDown());
429 renderRowAttribute(writer, HTML.ONKEYPRESS_ATTR, table.getRowOnKeyPress());
430 renderRowAttribute(writer, HTML.ONKEYUP_ATTR, table.getRowOnKeyUp());
431 renderRowAttribute(writer, HTML.ONMOUSEDOWN_ATTR, table.getRowOnMouseDown());
432 renderRowAttribute(writer, HTML.ONMOUSEMOVE_ATTR, table.getRowOnMouseMove());
433 renderRowAttribute(writer, HTML.ONMOUSEOUT_ATTR, table.getRowOnMouseOut());
434 renderRowAttribute(writer, HTML.ONMOUSEOVER_ATTR, table.getRowOnMouseOver());
435 renderRowAttribute(writer, HTML.ONMOUSEUP_ATTR, table.getRowOnMouseUp());
436 }
437
438 /**
439 * @see org.apache.myfaces.shared_tomahawk.renderkit.html.HtmlTableRendererBase#renderRowStyle(javax.faces.context.FacesContext, javax.faces.context.ResponseWriter, javax.faces.component.UIData, java.util.Iterator)
440 */
441 protected void renderRowStyle(FacesContext facesContext, ResponseWriter writer, UIData uiData, Styles styles, int rowStyleIndex) throws IOException
442 {
443 String rowStyleClass;
444 String rowStyle;
445 if (uiData instanceof HtmlDataTable)
446 {
447 HtmlDataTable datatable = (HtmlDataTable) uiData;
448 rowStyleClass = datatable.getRowStyleClass();
449 rowStyle = datatable.getRowStyle();
450 }
451 else
452 {
453 rowStyleClass = (String) uiData.getAttributes().get(JSFAttr.ROW_STYLECLASS_ATTR);
454 rowStyle = (String) uiData.getAttributes().get(JSFAttr.ROW_STYLE_ATTR);
455 }
456 if(rowStyleClass == null)
457 {
458 super.renderRowStyle(facesContext, writer, uiData, styles, rowStyleIndex);
459 }
460 else
461 {
462 writer.writeAttribute(HTML.CLASS_ATTR, rowStyleClass, null);
463 }
464 if(rowStyle != null)
465 {
466 writer.writeAttribute(HTML.STYLE_ATTR, rowStyle, null);
467 }
468 }
469
470 protected void renderRowAttribute(ResponseWriter writer,
471 String htmlAttribute, Object value) throws IOException
472 {
473 if (value != null)
474 {
475 writer.writeAttribute(htmlAttribute, value, null);
476 }
477 }
478
479 /**
480 * Render the specified column object using the current row data.
481 * <p>
482 * When the component is a UIColumn object, the inherited method is
483 * invoked to render a single table cell.
484 * <p>
485 * In addition to the inherited functionality, support is implemented
486 * here for UIColumns children. When a UIColumns child is encountered:
487 * <pre>
488 * For each dynamic column in that UIColumns child:
489 * * Select the column (which sets variable named by the var attribute
490 * to refer to the current column object)
491 * * Call this.renderColumnBody passing the UIColumns object.
492 * </pre>
493 * The renderColumnBody method eventually:
494 * <ul>
495 * <li>emits TD
496 * <li>calls encodeBegin on the UIColumns (which does nothing)
497 * <li>calls rendering methods on all children of the UIColumns
498 * <li>calls encodeEnd on the UIColumns (which does nothing)
499 * <li> emits /TD
500 * </ul>
501 * If the children of the UIColumns access the variable named by the var
502 * attribute on the UIColumns object, then they end up rendering content
503 * that is extracted from the current column object.
504 *
505 * @see org.apache.myfaces.shared_tomahawk.renderkit.html.HtmlTableRendererBase#encodeColumnChild(javax.faces.context.FacesContext, javax.faces.context.ResponseWriter, javax.faces.component.UIData, javax.faces.component.UIComponent, java.util.Iterator)
506 */
507 protected void encodeColumnChild(FacesContext facesContext,
508 ResponseWriter writer, UIData uiData,
509 UIComponent component, Styles styles, int columnStyleIndex)
510 throws IOException
511 {
512 super.encodeColumnChild(facesContext, writer, uiData, component,
513 styles, columnStyleIndex);
514 if (component instanceof UIColumns)
515 {
516 UIColumns columns = (UIColumns) component;
517 for (int k = 0, colSize = columns.getRowCount(); k < colSize; k++)
518 {
519 columns.setRowIndex(k);
520 renderColumnBody(facesContext, writer, uiData, component,
521 styles, columnStyleIndex);
522 }
523 columns.setRowIndex(-1);
524 }
525 }
526
527 /**
528 * @see org.apache.myfaces.shared_tomahawk.renderkit.html.HtmlTableRendererBase#renderColumnBody(javax.faces.context.FacesContext, javax.faces.context.ResponseWriter, javax.faces.component.UIData, javax.faces.component.UIComponent, java.util.Iterator)
529 */
530 protected void renderColumnBody(FacesContext facesContext,
531 ResponseWriter writer, UIData uiData,
532 UIComponent component, Styles styles, int columnStyleIndex)
533 throws IOException
534 {
535 if (isGroupedTable(uiData)){
536
537 HtmlDataTable htmlDataTable = (HtmlDataTable) uiData;
538 List tableChildren = htmlDataTable.getChildren();
539
540 int first = htmlDataTable.getFirst();
541 int rowInfoIndex= htmlDataTable.getRowIndex()-first;
542 int columnInfoIndex = tableChildren.indexOf(component);
543
544 RowInfo rowInfo = (RowInfo) htmlDataTable.getTableContext().getRowInfos().get(rowInfoIndex);
545 ColumnInfo columnInfo= (ColumnInfo) rowInfo.getColumnInfos().get(columnInfoIndex);
546
547 if(!columnInfo.isRendered()) return;
548
549 if (component instanceof HtmlColumn && amISpannedOver(null, component))
550 return;
551 writer.startElement(HTML.TD_ELEM, uiData);
552 String styleClass = ((HtmlColumn) component).getStyleClass();
553 if(columnInfo.getStyleClass()!= null)
554 {
555 styleClass = columnInfo.getStyleClass();
556 }
557
558 if(styles.hasColumnStyle())
559 {
560 if (styleClass == null)
561 {
562 styleClass = styles.getColumnStyle(columnStyleIndex);
563 }
564 }
565 if (styleClass != null)
566 {
567 writer.writeAttribute(HTML.CLASS_ATTR, styleClass, null);
568 }
569
570 if (columnInfo.getStyle() != null)
571 {
572 writer.writeAttribute(HTML.STYLE_ATTR, columnInfo.getStyle(), null);
573 }
574
575 if (columnInfo.getRowSpan() > 1)
576 {
577 writer.writeAttribute("rowspan", new Integer(columnInfo.getRowSpan()).toString(), null);
578 if (columnInfo.getStyle() == null)
579 {
580 writer.writeAttribute(HTML.STYLE_ATTR, "vertical-align:top", null);
581 }
582 }
583
584 renderHtmlColumnAttributes(writer, component, null);
585
586 RendererUtils.renderChild(facesContext, component);
587 writer.endElement(HTML.TD_ELEM);
588 }
589 else if (component instanceof HtmlColumn)
590 {
591 if (amISpannedOver(null, component))
592 return;
593 writer.startElement(HTML.TD_ELEM, uiData);
594 String styleClass = ((HtmlColumn) component).getStyleClass();
595 if(styles.hasColumnStyle())
596 {
597 if (styleClass == null)
598 {
599 styleClass = styles.getColumnStyle(columnStyleIndex);
600 }
601 }
602 if (styleClass != null)
603 {
604 writer.writeAttribute(HTML.CLASS_ATTR, styleClass, null);
605 }
606 renderHtmlColumnAttributes(writer, component, null);
607
608 RendererUtils.renderChild(facesContext, component);
609 writer.endElement(HTML.TD_ELEM);
610 }
611 else
612 {
613 super.renderColumnBody(facesContext, writer, uiData, component,
614 styles, columnStyleIndex);
615 }
616 }
617
618 /**
619 * Render the header or footer of the specified column object.
620 * <p>
621 * When the component is a UIColumn object, the inherited method is
622 * invoked to render a single header cell.
623 * <p>
624 * In addition to the inherited functionality, support is implemented
625 * here for UIColumns children. When a UIColumns child is encountered:
626 * <pre>
627 * For each dynamic column in that UIColumns child:
628 * * Select the column (which sets variable named by the var attribute
629 * to refer to the current column object)
630 * * Call this.renderColumnHeaderCell or this.renderColumnFooterCell
631 * passing the header or footer facet of the UIColumns object.
632 * </pre>
633 * If the facet of the UIColumns accesses the variable named by the var
634 * attribute on the UIColumns object, then it ends up rendering content
635 * that is extracted from the current column object.
636 *
637 * @see org.apache.myfaces.shared_tomahawk.renderkit.html.HtmlTableRendererBase#renderColumnChildHeaderOrFooterRow(javax.faces.context.FacesContext, javax.faces.context.ResponseWriter, javax.faces.component.UIComponent, java.lang.String, boolean)
638 */
639 protected void renderColumnChildHeaderOrFooterRow(
640 FacesContext facesContext, ResponseWriter writer,
641 UIComponent uiComponent, String styleClass, boolean header)
642 throws IOException
643 {
644 super.renderColumnChildHeaderOrFooterRow(facesContext, writer,
645 uiComponent, styleClass, header);
646 if (uiComponent instanceof UIColumns)
647 {
648 UIColumns columns = (UIColumns) uiComponent;
649 for (int i = 0, size = columns.getRowCount(); i < size; i++)
650 {
651 columns.setRowIndex(i);
652 if (header)
653 {
654 renderColumnHeaderCell(facesContext, writer, columns,
655 columns.getHeader(), styleClass, 0);
656 }
657 else
658 {
659 renderColumnFooterCell(facesContext, writer, columns,
660 columns.getFooter(), styleClass, 0);
661 }
662 }
663 columns.setRowIndex(-1);
664 }
665 }
666
667 /**
668 * @see org.apache.myfaces.shared_tomahawk.renderkit.html.HtmlTableRendererBase#renderColumnHeaderCell(javax.faces.context.FacesContext, javax.faces.context.ResponseWriter, javax.faces.component.UIComponent, javax.faces.component.UIComponent, java.lang.String, int)
669 */
670 protected void renderColumnHeaderCell(FacesContext facesContext,
671 ResponseWriter writer, UIComponent uiComponent,
672 UIComponent facet, String headerStyleClass, int colspan)
673 throws IOException
674 {
675 if (uiComponent instanceof HtmlColumn)
676 {
677 if (amISpannedOver("header", uiComponent))
678 return;
679 writer.startElement(HTML.TH_ELEM, uiComponent);
680 if (colspan > 1)
681 {
682 writer.writeAttribute(HTML.COLSPAN_ATTR, new Integer(colspan),
683 null);
684 }
685 String styleClass = ((HtmlColumn) uiComponent)
686 .getHeaderstyleClass();
687 if (styleClass == null)
688 {
689 styleClass = headerStyleClass;
690 }
691 if (styleClass != null)
692 {
693 writer.writeAttribute(HTML.CLASS_ATTR, styleClass, null);
694 }
695 renderHtmlColumnAttributes(writer, uiComponent, "header");
696 if (facet != null)
697 {
698 RendererUtils.renderChild(facesContext, facet);
699 }
700 writer.endElement(HTML.TH_ELEM);
701 }
702 else
703 {
704 super.renderColumnHeaderCell(facesContext, writer, uiComponent,
705 facet, headerStyleClass, colspan);
706 }
707 }
708
709 /**
710 * @see org.apache.myfaces.shared_tomahawk.renderkit.html.HtmlTableRendererBase#renderColumnFooterCell(javax.faces.context.FacesContext, javax.faces.context.ResponseWriter, javax.faces.component.UIComponent, javax.faces.component.UIComponent, java.lang.String, int)
711 */
712 protected void renderColumnFooterCell(FacesContext facesContext,
713 ResponseWriter writer, UIComponent uiComponent,
714 UIComponent facet, String footerStyleClass, int colspan)
715 throws IOException
716 {
717 if (uiComponent instanceof HtmlColumn)
718 {
719 if (amISpannedOver("footer", uiComponent))
720 return;
721 writer.startElement(HTML.TD_ELEM, uiComponent);
722 if (colspan > 1)
723 {
724 writer.writeAttribute(HTML.COLSPAN_ATTR, new Integer(colspan),
725 null);
726 }
727 String styleClass = ((HtmlColumn) uiComponent)
728 .getFooterstyleClass();
729 if (styleClass == null)
730 {
731 styleClass = footerStyleClass;
732 }
733 if (styleClass != null)
734 {
735 writer.writeAttribute(HTML.CLASS_ATTR, styleClass, null);
736 }
737 renderHtmlColumnAttributes(writer, uiComponent, "footer");
738 if (facet != null)
739 {
740 RendererUtils.renderChild(facesContext, facet);
741 }
742 writer.endElement(HTML.TD_ELEM);
743 }
744 else
745 {
746 super.renderColumnFooterCell(facesContext, writer, uiComponent,
747 facet, footerStyleClass, colspan);
748 }
749 }
750
751 protected void renderHtmlColumnAttributes(ResponseWriter writer,
752 UIComponent uiComponent, String prefix) throws IOException
753 {
754 String[] attrs = (String[]) ArrayUtils.concat(HTML.COMMON_PASSTROUGH_ATTRIBUTES_WITHOUT_STYLE, new String[] {HTML.COLSPAN_ATTR});
755 for (int i = 0, size = attrs.length; i < size; i++)
756 {
757 String attributeName = attrs[i];
758 String compAttrName = prefix != null ? prefix + attributeName : attributeName;
759 HtmlRendererUtils.renderHTMLAttribute(writer, uiComponent,
760 compAttrName, attributeName);
761 }
762 String compAttrName = prefix != null ? prefix + HTML.STYLE_ATTR : HTML.STYLE_ATTR;
763 HtmlRendererUtils.renderHTMLAttribute(writer, uiComponent,
764 compAttrName, HTML.STYLE_ATTR);
765
766 HtmlRendererUtils.renderHTMLAttribute(writer, uiComponent,
767 HTML.WIDTH_ATTR, HTML.WIDTH_ATTR);
768 }
769
770 /**
771 * Return the number of columns spanned by the specified component.
772 * <p>
773 * For normal components, use the inherited implementation.
774 * For UIColumns children, return the number of dynamic columns rendered
775 * by that child.
776 *
777 * @see org.apache.myfaces.shared_tomahawk.renderkit.html.HtmlTableRendererBase
778 * #determineChildColSpan(javax.faces.component.UIComponent)
779 */
780 protected int determineChildColSpan(UIComponent uiComponent)
781 {
782 int result = super.determineChildColSpan(uiComponent);
783 if (uiComponent instanceof UIColumns)
784 {
785 result += ((UIColumns) uiComponent).getRowCount();
786 }
787 return result;
788 }
789
790 /**
791 * Return true if the specified component has a facet that needs to be
792 * rendered in a THEAD or TFOOT section.
793 *
794 * @see org.apache.myfaces.shared_tomahawk.renderkit.html.HtmlTableRendererBase#hasFacet(boolean, javax.faces.component.UIComponent)
795 */
796 protected boolean hasFacet(boolean header, UIComponent uiComponent)
797 {
798 boolean result = super.hasFacet(header, uiComponent);
799 if (!result && uiComponent instanceof UIColumns)
800 {
801 // Why is this necessary? It seems to me that the inherited
802 // implementation will work fine with a UIColumns component...
803 UIColumns columns = (UIColumns) uiComponent;
804 result = header ? columns.getHeader() != null : columns.getFooter() != null;
805 }
806 return result;
807 }
808
809 /**
810 * Renders the column footer.
811 * Rendering will be supressed if all of the facets have rendered="false"
812 */
813 protected void renderColumnFooterRow(FacesContext facesContext, ResponseWriter writer, UIComponent component, String footerStyleClass) throws IOException
814 {
815 if (determineRenderFacet(component, false))
816 {
817 super.renderColumnFooterRow(facesContext, writer, component, footerStyleClass);
818 }
819 }
820
821 /**
822 * Renders the column header.
823 * Rendering will be supressed if all of the facets have rendered="false"
824 */
825 protected void renderColumnHeaderRow(FacesContext facesContext, ResponseWriter writer, UIComponent component, String headerStyleClass) throws IOException
826 {
827 if (determineRenderFacet(component, true))
828 {
829 super.renderColumnHeaderRow(facesContext, writer, component, headerStyleClass);
830 }
831 }
832
833 /**
834 * determine if the header or footer should be rendered.
835 */
836 protected boolean determineRenderFacet(UIComponent component, boolean header)
837 {
838 for (Iterator it = getChildren(component).iterator(); it.hasNext();)
839 {
840 UIComponent uiComponent = (UIComponent) it.next();
841 if(uiComponent.isRendered() && determineChildColSpan(uiComponent) > 0)
842 {
843 UIComponent facet = header ? (UIComponent) uiComponent.getFacets().get(HEADER_FACET_NAME)
844 : (UIComponent) uiComponent.getFacets().get(FOOTER_FACET_NAME);
845
846 if (facet != null && facet.isRendered())
847 {
848 return true;
849 }
850 }
851 }
852
853 return false;
854 }
855
856 protected void beforeColumn(FacesContext facesContext, UIData uiData, int columnIndex) throws IOException
857 {
858 super.beforeColumn(facesContext, uiData, columnIndex);
859
860 if (uiData instanceof HtmlDataTable)
861 {
862 HtmlDataTable dataTable = (HtmlDataTable)uiData;
863
864 putSortedReqScopeParam(facesContext, dataTable, columnIndex);
865 }
866 }
867
868 protected void beforeColumnHeaderOrFooter(FacesContext facesContext, UIData uiData, boolean header, int columnIndex) throws IOException
869 {
870 super.beforeColumnHeaderOrFooter(facesContext, uiData, header, columnIndex);
871
872 if (header && uiData instanceof HtmlDataTable)
873 {
874 HtmlDataTable dataTable = (HtmlDataTable)uiData;
875
876 putSortedReqScopeParam(facesContext, dataTable, columnIndex);
877 }
878 }
879
880 protected void putSortedReqScopeParam(FacesContext facesContext, HtmlDataTable dataTable, int columnIndex)
881 {
882 String sortedColumnVar = dataTable.getSortedColumnVar();
883 Map requestMap = facesContext.getExternalContext().getRequestMap();
884
885 if (columnIndex == dataTable.getSortColumnIndex())
886 {
887 if (sortedColumnVar != null)
888 requestMap.put(sortedColumnVar, Boolean.TRUE);
889 }
890 else if (sortedColumnVar != null)
891 requestMap.remove(sortedColumnVar);
892 }
893
894 /**
895 * specify if the header, footer or <td> is spanned over (not shown) because
896 * of a colspan in a cell in a previous column
897 *
898 * @param prefix header, footer or null
899 * @param uiComponent
900 */
901 protected boolean amISpannedOver(String prefix, UIComponent component) {
902 UIComponent table = component.getParent();
903 int span = 0;
904 for (Iterator it = table.getChildren().iterator(); it.hasNext();) {
905 UIComponent columnComponent = (UIComponent) it.next();
906 if (!(columnComponent instanceof HtmlColumn))
907 continue;
908 if (span > 0)
909 span--;
910 if (columnComponent == component)
911 return span > 0;
912 if (span == 0) {
913 try {
914 if (prefix == null && ((HtmlColumn)columnComponent).getColspan() != null)
915 span = Integer.parseInt(((HtmlColumn)columnComponent).getColspan());
916 if ("header".equals(prefix) && ((HtmlColumn)columnComponent).getHeadercolspan() != null)
917 span = Integer.parseInt(((HtmlColumn)columnComponent).getHeadercolspan());
918 if ("footer".equals(prefix) && ((HtmlColumn)columnComponent).getFootercolspan() != null)
919 span = Integer.parseInt(((HtmlColumn)columnComponent).getFootercolspan());
920 }
921 catch (NumberFormatException ex) {
922 log.warn("Invalid " + ((prefix == null) ? "" : prefix) + "colspan attribute ignored");
923 }
924 }
925 }
926 return false;
927 }
928
929
930 /**
931 * Perform any operations necessary in the TBODY start tag.
932 *
933 * @param facesContext the <code>FacesContext</code>.
934 * @param uiData the <code>UIData</code> being rendered.
935 */
936 protected void inBodyStart(FacesContext facesContext, UIData uiData) throws IOException
937 {
938 String bodyStyleClass;
939 String bodyStyle;
940
941 if(uiData instanceof HtmlDataTable) {
942 bodyStyleClass = ((HtmlDataTable)uiData).getBodyStyleClass();
943 bodyStyle = ((HtmlDataTable)uiData).getBodyStyle();
944 } else {
945 bodyStyleClass = (String)uiData.getAttributes().get(BODY_STYLE_CLASS);
946 bodyStyle = (String)uiData.getAttributes().get(BODY_STYLE);
947 }
948
949 ResponseWriter writer = facesContext.getResponseWriter();
950 if (bodyStyleClass != null)
951 {
952 writer.writeAttribute(HTML.CLASS_ATTR, bodyStyleClass,
953 BODY_STYLE_CLASS);
954 }
955 if (bodyStyle != null)
956 {
957 writer.writeAttribute(HTML.STYLE_ATTR, bodyStyle, BODY_STYLE);
958 }
959 }
960
961
962
963 }