org.apache.myfaces.custom.newspaper.HtmlNewspaperTableRenderer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of tomahawk Show documentation
Show all versions of tomahawk Show documentation
JSF components and utilities that can be used with any JSF implementation.
This library is compatible with both JSF1.1 and JSF1.2; however for JSF1.2 users there
is an alternative build of Tomahawk available that takes advantage of JSF1.2 features to
offer some additional benefits.
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.myfaces.custom.newspaper;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.component.html.HtmlDataTable;
import javax.faces.context.ResponseWriter;
import javax.faces.component.UIColumn;
import javax.faces.component.UIData;
import org.apache.myfaces.shared_tomahawk.renderkit.JSFAttr;
import org.apache.myfaces.shared_tomahawk.renderkit.RendererUtils;
import org.apache.myfaces.shared_tomahawk.renderkit.html.HTML;
import org.apache.myfaces.shared_tomahawk.renderkit.html.HtmlRendererUtils;
import org.apache.myfaces.shared_tomahawk.renderkit.html.HtmlTableRendererBase;
import org.apache.myfaces.shared_tomahawk.util.ArrayUtils;
import org.apache.myfaces.shared_tomahawk.util.StringUtils;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Renderer for a table in multiple balanced columns.
*
* @JSFRenderer
* renderKitId = "HTML_BASIC"
* family = "javax.faces.Data"
* type = "org.apache.myfaces.HtmlNewspaperTable"
*
* @author Jesse Wilson
*/
public class HtmlNewspaperTableRenderer
extends HtmlTableRendererBase
{
private static final Log log = LogFactory.getLog(HtmlNewspaperTableRenderer.class);
public void encodeBegin(FacesContext facesContext, UIComponent uiComponent) throws IOException {
RendererUtils.checkParamValidity(facesContext, uiComponent, UIData.class);
ResponseWriter writer = facesContext.getResponseWriter();
HtmlNewspaperTable newspaperTable = (HtmlNewspaperTable)uiComponent;
// write out the table start tag
HtmlRendererUtils.writePrettyLineSeparator(facesContext);
writer.startElement(HTML.TABLE_ELEM, newspaperTable);
writer.writeAttribute(HTML.ID_ATTR, newspaperTable.getClientId(facesContext), null);
HtmlRendererUtils.renderHTMLAttributes(writer, newspaperTable, HTML.TABLE_PASSTHROUGH_ATTRIBUTES);
// render the header
renderFacet(facesContext, writer, newspaperTable, true);
}
public void encodeChildren(FacesContext facesContext, UIComponent uiComponent) throws IOException {
RendererUtils.checkParamValidity(facesContext, uiComponent, UIData.class);
ResponseWriter writer = facesContext.getResponseWriter();
HtmlNewspaperTable newspaperTable = (HtmlNewspaperTable)uiComponent;
// begin the table
HtmlRendererUtils.writePrettyLineSeparator(facesContext);
writer.startElement(HTML.TBODY_ELEM, newspaperTable);
// get the CSS styles
Styles styles = getStyles(newspaperTable);
// count the number of actual rows
int first = newspaperTable.getFirst();
int rows = newspaperTable.getRows();
int rowCount = newspaperTable.getRowCount();
if(rows <= 0) {
rows = rowCount - first;
}
int last = first + rows;
if(last > rowCount) last = rowCount;
// the number of slices to break the table up into */
int newspaperColumns = newspaperTable.getNewspaperColumns();
int newspaperRows;
if((last - first) % newspaperColumns == 0) newspaperRows = (last - first) / newspaperColumns;
else newspaperRows = ((last - first) / newspaperColumns) + 1;
// walk through the newspaper rows
for(int nr = 0; nr < newspaperRows; nr++) {
// write the row start
HtmlRendererUtils.writePrettyLineSeparator(facesContext);
writer.startElement(HTML.TR_ELEM, newspaperTable);
if(styles.hasRowStyle()) {
String rowStyle = styles.getRowStyle(nr);
writer.writeAttribute(HTML.CLASS_ATTR, rowStyle, null);
}
// walk through the newspaper columns
for(int nc = 0; nc < newspaperColumns; nc++) {
// the current row in the 'real' table
int currentRow = nc * newspaperRows + nr + first;
// if this row is not to be rendered
if(currentRow >= last) continue;
// bail if any row does not exist
newspaperTable.setRowIndex(currentRow);
if(!newspaperTable.isRowAvailable()) {
log.error("Row is not available. Rowindex = " + currentRow);
return;
}
// write each cell
List children = newspaperTable.getChildren();
for(int j = 0; j < newspaperTable.getChildCount(); j++) {
// skip this child if its not a rendered column
UIComponent child = (UIComponent)children.get(j);
if(!(child instanceof UIColumn)) continue;
if(!child.isRendered()) continue;
// draw the element's cell
writer.startElement(HTML.TD_ELEM, newspaperTable);
if(styles.hasColumnStyle()) writer.writeAttribute(HTML.CLASS_ATTR, styles.getColumnStyle(nc * newspaperTable.getChildCount() + j), null);
RendererUtils.renderChild(facesContext, child);
writer.endElement(HTML.TD_ELEM);
}
// draw the spacer facet
if(nc < newspaperColumns - 1) renderSpacerCell(facesContext, writer, newspaperTable);
}
// write the row end
writer.endElement(HTML.TR_ELEM);
}
// write the end of the table's body
writer.endElement(HTML.TBODY_ELEM);
}
/**
* Fetch the number of columns to divide the table into.
*/
private int getNewspaperColumns() {
return 3;
}
public void encodeEnd(FacesContext facesContext, UIComponent uiComponent) throws IOException {
RendererUtils.checkParamValidity(facesContext, uiComponent, UIData.class);
ResponseWriter writer = facesContext.getResponseWriter();
HtmlNewspaperTable newspaperTable = (HtmlNewspaperTable)uiComponent;
// render the footer
renderFacet(facesContext, writer, newspaperTable, false);
// write out the table end tag
writer.endElement(HTML.TABLE_ELEM);
HtmlRendererUtils.writePrettyLineSeparator(facesContext);
}
/**
* Count the number of columns in the speicifed Newspaper table..
*/
private int countColumns(HtmlNewspaperTable newspaperTable) {
int columnCount = 0;
for(Iterator it = newspaperTable.getChildren().iterator(); it.hasNext(); ) {
UIComponent uiComponent = (UIComponent)it.next();
if (uiComponent instanceof UIColumn && ((UIColumn)uiComponent).isRendered()) {
columnCount++;
}
}
return columnCount;
}
/**
* Tests if the specified facet exists for the specified newspaper table.
*/
private boolean hasFacet(HtmlNewspaperTable newspaperTable, boolean header) {
for(Iterator it = newspaperTable.getChildren().iterator(); it.hasNext(); ) {
// get the column
UIComponent uiComponent = (UIComponent)it.next();
if(!(uiComponent instanceof UIColumn)) continue;
UIColumn column = (UIColumn)uiComponent;
if(!column.isRendered()) continue;
// test the facet
if(header && ((UIColumn)uiComponent).getHeader() != null) return true;
if(!header && ((UIColumn)uiComponent).getFooter() != null) return true;
}
return false;
}
/**
* Render table headers and footers.
*/
private void renderFacet(FacesContext facesContext, ResponseWriter writer, HtmlNewspaperTable newspaperTable, boolean header) throws IOException {
int columnCount = countColumns(newspaperTable);
boolean hasColumnFacet = hasFacet(newspaperTable, header);
UIComponent facet = header ? newspaperTable.getHeader() : newspaperTable.getFooter();
// quit if there's nothing to draw
if(facet == null && !hasColumnFacet) return;
// start the row block
HtmlRendererUtils.writePrettyLineSeparator(facesContext);
String elemName = header ? HTML.THEAD_ELEM : HTML.TFOOT_ELEM;
writer.startElement(elemName, newspaperTable);
// fetch the style
String styleClass;
if(header) styleClass = getHeaderClass(newspaperTable);
else styleClass = getFooterClass(newspaperTable);
// write the header row and column headers
if(header) {
if (facet != null) renderTableHeaderOrFooterRow(facesContext, writer, newspaperTable, facet, styleClass, HTML.TD_ELEM, columnCount);
if (hasColumnFacet) renderColumnHeaderOrFooterRow(facesContext, writer, newspaperTable, styleClass, header);
// write the footer row and column footers
} else {
if (hasColumnFacet) renderColumnHeaderOrFooterRow(facesContext, writer, newspaperTable, styleClass, header);
if (facet != null) renderTableHeaderOrFooterRow(facesContext, writer, newspaperTable, facet, styleClass, HTML.TD_ELEM, columnCount);
}
// end the row block
writer.endElement(elemName);
}
/**
* Renders the table header or footer row. This is one giant cell that spans
* the entire table header or footer.
*/
private void renderTableHeaderOrFooterRow(FacesContext facesContext, ResponseWriter writer,
HtmlNewspaperTable newspaperTable, UIComponent facet, String styleClass, String colElementName, int tableColumns)
throws IOException {
// start the row
HtmlRendererUtils.writePrettyLineSeparator(facesContext);
writer.startElement(HTML.TR_ELEM, newspaperTable);
writer.startElement(colElementName, newspaperTable);
if(styleClass != null) writer.writeAttribute(HTML.CLASS_ATTR, styleClass, null);
if(colElementName.equals(HTML.TH_ELEM)) writer.writeAttribute(HTML.SCOPE_ATTR, HTML.SCOPE_COLGROUP_VALUE, null);
// span all the table's columns
int totalColumns = newspaperTable.getNewspaperColumns() * tableColumns;
if(newspaperTable.getSpacer() != null) totalColumns = totalColumns + getNewspaperColumns() - 1;
writer.writeAttribute(HTML.COLSPAN_ATTR, new Integer(totalColumns), null);
// write the actual cell contents
if(facet != null) RendererUtils.renderChild(facesContext, facet);
// finish
writer.endElement(colElementName);
writer.endElement(HTML.TR_ELEM);
}
/**
* Renders the column header or footer row.
*/
private void renderColumnHeaderOrFooterRow(FacesContext facesContext,
ResponseWriter writer, HtmlNewspaperTable newspaperTable, String styleClass, boolean header)
throws IOException {
HtmlRendererUtils.writePrettyLineSeparator(facesContext);
writer.startElement(HTML.TR_ELEM, newspaperTable);
int newspaperColumns = newspaperTable.getNewspaperColumns();
for(int nc = 0; nc < newspaperColumns; nc++) {
for(Iterator it = newspaperTable.getChildren().iterator(); it.hasNext(); ) {
UIComponent uiComponent = (UIComponent)it.next();
if(!(uiComponent instanceof UIColumn)) continue;
UIColumn column = (UIColumn)uiComponent;
if(!column.isRendered()) continue;
// get the component to render
UIComponent facet = null;
if(header) facet = column.getHeader();
else facet = column.getFooter();
// do the rendering of the cells
renderColumnHeaderOrFooterCell(facesContext, writer, column, styleClass, facet);
}
// draw the spacer facet
if(nc < newspaperColumns - 1) renderSpacerCell(facesContext, writer, newspaperTable);
}
writer.endElement(HTML.TR_ELEM);
}
/**
* Renders a cell in the column header or footer.
*/
private void renderColumnHeaderOrFooterCell(FacesContext facesContext, ResponseWriter writer,
UIColumn uiColumn, String styleClass, UIComponent facet) throws IOException {
writer.startElement(HTML.TH_ELEM, uiColumn);
if(styleClass != null) writer.writeAttribute(HTML.CLASS_ATTR, styleClass, null);
if(facet != null) RendererUtils.renderChild(facesContext, facet);
writer.endElement(HTML.TH_ELEM);
}
/**
* Renders a spacer between adjacent newspaper columns.
*/
private void renderSpacerCell(FacesContext facesContext, ResponseWriter writer,
HtmlNewspaperTable newspaperTable) throws IOException {
if(newspaperTable.getSpacer() == null) return;
writer.startElement(HTML.TD_ELEM, newspaperTable);
RendererUtils.renderChild(facesContext, newspaperTable.getSpacer());
writer.endElement(HTML.TD_ELEM);
}
/**
* Gets the style class for the table header.
*/
private static String getHeaderClass(HtmlNewspaperTable newspaperTable) {
if(newspaperTable instanceof HtmlDataTable) {
return ((HtmlDataTable)newspaperTable).getHeaderClass();
} else {
return (String)newspaperTable.getAttributes().get(JSFAttr.HEADER_CLASS_ATTR);
}
}
/**
* Gets the style class for the table footer.
*/
private static String getFooterClass(HtmlNewspaperTable newspaperTable) {
if(newspaperTable instanceof HtmlDataTable) {
return ((HtmlDataTable)newspaperTable).getFooterClass();
} else {
return (String)newspaperTable.getAttributes().get(JSFAttr.FOOTER_CLASS_ATTR);
}
}
/**
* Gets styles for the specified component.
*/
public static Styles getStyles(HtmlNewspaperTable newspaperTable) {
String rowClasses;
String columnClasses;
if(newspaperTable instanceof HtmlDataTable) {
rowClasses = ((HtmlDataTable)newspaperTable).getRowClasses();
columnClasses = ((HtmlDataTable)newspaperTable).getColumnClasses();
} else {
rowClasses = (String)newspaperTable.getAttributes().get(JSFAttr.ROW_CLASSES_ATTR);
columnClasses = (String)newspaperTable.getAttributes().get(JSFAttr.COLUMN_CLASSES_ATTR);
}
return new Styles(rowClasses, columnClasses);
}
/**
* Class manages the styles from String lists.
*/
private static class Styles {
private String[] _columnStyle;
private String[] _rowStyle;
Styles(String rowStyles, String columnStyles) {
_rowStyle = (rowStyles == null)
? ArrayUtils.EMPTY_STRING_ARRAY
: StringUtils.trim(
StringUtils.splitShortString(rowStyles, ','));
_columnStyle = (columnStyles == null)
? ArrayUtils.EMPTY_STRING_ARRAY
: StringUtils.trim(
StringUtils.splitShortString(columnStyles, ','));
}
public String getRowStyle(int idx) {
if(!hasRowStyle()) {
return null;
}
return _rowStyle[idx % _rowStyle.length];
}
public String getColumnStyle(int idx) {
if(!hasColumnStyle()) {
return null;
}
return _columnStyle[idx % _columnStyle.length];
}
public boolean hasRowStyle() {
return _rowStyle.length > 0;
}
public boolean hasColumnStyle() {
return _columnStyle.length > 0;
}
}
}