All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.myfaces.renderkit.html.HtmlTableRendererBase Maven / Gradle / Ivy

Go to download

The MyFaces Commons Subproject provides base classes for usage in both the MyFaces implementation and the MyFaces Tomahawk components. This is also a general set of utility classes for usage in your JSF projects independent of the implementation you might be deciding upon.

The newest version!
/*
 * Copyright 2004 The Apache Software Foundation.
 *
 * Licensed 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.renderkit.html;

import org.apache.myfaces.renderkit.JSFAttr;
import org.apache.myfaces.renderkit.RendererUtils;
import org.apache.myfaces.util.ArrayUtils;
import org.apache.myfaces.util.StringUtils;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import javax.faces.component.UIColumn;
import javax.faces.component.UIComponent;
import javax.faces.component.UIData;
import javax.faces.component.html.HtmlDataTable;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;

/**
 * Common methods for renderers for components that subclass the standard
 * JSF HtmlDataTable component.
 * 
 * @author Thomas Spiegl (latest modification by $Author: skitching $)
 * @version $Revision: 358448 $ $Date: 2005-12-22 02:52:45 +0000 (Thu, 22 Dec 2005) $
 */
public class HtmlTableRendererBase extends HtmlRenderer
{
    /** Header facet name. */
    protected static final String HEADER_FACET_NAME = "header";

    /** Footer facet name. */
    protected static final String FOOTER_FACET_NAME = "footer";

    /** The logger. */
    private static final Log log = LogFactory.getLog(HtmlTableRendererBase.class);

    /**
     * @see javax.faces.render.Renderer#getRendersChildren()
     */
    public boolean getRendersChildren()
    {
        return true;
    }

    /**
     * Render the necessary bits that come before any actual rows in the table.
     * 
     * @see javax.faces.render.Renderer#encodeBegin(FacesContext, UIComponent)
     */
    public void encodeBegin(FacesContext facesContext, UIComponent uiComponent) throws IOException
    {
        RendererUtils.checkParamValidity(facesContext, uiComponent, UIData.class);

        ResponseWriter writer = facesContext.getResponseWriter();

        beforeTable(facesContext, (UIData) uiComponent);

        HtmlRendererUtils.writePrettyLineSeparator(facesContext);
        writer.startElement(HTML.TABLE_ELEM, uiComponent);
        HtmlRendererUtils.writeIdIfNecessary(writer, uiComponent, facesContext);
        HtmlRendererUtils.renderHTMLAttributes(writer, uiComponent, HTML.TABLE_PASSTHROUGH_ATTRIBUTES);
    }

    /**
     * Render the TBODY section of the html table. See also method encodeInnerHtml.
     * 
     * @see javax.faces.render.Renderer#encodeChildren(FacesContext, UIComponent)
     */
    public void encodeChildren(FacesContext facesContext, UIComponent component) throws IOException
    {
        RendererUtils.checkParamValidity(facesContext, component, UIData.class);

        ResponseWriter writer = facesContext.getResponseWriter();

        beforeBody(facesContext, (UIData) component);

        HtmlRendererUtils.writePrettyLineSeparator(facesContext);
        writer.startElement(HTML.TBODY_ELEM, component);
        writer.writeAttribute(HTML.ID_ATTR, component.getClientId(facesContext)+":tbody_element", null);

        encodeInnerHtml(facesContext, component);

        writer.endElement(HTML.TBODY_ELEM);

        afterBody(facesContext, (UIData) component);
    }

    /**
     * Renders everything inside the TBODY tag by iterating over the row objects
     * between offsets first and first+rows and applying the UIColumn components
     * to those objects. 
     * 

* This method is separated from the encodeChildren so that it can be overridden by * subclasses. One class that uses this functionality is autoUpdateDataTable. */ public void encodeInnerHtml(FacesContext facesContext, UIComponent component)throws IOException{ UIData uiData = (UIData) component; ResponseWriter writer = facesContext.getResponseWriter(); String rowClasses; String columnClasses; if (component instanceof HtmlDataTable) { rowClasses = ((HtmlDataTable) component).getRowClasses(); columnClasses = ((HtmlDataTable) component).getColumnClasses(); } else { rowClasses = (String) component.getAttributes().get(JSFAttr.ROW_CLASSES_ATTR); columnClasses = (String) component.getAttributes().get(JSFAttr.COLUMN_CLASSES_ATTR); } Iterator rowStyleIterator = new StyleIterator(rowClasses); StyleIterator columnStyleIterator = new StyleIterator(columnClasses); int first = uiData.getFirst(); int rows = uiData.getRows(); int rowCount = uiData.getRowCount(); if (rows <= 0) { rows = rowCount - first; } int last = first + rows; if (last > rowCount) last = rowCount; for (int i = first; i < last; i++) { uiData.setRowIndex(i); if (!uiData.isRowAvailable()) { log.error("Row is not available. Rowindex = " + i); return; } columnStyleIterator.reset(); beforeRow(facesContext, uiData); HtmlRendererUtils.writePrettyLineSeparator(facesContext); renderRowStart(facesContext, writer, uiData, rowStyleIterator); List children = getChildren(component); for (int j = 0, size = getChildCount(component); j < size; j++) { UIComponent child = (UIComponent) children.get(j); if(child.isRendered()) { encodeColumnChild(facesContext, writer, uiData, child, columnStyleIterator); } } renderRowEnd(facesContext, writer, uiData); afterRow(facesContext, uiData); } } protected void encodeColumnChild(FacesContext facesContext, ResponseWriter writer, UIData uiData, UIComponent component, Iterator columnStyleIterator) throws IOException { if (component instanceof UIColumn) { renderColumnBody(facesContext, writer, uiData, component, columnStyleIterator); } } /** * Renders the body of a given UIColumn (everything but * the header and footer facets). This emits a TD cell, whose contents * are the result of calling encodeBegin, encodeChildren and * encodeEnd methods on the component (or its associated renderer). * * @param facesContext the FacesContext. * @param writer the ResponseWriter. * @param uiData the UIData being rendered. * @param component the UIComponent to render. * @param columnStyleIterator the styleClass of the UIColumn or null if * there is none. * @throws IOException if an exception occurs. */ protected void renderColumnBody( FacesContext facesContext, ResponseWriter writer, UIData uiData, UIComponent component, Iterator columnStyleIterator) throws IOException { writer.startElement(HTML.TD_ELEM, uiData); if (columnStyleIterator.hasNext()) { writer.writeAttribute(HTML.CLASS_ATTR, columnStyleIterator.next(), null); } RendererUtils.renderChild(facesContext, component); writer.endElement(HTML.TD_ELEM); } /** * Renders the start of a new row of body content. * @param facesContext the FacesContext. * @param writer the ResponseWriter. * @param uiData the UIData being rendered. * @param rowStyleIterator te styleClass of the row or null if there is none. * @throws IOException if an exceptoin occurs. */ protected void renderRowStart( FacesContext facesContext, ResponseWriter writer, UIData uiData, Iterator rowStyleIterator) throws IOException { writer.startElement(HTML.TR_ELEM, uiData); renderRowStyle(facesContext, writer, uiData, rowStyleIterator); Object rowId = uiData.getAttributes().get(JSFAttr.ROW_ID); if (rowId != null) { writer.writeAttribute(HTML.ID_ATTR, rowId.toString(), null); } } protected void renderRowStyle(FacesContext facesContext, ResponseWriter writer, UIData uiData, Iterator rowStyleIterator) throws IOException { if (rowStyleIterator.hasNext()) { writer.writeAttribute(HTML.CLASS_ATTR, rowStyleIterator.next(), null); } } /** * Renders the end of a row of body content. * @param facesContext the FacesContext. * @param writer the ResponseWriter. * @param uiData the UIData being rendered. * @throws IOException if an exceptoin occurs. */ protected void renderRowEnd( FacesContext facesContext, ResponseWriter writer, UIData uiData) throws IOException { writer.endElement(HTML.TR_ELEM); } /** * Perform any operations necessary immediately before the TABLE start tag * is output. * * @param facesContext the FacesContext. * @param uiData the UIData being rendered. */ protected void beforeTable(FacesContext facesContext, UIData uiData) throws IOException { } /** * Perform any operations necessary after TABLE start tag is output * but before the TBODY start tag. *

* This method generates the THEAD/TFOOT sections of a table if there * are any header or footer facets defined on the table or on any child * UIColumn component. * * @param facesContext the FacesContext. * @param uiData the UIData being rendered. */ protected void beforeBody(FacesContext facesContext, UIData uiData) throws IOException { ResponseWriter writer = facesContext.getResponseWriter(); renderFacet(facesContext, writer, uiData, true); renderFacet(facesContext, writer, uiData, false); } /** * Perform any operations necessary immediately before each TR start tag * is output. * * @param facesContext the FacesContext. * @param uiData the UIData being rendered. */ protected void beforeRow(FacesContext facesContext, UIData uiData) throws IOException { } /** * Perform any operations necessary immediately after each TR end tag * is output. * * @param facesContext the FacesContext. * @param uiData the UIData being rendered. */ protected void afterRow(FacesContext facesContext, UIData uiData) throws IOException { } /** * Perform any operations necessary immediately after the TBODY end tag * is output. * * @param facesContext the FacesContext. * @param uiData the UIData being rendered. */ protected void afterBody(FacesContext facesContext, UIData uiData) throws IOException { } /** * Perform any operations necessary immediately after the TABLE end tag * is output. * * @param facesContext the FacesContext. * @param uiData the UIData being rendered. */ protected void afterTable(FacesContext facesContext, UIData uiData) throws IOException { } /** * @see javax.faces.render.Renderer#encodeEnd(FacesContext, UIComponent) */ public void encodeEnd(FacesContext facesContext, UIComponent uiComponent) throws IOException { RendererUtils.checkParamValidity(facesContext, uiComponent, UIData.class); ResponseWriter writer = facesContext.getResponseWriter(); writer.endElement(HTML.TABLE_ELEM); HtmlRendererUtils.writePrettyLineSeparator(facesContext); afterTable(facesContext, (UIData) uiComponent); } /** * Renders either the header or the footer facets for the UIData component * and all the child UIColumn components, as a THEAD or TFOOT element * containing TR (row) elements. *

* If there is a header or footer attached to the UIData then that is * rendered as a TR element whose COLSPAN is the sum of all rendered * columns in the table. This allows that header/footer to take up the * entire width of the table. *

* If any child column has a header or footer then a TR is rendered * with a TH cell for each column child. * * @param facesContext the FacesContext. * @param writer the ResponseWriter. * @param component the UIData component * @param header whether this is the header facet (if not, then the footer facet). * @throws IOException if an exception occurs. */ protected void renderFacet(FacesContext facesContext, ResponseWriter writer, UIComponent component, boolean header) throws IOException { int colspan = 0; boolean hasColumnFacet = false; for (Iterator it = getChildren(component).iterator(); it.hasNext();) { UIComponent uiComponent = (UIComponent) it.next(); if(uiComponent.isRendered()) { // a UIColumn has a span of 1, anything else has a span of 0 colspan += determineChildColSpan(uiComponent); // hasColumnFacet is true if *any* child column has a facet of // the specified type. if (!hasColumnFacet) { hasColumnFacet = hasFacet(header, uiComponent); } } } UIComponent facet = header ? (UIComponent) component.getFacets().get(HEADER_FACET_NAME) : (UIComponent) component.getFacets().get(FOOTER_FACET_NAME); if (facet != null || hasColumnFacet) { // Header or Footer present on either the UIData or a column, so we // definitely need to render the THEAD or TFOOT section. String elemName = header ? HTML.THEAD_ELEM : HTML.TFOOT_ELEM; HtmlRendererUtils.writePrettyLineSeparator(facesContext); writer.startElement(elemName, component); if (header) { String headerStyleClass = getHeaderClass(component); if (facet != null) renderTableHeaderRow(facesContext, writer, component, facet, headerStyleClass, colspan); if (hasColumnFacet) renderColumnHeaderRow(facesContext, writer, component, headerStyleClass); } else { String footerStyleClass = getFooterClass(component); if (hasColumnFacet) renderColumnFooterRow(facesContext, writer, component, footerStyleClass); if (facet != null) renderTableFooterRow(facesContext, writer, component, facet, footerStyleClass, colspan); } writer.endElement(elemName); } } /** * @param header * @param uiComponent * @return boolean */ protected boolean hasFacet(boolean header, UIComponent uiComponent) { if (uiComponent instanceof UIColumn) { UIColumn uiColumn = (UIColumn) uiComponent; return header ? uiColumn.getHeader() != null : uiColumn.getFooter() != null; } return false; } /** * Calculate the number of columns the specified child component will span * when rendered. *

* Normally, this is a fairly simple calculation: a UIColumn component * is rendered as one column, every other child type is not rendered * (ie spans zero columns). However custom subclasses of this renderer may * override this method to handle cases where a single component renders * as multiple columns. */ protected int determineChildColSpan(UIComponent uiComponent) { if (uiComponent instanceof UIColumn) { return 1; } return 0; } /** * Renders the header row of the table being rendered. * @param facesContext the FacesContext. * @param writer the ResponseWriter. * @param component the UIComponent for whom a table is being rendered. * @param headerFacet the facet for the header. * @param headerStyleClass the styleClass of the header. * @param colspan the number of columns the header should span. Typically, this is * the number of columns in the table. * @throws IOException if an exception occurs. */ protected void renderTableHeaderRow(FacesContext facesContext, ResponseWriter writer, UIComponent component, UIComponent headerFacet, String headerStyleClass, int colspan) throws IOException { renderTableHeaderOrFooterRow(facesContext, writer, component, headerFacet, headerStyleClass, HTML.TH_ELEM, colspan); } /** * Renders the footer row of the table being rendered. * @param facesContext the FacesContext. * @param writer the ResponseWriter. * @param component the UIComponent for whom a table is being rendered. * @param footerFacet the facet for the footer. * @param footerStyleClass the styleClass of the footer. * @param colspan the number of columns the header should span. Typically, this is * the number of columns in the table. * @throws IOException if an exception occurs. */ protected void renderTableFooterRow(FacesContext facesContext, ResponseWriter writer, UIComponent component, UIComponent footerFacet, String footerStyleClass, int colspan) throws IOException { renderTableHeaderOrFooterRow(facesContext, writer, component, footerFacet, footerStyleClass, HTML.TD_ELEM, colspan); } /** * Renders the header row for the columns, which is a separate row from the header row for the * UIData header facet. * * @param facesContext the FacesContext. * @param writer the ResponseWriter. * @param component the UIData component for whom a table is being rendered. * @param headerStyleClass the styleClass of the header * @throws IOException if an exception occurs. */ protected void renderColumnHeaderRow(FacesContext facesContext, ResponseWriter writer, UIComponent component, String headerStyleClass) throws IOException { renderColumnHeaderOrFooterRow(facesContext, writer, component, headerStyleClass, true); } /** * Renders the footer row for the columns, which is a separate row from the footer row for the * UIData footer facet. * @param facesContext the FacesContext. * @param writer the ResponseWriter. * @param component the UIComponent for whom a table is being rendered. * @param footerStyleClass the styleClass of the footerStyleClass * @throws IOException if an exception occurs. */ protected void renderColumnFooterRow(FacesContext facesContext, ResponseWriter writer, UIComponent component, String footerStyleClass) throws IOException { renderColumnHeaderOrFooterRow(facesContext, writer, component, footerStyleClass, false); } private void renderTableHeaderOrFooterRow(FacesContext facesContext, ResponseWriter writer, UIComponent component, UIComponent facet, String styleClass, String colElementName, int colspan) throws IOException { HtmlRendererUtils.writePrettyLineSeparator(facesContext); writer.startElement(HTML.TR_ELEM, component); writer.startElement(colElementName, component); if (colElementName.equals(HTML.TH_ELEM)) { writer.writeAttribute(HTML.SCOPE_ATTR, HTML.SCOPE_COLGROUP_VALUE, null); } writer.writeAttribute(HTML.COLSPAN_ATTR, new Integer(colspan), null); if (styleClass != null) { writer.writeAttribute(HTML.CLASS_ATTR, styleClass, null); } if (facet != null) { RendererUtils.renderChild(facesContext, facet); } writer.endElement(colElementName); writer.endElement(HTML.TR_ELEM); } /** * @param component the UIData component for whom a table is being rendered. */ private void renderColumnHeaderOrFooterRow(FacesContext facesContext, ResponseWriter writer, UIComponent component, String styleClass, boolean header) throws IOException { HtmlRendererUtils.writePrettyLineSeparator(facesContext); writer.startElement(HTML.TR_ELEM, component); for (Iterator it = getChildren(component).iterator(); it.hasNext();) { UIComponent uiComponent = (UIComponent) it.next(); if(uiComponent.isRendered()) { renderColumnChildHeaderOrFooterRow(facesContext, writer, uiComponent, styleClass, header); } } writer.endElement(HTML.TR_ELEM); } protected void renderColumnChildHeaderOrFooterRow(FacesContext facesContext, ResponseWriter writer, UIComponent uiComponent, String styleClass, boolean header) throws IOException { if (uiComponent instanceof UIColumn) { if (header) { renderColumnHeaderCell(facesContext, writer, uiComponent, ((UIColumn) uiComponent).getHeader(), styleClass, 0); } else { renderColumnFooterCell(facesContext, writer, uiComponent, ((UIColumn) uiComponent).getFooter(), styleClass, 0); } } } /** * Renders the header facet for the given UIColumn. * @param facesContext the FacesContext. * @param writer the ResponseWriter. * @param uiColumn the UIColumn. * @param headerStyleClass the styleClass of the header facet. * @param colspan the colspan for the tableData element in which the header facet * will be wrapped. * @throws IOException */ protected void renderColumnHeaderCell(FacesContext facesContext, ResponseWriter writer, UIColumn uiColumn, String headerStyleClass, int colspan) throws IOException { renderColumnHeaderCell(facesContext, writer, uiColumn, uiColumn.getHeader(), headerStyleClass, colspan); } /** * Renders a TH cell within a TR within a THEAD section. If the specified * UIColumn object does have a header facet, then that facet is rendered * within the cell, otherwise the cell is left blank (though any specified * style class is still applied to empty cells). * * @param facesContext the FacesContext. * @param writer the ResponseWriter. * @param uiComponent the UIComponent to render the facet for. * @param facet the UIComponent to render as facet. * @param headerStyleClass the styleClass of the header facet. * @param colspan the colspan for the tableData element in which the header facet * will be wrapped. * @throws IOException */ protected void renderColumnHeaderCell(FacesContext facesContext, ResponseWriter writer, UIComponent uiComponent, UIComponent facet, String headerStyleClass, int colspan) throws IOException { writer.startElement(HTML.TH_ELEM, uiComponent); if (colspan > 1) { writer.writeAttribute(HTML.COLSPAN_ATTR, new Integer(colspan), null); } if (headerStyleClass != null) { writer.writeAttribute(HTML.CLASS_ATTR, headerStyleClass, null); } if (facet != null) { RendererUtils.renderChild(facesContext, facet); } writer.endElement(HTML.TH_ELEM); } /** * Renders the footer facet for the given UIColumn. * @param facesContext the FacesContext. * @param writer the ResponseWriter. * @param uiColumn the UIComponent. * @param footerStyleClass the styleClass of the footer facet. * @param colspan the colspan for the tableData element in which the footer facet * will be wrapped. * @throws IOException */ protected void renderColumnFooterCell(FacesContext facesContext, ResponseWriter writer, UIColumn uiColumn, String footerStyleClass, int colspan) throws IOException { renderColumnFooterCell(facesContext, writer, uiColumn, uiColumn.getFooter(), footerStyleClass, colspan); } /** * Renders the footer facet for the given UIColumn. * @param facesContext the FacesContext. * @param writer the ResponseWriter. * @param uiComponent the UIComponent to render the facet for. * @param facet the UIComponent to render as facet. * @param footerStyleClass the styleClass of the footer facet. * @param colspan the colspan for the tableData element in which the footer facet * will be wrapped. * @throws IOException */ protected void renderColumnFooterCell(FacesContext facesContext, ResponseWriter writer, UIComponent uiComponent, UIComponent facet, String footerStyleClass, int colspan) throws IOException { writer.startElement(HTML.TD_ELEM, uiComponent); if (colspan > 1) { writer.writeAttribute(HTML.COLSPAN_ATTR, new Integer(colspan), null); } if (footerStyleClass != null) { writer.writeAttribute(HTML.CLASS_ATTR, footerStyleClass, null); } if (facet != null) { RendererUtils.renderChild(facesContext, facet); } writer.endElement(HTML.TD_ELEM); } /** * Gets the headerClass attribute of the given UIComponent. * @param component the UIComponent. * @return the headerClass attribute of the given UIComponent. */ protected static String getHeaderClass(UIComponent component) { if (component instanceof HtmlDataTable) { return ((HtmlDataTable) component).getHeaderClass(); } else { return (String) component.getAttributes().get(JSFAttr.HEADER_CLASS_ATTR); } } /** * Gets the footerClass attribute of the given UIComponent. * @param component the UIComponent. * @return the footerClass attribute of the given UIComponent. */ protected static String getFooterClass(UIComponent component) { if (component instanceof HtmlDataTable) { return ((HtmlDataTable) component).getFooterClass(); } else { return (String) component.getAttributes().get(JSFAttr.FOOTER_CLASS_ATTR); } } //------------------------------------------------------------- // Helper class Styles //------------------------------------------------------------- private static class StyleIterator implements Iterator { //~ Instance fields // ------------------------------------------------------------------------ private String[] _style; private int _idx = 0; //~ Constructors // --------------------------------------------------------------------------- StyleIterator(String styles) { _style = (styles == null) ? ArrayUtils.EMPTY_STRING_ARRAY : StringUtils.trim(StringUtils .splitShortString(styles, ',')); } /** * @see java.util.Iterator#hasNext() */ public boolean hasNext() { return _style.length > 0; } /** * @see java.util.Iterator#next() */ public Object next() { if(hasNext()) { return _style[_idx++ % _style.length]; } throw new NoSuchElementException("no style defined"); } /** * @see java.util.Iterator#remove() */ public void remove() { throw new UnsupportedOperationException("remove is not supported"); } public void reset() { _idx = 0; } } public void decode(FacesContext context, UIComponent component) { super.decode(context, component); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy