/**
* License Agreement.
*
* JBoss RichFaces - Ajax4jsf Component Library
*
* Copyright (C) 2007 Exadel, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package org.richfaces.renderkit;
import java.io.IOException;
import java.util.Iterator;
import javax.faces.FacesException;
import javax.faces.component.UIColumn;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import org.ajax4jsf.renderkit.RendererUtils.HTML;
import org.apache.commons.collections.Predicate;
import org.apache.commons.collections.iterators.FilterIterator;
import org.richfaces.component.Column;
import org.richfaces.component.Row;
import org.richfaces.component.UIDataTable;
/**
* @author shura
*
*/
public abstract class AbstractTableRenderer extends AbstractRowsRenderer {
/**
* Encode all table structure - colgroups definitions, caption, header,
* footer
*
* @param context
* @param table
* @throws IOException
*/
// protected final static String PERSENTAGE_SUPPORT_ERROR_MSG = "columnsWidth property: Percentage values are not supported";
public void encodeTableStructure(FacesContext context, UIDataTable table)
throws IOException {
ResponseWriter writer = context.getResponseWriter();
int columns = getColumnsCount(table);
// Encode colgroup definition.
writer.startElement("colgroup", table);
writer.writeAttribute("span", String.valueOf(columns), null);
String columnsWidth = (String) table.getAttributes().get("columnsWidth");
if (null != columnsWidth) {
// temporary solution RF-957
// if(columnsWidth.contains("%")){
// throw new FacesException(PERSENTAGE_SUPPORT_ERROR_MSG);
// }
String[] widths = columnsWidth.split(",");
for (int i = 0; i < widths.length; i++) {
writer.startElement("col", table);
writer.writeAttribute("width", widths[i], null);
writer.endElement("col");
}
}
writer.endElement("colgroup");
encodeCaption(context, table);
encodeHeader(context, table, columns);
encodeFooter(context, table, columns);
}
public void encodeHeader(FacesContext context, UIDataTable table,
int columns) throws IOException {
ResponseWriter writer = context.getResponseWriter();
UIComponent header = table.getHeader();
Iterator headers = columnFacets(table,"header");
if (header != null ||headers.hasNext()) {
writer.startElement("thead", table);
String headerClass = (String) table.getAttributes().get(
"headerClass");
if (header != null) {
encodeTableHeaderFacet(context, columns, writer, header,
"dr-table-header rich-table-header",
"dr-table-header-continue rich-table-header-continue",
"dr-table-headercell rich-table-headercell",
headerClass, "th");
}
if (headers.hasNext()&&findFacet(table,"header")) {
writer.startElement("tr", table);
encodeStyleClass(writer, null,
"dr-table-subheader rich-table-subheader", null,
headerClass);
encodeHeaderFacets(context, writer, headers,
"dr-table-subheadercell rich-table-subheadercell",
headerClass, "header", "th");
writer.endElement("tr");
}
writer.endElement("thead");
}
}
public boolean findFacet(UIDataTable table, String facetName)
{
Iterator iter = columnFacets(table,facetName);
boolean find = false;
while(iter.hasNext()){
UIComponent comp = (UIComponent) iter.next();
if(comp.getFacet(facetName)!=null)
{
find = true;
break;
}
}
return find;
}
protected void encodeHeaderFacets(FacesContext context,
ResponseWriter writer, Iterator headers, String skinCellClass,
String headerClass, String facetName, String element)
throws IOException {
while (headers.hasNext()) {
UIComponent column = (UIComponent) headers.next();
String classAttribute = facetName + "Class";
String columnHeaderClass = (String) column.getAttributes().get(
classAttribute);
writer.startElement(element, column);
encodeStyleClass(writer, null, skinCellClass, headerClass,
columnHeaderClass);
writer.writeAttribute("scope", "col", null);
getUtils().encodeAttribute(context, column, "colspan");
UIComponent facet = column.getFacet(facetName);
if (facet != null) {
renderChild(context, facet);
}
writer.endElement(element);
}
}
public void encodeFooter(FacesContext context, UIDataTable table,
int columns) throws IOException {
ResponseWriter writer = context.getResponseWriter();
UIComponent footer = table.getFooter();
Iterator footers = columnFacets(table,"footer");
if (footer != null || footers.hasNext()) {
writer.startElement("tfoot", table);
String footerClass = (String) table.getAttributes().get(
"footerClass");
if (footers.hasNext()&&findFacet(table,"footer")) {
writer.startElement("tr", table);
encodeStyleClass(writer, null,
"dr-table-subfooter rich-table-subfooter", null,
footerClass);
encodeHeaderFacets(context, writer, footers,
"dr-table-subfootercell rich-table-subfootercell",
footerClass, "footer", "td");
writer.endElement("tr");
}
if (footer != null) {
encodeTableHeaderFacet(context, columns, writer, footer,
"dr-table-footer rich-table-footer",
"dr-table-footer-continue rich-table-footer-continue",
"dr-table-footercell rich-table-footercell",
footerClass, "td");
}
writer.endElement("tfoot");
}
}
public void encodeOneRow(FacesContext context, TableHolder holder)
throws IOException {
UIDataTable table = (UIDataTable) holder.getTable();
ResponseWriter writer = context.getResponseWriter();
Iterator iter = table.columns();
boolean first = true;
int currentColumn = 0;
UIComponent column = null;
while (iter.hasNext()) {
column = (UIComponent) iter.next();
// Start new row for first column - expect a case of the detail
// table, wich will be insert own row.
if (first && !(column instanceof Row)) {
encodeRowStart(context, getFirstRowSkinClass(), holder
.getRowClass(), table, writer);
}
if (column instanceof Column) {
boolean breakBefore = ((Column) column).isBreakBefore()
|| column instanceof Row;
if (breakBefore && !first) {
// close current row
writer.endElement(HTML.TR_ELEMENT);
// reset columns counter.
currentColumn = 0;
// Start new row, expect a case of the detail table, wich
// will be insert own row.
if (!(column instanceof Row)) {
holder.nextRow();
encodeRowStart(context, holder.getRowClass(), table,
writer);
}
}
encodeCellChildren(context, column,
first ? getFirstRowSkinClass() : null,
getRowSkinClass(), holder.getRowClass(),
getCellSkinClass(), holder
.getColumnClass(currentColumn));
// renderChild(context, column);
if ((column instanceof Row) && iter.hasNext()) {
// Start new row for remained columns.
holder.nextRow();
encodeRowStart(context, holder.getRowClass(), table, writer);
// reset columns counter.
currentColumn = -1;
}
} else if (column.isRendered()) {
// UIColumn don't have own renderer
writer.startElement(HTML.td_ELEM, table);
getUtils().encodeId(context, column);
String columnClass = holder.getColumnClass(currentColumn);
encodeStyleClass(writer, null, getCellSkinClass(), null,
columnClass);
// TODO - encode column attributes.
renderChildren(context, column);
writer.endElement(HTML.td_ELEM);
}
currentColumn++;
first = false;
}
// Close row if then is open.
if (!first && !(column instanceof Row)) {
writer.endElement(HTML.TR_ELEMENT);
}
}
protected void encodeRowStart(FacesContext context, String rowClass,
UIDataTable table, ResponseWriter writer) throws IOException {
encodeRowStart(context, getRowSkinClass(), rowClass, table, writer);
}
/**
* @return
*/
protected String getRowSkinClass() {
return "dr-table-row rich-table-row";
}
/**
* @return
*/
protected String getFirstRowSkinClass() {
return "dr-table-firstrow rich-table-firstrow";
}
/**
* @return
*/
protected String getCellSkinClass() {
return "dr-table-cell rich-table-cell";
}
protected void encodeRowStart(FacesContext context, String skinClass,
String rowClass, UIDataTable table, ResponseWriter writer)
throws IOException {
writer.startElement(HTML.TR_ELEMENT, table);
encodeStyleClass(writer, null, skinClass, null, rowClass);
encodeRowEvents(context, table);
}
/*
* protected Iterator columnFacets(UIDataTable table) { return
* table.columns();
*
* Changed by Alexej Kushunin
*/
protected Iterator columnFacets(UIDataTable table,final String name){
return new FilterIterator(table.columns(), new Predicate() {
public boolean evaluate(Object input) {
UIComponent component = (UIComponent) input;
// accept only columns with corresponding facets.
if (component instanceof Column || component instanceof UIColumn) {
return component.isRendered()&&(component.getFacet(name) != null);
}
else{
return false;
}
}});
}
/**
* Calculate total number of columns in table.
*
* @param context
* @param table
* @return
*/
protected int getColumnsCount(UIDataTable table) {
int count = 0;
// check for exact value in component
Integer span = (Integer) table.getAttributes().get("columns");
if (null != span && span.intValue() != Integer.MIN_VALUE) {
count = span.intValue();
} else {
// calculate max html columns count for all columns/rows children.
Iterator col = table.columns();
count = calculateRowColumns(col);
}
return count;
}
/**
* Calculate max number of columns per row. For rows, recursive calculate
* max length.
*
* @param col -
* Iterator other all columns in table.
* @return
*/
protected int calculateRowColumns(Iterator col) {
int count = 0;
int currentLength = 0;
while (col.hasNext()) {
UIComponent column = (UIComponent) col.next();
if (column.isRendered()) {
if (column instanceof Row) {
// Store max calculated value of previsous rows.
if (currentLength > count) {
count = currentLength;
}
// Calculate number of columns in row.
currentLength = calculateRowColumns(((Row) column)
.columns());
// Store max calculated value
if (currentLength > count) {
count = currentLength;
}
currentLength = 0;
} else if (column instanceof Column) {
Column tableColumn = (Column) column;
// For new row, save length of previsous.
if (tableColumn.isBreakBefore()) {
if (currentLength > count) {
count = currentLength;
}
currentLength = 0;
}
Integer colspan = (Integer) column.getAttributes().get(
"colspan");
// Append colspan of this column
if (null != colspan
&& colspan.intValue() != Integer.MIN_VALUE) {
currentLength += colspan.intValue();
} else {
currentLength++;
}
} else if (column instanceof UIColumn) {
// UIColumn always have colspan == 1.
currentLength++;
}
}
}
if (currentLength > count) {
count = currentLength;
}
return count;
}
}