
org.apache.myfaces.custom.newspaper.HtmlNewspaperTableRenderer Maven / Gradle / Ivy
/*
* 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;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy