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

org.apache.myfaces.custom.newspaper.HtmlNewspaperTableRenderer Maven / Gradle / Ivy

Go to download

JSF components and utilities that can be used with any JSF implementation. This library is based on the JSF1.1 version of Tomahawk, but with minor source code and build changes to take advantage of JSF2.1 features. A JSF2.1 implementation is required to use this version of the Tomahawk library.

The newest version!
/*
 * 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.behavior.ClientBehavior;
import javax.faces.component.behavior.ClientBehaviorHolder;
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.renderkit.html.util.ResourceUtils;
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 java.util.Map;

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;
        
        Map> behaviors = null;
        if (uiComponent instanceof ClientBehaviorHolder)
        {
            behaviors = ((ClientBehaviorHolder) uiComponent).getClientBehaviors();
            if (!behaviors.isEmpty())
            {
                ResourceUtils.renderDefaultJsfJsInlineIfNecessary(facesContext, facesContext.getResponseWriter());
            }
        }
        
        // write out the table start tag
        HtmlRendererUtils.writePrettyLineSeparator(facesContext);
        writer.startElement(HTML.TABLE_ELEM, newspaperTable);
        writer.writeAttribute(HTML.ID_ATTR, newspaperTable.getClientId(facesContext), null);
        
        if (behaviors != null && !behaviors.isEmpty())
        {
            HtmlRendererUtils.renderBehaviorizedEventHandlers(facesContext, writer, newspaperTable, behaviors);
            HtmlRendererUtils.renderHTMLAttributes(writer, newspaperTable, HTML.TABLE_PASSTHROUGH_ATTRIBUTES_WITHOUT_EVENTS); 
            
        }
        else
        {
            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 - 2024 Weber Informatics LLC | Privacy Policy