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

org.richfaces.renderkit.AbstractTableRenderer Maven / Gradle / Ivy

There is a newer version: 4.3.7.Final
Show newest version
/*
 * JBoss, Home of Professional Open Source
 * Copyright ${year}, Red Hat, Inc. and individual contributors
 * by the @authors tag. See the copyright.txt in the distribution for a
 * full listing of individual contributors.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software 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 software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */

package org.richfaces.renderkit;

import java.io.IOException;
import java.util.Iterator;

import javax.faces.application.ResourceDependencies;
import javax.faces.application.ResourceDependency;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;

import org.ajax4jsf.renderkit.RendererUtils.HTML;
import org.richfaces.component.Row;
import org.richfaces.component.UIDataTableBase;
import org.richfaces.component.util.HtmlUtil;

/**
 * @author Anton Belevich
 *
 */

@ResourceDependencies({
    @ResourceDependency(name = "richfaces-event.js")
})    
public abstract class AbstractTableRenderer extends AbstractTableBaseRenderer implements MetaComponentRenderer {
    
    public static final String HIDDEN_CONTAINER_ID =":sc"; 
    
    public abstract EncodeStrategy getHiddenContainerStrategy(UIDataTableBase dataTableBase);
    
    public boolean isColumnAttributeSet(UIDataTableBase table, String attributeName) {
        Iterator columns = table.columns();
        boolean result = false;
        while (columns.hasNext() && !result) {
            UIComponent component = columns.next();
            result = (component.isRendered() && (null != component.getValueExpression(attributeName)));
        }
        return result;
    }
    
    @Override
    public RowHolderBase createRowHolder(FacesContext context, UIComponent component, Object[] options) {
        RowHolder rowHolder = null;
        if(component instanceof UIDataTableBase) {
            rowHolder = new RowHolder(context, (UIDataTableBase)component);
            rowHolder.setUpdatePartial((Boolean)options[0]);
            rowHolder.setEncodeParentTBody((Boolean)options[1]);
        }    

        return rowHolder;
    }
    
    protected class SimpleHeaderEncodeStrategy implements EncodeStrategy {
        public void begin(ResponseWriter writer, FacesContext context,  UIComponent column, Object [] params)
            throws IOException {
        }

        public void end(ResponseWriter writer, FacesContext context, UIComponent column, Object [] params)
            throws IOException {
        }
    }
    
    protected void doDecode(FacesContext context, UIComponent component) {
        decodeSortingFiltering(context, component);
    }
    
    @Override
    protected void encodeRows(FacesContext facesContext, RowHolderBase rowHolder) {
        UIDataTableBase dataTableBase = (UIDataTableBase)rowHolder.getRow();

        String rowClass = getRowSkinClass();
        String cellClass = getCellSkinClass();
        String firstClass = getFirstRowSkinClass();

        rowClass = mergeStyleClasses(ROW_CLASS_KEY, rowClass, dataTableBase);
        cellClass = mergeStyleClasses(CELL_CLASS_KEY, cellClass, dataTableBase);
        firstClass = mergeStyleClasses(FIRST_ROW_CLASS_KEY, firstClass, dataTableBase);

        saveRowStyles(facesContext, dataTableBase.getClientId(facesContext), firstClass, rowClass, cellClass);

        super.encodeRows(facesContext, rowHolder);
    }

    protected boolean isEncodeHeaders(UIDataTableBase table) {
        return table.isColumnFacetPresent(UIDataTableBase.HEADER) || isColumnAttributeSet(table, "sortBy")
            || isColumnAttributeSet(table, "comparator")
            || isColumnAttributeSet(table, "filterBy");
    }

    protected int getColumnsCount(UIDataTableBase table) {
        // check for exact value in component
        Integer span = (Integer) table.getAttributes().get("columns");
        int count = (null != span && span.intValue() != Integer.MIN_VALUE) ? span.intValue()
            : getColumnsCount(table.columns());
        return count;
    }
    
    public void encodeTableStructure(ResponseWriter writer, FacesContext context, UIDataTableBase dataTable) throws IOException {
        //DataTableRenderer override this method   
    }
    
    public void encodeBeforeRows(ResponseWriter writer, FacesContext facesContext, UIDataTableBase dataTableBase, boolean encodeParentTBody, boolean partialUpdate) throws IOException {
    }
    
    public void encodeAfterRows(ResponseWriter writer, FacesContext facesContext, UIDataTableBase dataTableBase, boolean encodeParentTBody, boolean partialUpdate) throws IOException {
    }
    
    public abstract boolean encodeParentTBody(UIDataTableBase dataTableBase);
    
    public void encodeTableFacets(ResponseWriter writer, FacesContext context, UIDataTableBase dataTable) throws IOException {

        Object key = dataTable.getRowKey();
        dataTable.captureOrigValue(context);
        dataTable.setRowKey(context, null);
        
        encodeTableStructure(writer, context, dataTable);
        
        setupTableStartElement(context, dataTable);
        encodeHeaderFacet(writer, context, dataTable, false);
        setupTableStartElement(context, dataTable, HTML.TD_ELEM);
        encodeFooterFacet(writer, context, dataTable, false);
        dataTable.setRowKey(context, key);
        dataTable.restoreOrigValue(context);
    }
    
    public void encodeTableRows(ResponseWriter writer, FacesContext facesContext, UIDataTableBase dataTableBase,
        boolean encodePartialUpdate) throws IOException {
        
        int rowCount = dataTableBase.getRowCount();
       
        put(facesContext, dataTableBase.getClientId(facesContext) + CELL_ELEMENT_KEY, HTML.TD_ELEM);
        
        Object key = dataTableBase.getRowKey();
        dataTableBase.captureOrigValue(facesContext);
        dataTableBase.setRowKey(facesContext, null);
        
        boolean encodeParentTBody = encodeParentTBody(dataTableBase);
        encodeBeforeRows(writer, facesContext, dataTableBase, encodeParentTBody, encodePartialUpdate);

        if (rowCount > 0) {
            processRows(writer, facesContext, dataTableBase, new Object[] {encodePartialUpdate, encodeParentTBody});
        } else {
            int columns = getColumnsCount(dataTableBase.columns());

            writer.startElement(HTML.TR_ELEMENT, dataTableBase);
            writer.startElement(HTML.TD_ELEM, dataTableBase);
            writer.writeAttribute(HTML.COLSPAN_ATTRIBUTE, columns, null);

            String styleClass = (String) dataTableBase.getAttributes().get("noDataStyleClass");
            styleClass = styleClass != null ? getNoDataClass() + " " + styleClass : getNoDataClass();

            writer.writeAttribute(HTML.CLASS_ATTRIBUTE, styleClass, null);

            UIComponent noDataFacet = dataTableBase.getNoData();
            if (noDataFacet != null && noDataFacet.isRendered()) {
                noDataFacet.encodeAll(facesContext);
            } else {
                String noDataLabel = dataTableBase.getNoDataLabel();
                if (noDataLabel != null) {
                    writer.writeText(noDataLabel, "noDataLabel");
                }
            }

            writer.endElement(HTML.TD_ELEM);
            writer.endElement(HTML.TR_ELEMENT);
        }      
       
        
        encodeAfterRows(writer, facesContext, dataTableBase, encodeParentTBody, encodePartialUpdate);

        if(encodePartialUpdate) {
            String id = dataTableBase.getClientId(facesContext) + HIDDEN_CONTAINER_ID;
            partialStart(facesContext, id);
        }
        
        encodeHiddens(writer, facesContext, dataTableBase, new Object[]{encodeParentTBody});

        if(encodePartialUpdate) {
            partialEnd(facesContext);
        }

        dataTableBase.setRowKey(facesContext, key);
        dataTableBase.restoreOrigValue(facesContext);
    }
           
    protected void doEncodeChildren(ResponseWriter writer, FacesContext context, UIComponent component) throws IOException {
        if(component instanceof UIDataTableBase) {
            encodeTableRows(writer, context, (UIDataTableBase)component, false);
        }    
    }
    
    public void encodeTableStart(ResponseWriter writer, FacesContext context, UIDataTableBase component) throws IOException {
        writer.startElement(HTML.TABLE_ELEMENT, component);
        writer.writeAttribute(HTML.ID_ATTRIBUTE, component.getClientId(), null);
        String styleClass = getTableSkinClass();
        encodeStyleClass(writer, context, component, HTML.STYLE_CLASS_ATTR, styleClass);
    }
    
    protected void encodeHiddens(ResponseWriter writer, FacesContext facesContext, UIDataTableBase dataTableBase, Object [] params) throws IOException {
        EncodeStrategy encodeStrategy = getHiddenContainerStrategy(dataTableBase);
        if(encodeStrategy != null) {
            encodeStrategy.begin(writer, facesContext, dataTableBase, params);
            
            encodeClientScript(writer, facesContext, dataTableBase);
            encodeHiddenInput(writer, facesContext, dataTableBase);
            
            encodeStrategy.end(writer, facesContext, dataTableBase, params);
        }    
    }
    
    public void encodeTableEnd(ResponseWriter writer) throws IOException {
        writer.endElement(HTML.TABLE_ELEMENT);
    }
    
    public abstract void encodeClientScript(ResponseWriter writer, FacesContext context, UIDataTableBase component) throws IOException;
    
    public abstract void encodeHiddenInput(ResponseWriter writer, FacesContext context, UIDataTableBase component) throws IOException;
           
    public void encodeTableBodyStart(ResponseWriter writer, FacesContext facesContext, UIDataTableBase dataTableBase)
        throws IOException {
           
        writer.startElement(HTML.TBODY_ELEMENT, dataTableBase);
        String clientId = (dataTableBase.getRelativeRowIndex() < 0) ? dataTableBase.getClientId(facesContext) : dataTableBase.getRelativeClientId(facesContext);
       
        writer.writeAttribute(HTML.ID_ATTRIBUTE,  clientId + ":tb", null);
        writer.writeAttribute(HTML.CLASS_ATTRIBUTE, getTableSkinClass(), null);
        encodeStyle(writer, facesContext, dataTableBase, null);
    }
    
    public void encodeTableBodyEnd(ResponseWriter writer) throws IOException {
        writer.endElement(HTML.TBODY_ELEMENT);
    }

    public void encodeFooterFacet(ResponseWriter writer, FacesContext facesContext, UIDataTableBase dataTable, 
        boolean encodePartialUpdate) throws IOException {

        UIComponent footer = dataTable.getFooter();
        boolean columnFacetPresent = dataTable.isColumnFacetPresent("footer");

        if ((footer != null && footer.isRendered()) || columnFacetPresent) {
            boolean partialUpdateEncoded = false;

            boolean encodeTfoot = containsThead();
            if (encodeTfoot) {
                String footerClientId = dataTable.getClientId(facesContext) + ":tf";

                if (encodePartialUpdate) {
                    partialUpdateEncoded = true;
                    partialStart(facesContext, footerClientId);
                }

                writer.startElement(HTML.TFOOT_ELEMENT, dataTable);
                writer.writeAttribute(HTML.ID_ATTRIBUTE, footerClientId, null);
                writer.writeAttribute(HTML.CLASS_ATTRIBUTE, "rd-dt-tfoot", null);
            }
     
            int columns = getColumnsCount(dataTable);
            String id = dataTable.getClientId(facesContext);

            boolean encodePartialUpdateForChildren = (encodePartialUpdate && !partialUpdateEncoded);
            
            if (columnFacetPresent) {
                
                
                String rowClass =  getColumnFooterSkinClass();
                String cellClass = getColumnFooterCellSkinClass();
                String firstClass = getColumnFooterFirstSkinClass();
                
                rowClass = mergeStyleClasses("columnFooterClass", rowClass, dataTable);
                cellClass = mergeStyleClasses("columnFooterCellClass", cellClass, dataTable);
                firstClass = mergeStyleClasses("firstColumnFooterClass", firstClass, dataTable);
                                
                saveRowStyles(facesContext,id, firstClass, rowClass, cellClass);
                
                String targetId = id + ":cf";
                
                if (encodePartialUpdateForChildren) {
                    partialStart(facesContext, targetId);
                }
                
                writer.startElement(HTML.TR_ELEMENT, dataTable);
                writer.writeAttribute(HTML.ID_ATTRIBUTE, targetId, null);
                
                encodeStyleClass(writer, facesContext, dataTable, null, rowClass);
                encodeColumnFacet(facesContext, writer, dataTable, UIDataTableBase.FOOTER,columns, cellClass);
                writer.endElement(HTML.TR_ELEMENT);

                if (encodePartialUpdateForChildren) {
                    partialEnd(facesContext);
                }
            }

            if (footer != null && footer.isRendered()) {
                         
                String rowClass =  getFooterSkinClass();
                String cellClass = getFooterCellSkinClass();
                String firstClass = getFooterFirstSkinClass();
                
                rowClass = mergeStyleClasses("footerClass", rowClass, dataTable);
                cellClass = mergeStyleClasses("footerCellClass", cellClass, dataTable);
                firstClass = mergeStyleClasses("footerFirstClass", firstClass, dataTable);
                // TODO nick - rename method "encodeTableHeaderFacet"
                saveRowStyles(facesContext, id, firstClass, rowClass, cellClass);
                encodeTableFacet(facesContext, writer, id, columns, footer, UIDataTableBase.FOOTER, rowClass, cellClass, 
                    encodePartialUpdateForChildren);
            }

            if (encodeTfoot) {
                writer.endElement(HTML.TFOOT_ELEMENT);
                
                if (partialUpdateEncoded) {
                    partialEnd(facesContext);
                }
            }
        }

    }
    
    protected String mergeStyleClasses(String classAttribibute, String skinClass, UIComponent component) {
        String resultClass = skinClass; 
        
        String styleClass = null;
        if(classAttribibute != null && component != null ) {
            styleClass = (String)component.getAttributes().get(classAttribibute);
        }
             
        return HtmlUtil.concatClasses(resultClass, styleClass);
    }
    
    public void encodeHeaderFacet(ResponseWriter writer, FacesContext facesContext, UIDataTableBase dataTable, 
        boolean encodePartialUpdate) throws IOException {

        UIComponent header = dataTable.getHeader();
        boolean isEncodeHeaders = isEncodeHeaders(dataTable);

        boolean encodeThead = containsThead();

        if ((header != null && header.isRendered()) || isEncodeHeaders) {
            boolean partialUpdateEncoded = false;

            if (encodeThead) {
                String headerClientId = dataTable.getClientId(facesContext) + ":th";

                if (encodePartialUpdate) {
                    partialUpdateEncoded = true;
                    partialStart(facesContext, headerClientId);
                }
                
                writer.startElement(HTML.THEAD_ELEMENT, dataTable);
                writer.writeAttribute(HTML.ID_ATTRIBUTE, headerClientId, null);
                writer.writeAttribute(HTML.CLASS_ATTRIBUTE, "rf-dt-thead", null);
            }
            
            int columns = getColumnsCount(dataTable);
            String id = dataTable.getClientId(facesContext); 
            
            boolean encodePartialUpdateForChildren = (encodePartialUpdate && !partialUpdateEncoded);
            
            if (header != null && header.isRendered()) {
                                
                String rowClass =  getHeaderSkinClass();
                String cellClass = getHeaderCellSkinClass();
                String firstClass = getHeaderFirstSkinClass();
                
                rowClass = mergeStyleClasses("headerClass", rowClass, dataTable);
                cellClass = mergeStyleClasses("headerCellClass", cellClass, dataTable);
                firstClass = mergeStyleClasses("headerFirstClass", firstClass, dataTable);
                saveRowStyles(facesContext, id, firstClass, rowClass, cellClass);

                encodeTableFacet(facesContext, writer, id, columns, header, UIDataTableBase.HEADER, rowClass, cellClass, 
                    encodePartialUpdateForChildren);
            }

            if (isEncodeHeaders) {
                
                String rowClass =  getColumnHeaderSkinClass();
                String cellClass = getColumnHeaderCellSkinClass();
                String firstClass = getColumnHeaderFirstSkinClass();
                
                rowClass = mergeStyleClasses("columnHeaderClass", rowClass, dataTable);
                cellClass = mergeStyleClasses("columnHeaderCellClass", cellClass, dataTable);
                firstClass = mergeStyleClasses("columnHeaderFirstClass", firstClass, dataTable);
                saveRowStyles(facesContext, id, firstClass, rowClass, cellClass);
                 
                String targetId = id + ":ch";
                
                if (encodePartialUpdateForChildren) {
                    partialStart(facesContext, targetId);
                }
                
                writer.startElement(HTML.TR_ELEMENT, dataTable);
                writer.writeAttribute(HTML.ID_ATTRIBUTE, targetId, null);
                
                encodeStyleClass(writer, facesContext, dataTable, null, rowClass);
                
                encodeColumnFacet(facesContext, writer, dataTable, UIDataTableBase.HEADER, columns, cellClass);
                writer.endElement(HTML.TR_ELEMENT);
                
                if (encodePartialUpdateForChildren) {
                    partialEnd(facesContext);
                }
            }

            if (encodeThead) {
                writer.endElement(HTML.THEAD_ELEMENT);
                
                if (partialUpdateEncoded) {
                    partialEnd(facesContext);
                }
            }
        }

    }
    
    protected void encodeColumnFacet(FacesContext context, ResponseWriter writer, UIDataTableBase dataTableBase,  String facetName, int colCount, String cellClass) throws IOException {
        int tColCount = 0;
        String id  = dataTableBase.getClientId(context);
        String element = getCellElement(context, id);
        
        Iterator headers = dataTableBase.columns();
        
        while (headers.hasNext()) {
            UIComponent column = headers.next();
            
            
            if (!column.isRendered() || (column instanceof Row)) {
                continue;
            }

            Integer colspan = (Integer) column.getAttributes().get(HTML.COLSPAN_ATTRIBUTE);
            if (colspan != null && colspan.intValue() > 0) {
                tColCount += colspan.intValue();
            } else {
                tColCount++;
            }

            if (tColCount > colCount) {
                break;
            }

            writer.startElement(element, column);

            encodeStyleClass(writer, context, column, null, cellClass);

            writer.writeAttribute(HTML.SCOPE_ATTRIBUTE, HTML.COL_ELEMENT, null);
            getUtils().encodeAttribute(context, column, HTML.COLSPAN_ATTRIBUTE);
            
            EncodeStrategy strategy = getHeaderEncodeStrategy(column, facetName);
            if(strategy != null) {
                strategy.begin(writer, context, column, new String[] {facetName});
    
                UIComponent facet = column.getFacet(facetName);
                if (facet != null && facet.isRendered()) {
                    facet.encodeAll(context);
                }
                strategy.end(writer, context, column, new String[] {facetName});
            } 
            writer.endElement(element);
        }
    }
    
    protected void encodeTableFacet(FacesContext facesContext, ResponseWriter writer, String id, int columns, 
        UIComponent footer, String facetName, String rowClass, String cellClass, boolean encodePartialUpdate) throws IOException {
        
        boolean isColumnGroup = (footer instanceof Row);
        String element = getCellElement(facesContext, id);
        
        boolean partialUpdateEncoded = false;
        
        if (!isColumnGroup) {
            String targetId = id + ":" + facetName.charAt(0);

            if (encodePartialUpdate) {
                partialUpdateEncoded = true;
                partialStart(facesContext, targetId);
            }
            
            writer.startElement(HTML.TR_ELEMENT, footer);
            writer.writeAttribute(HTML.ID_ATTRIBUTE, targetId, null);

            encodeStyleClass(writer, facesContext, footer, null, rowClass);
            
            writer.startElement(element, footer);

            encodeStyleClass(writer, facesContext, footer, null, cellClass);

            if (columns > 0) {
                writer.writeAttribute(HTML.COLSPAN_ATTRIBUTE, String.valueOf(columns), null);
            }

            writer.writeAttribute(HTML.SCOPE_ATTRIBUTE, HTML.COLGROUP_ELEMENT, null);
        }    
        
        if (encodePartialUpdate && !partialUpdateEncoded) {
            partialStart(facesContext, footer.getClientId(facesContext));
        }
        
        footer.encodeAll(facesContext);
       
        if (encodePartialUpdate && !partialUpdateEncoded) {
            partialEnd(facesContext);
        }

        if (!isColumnGroup){
            writer.endElement(element);
            writer.endElement(HTML.TR_ELEMENT);
            
            if (partialUpdateEncoded) {
                partialEnd(facesContext);
            }
        }    
    }   
    
    public  abstract EncodeStrategy getHeaderEncodeStrategy(UIComponent column, String tableFacetName);
      
    public abstract boolean containsThead();
    
    public abstract String getTableSkinClass();
    
    public abstract String getFirstRowSkinClass();

    public abstract String getRowSkinClass();
        
    public abstract String getHeaderCellSkinClass();

    public abstract String getHeaderSkinClass();

    public abstract String getHeaderFirstSkinClass();
    
    public abstract String getColumnHeaderCellSkinClass();

    public abstract String getColumnHeaderSkinClass();
    
    public abstract String getColumnHeaderFirstSkinClass();

    public abstract String getFooterCellSkinClass();

    public abstract String getFooterSkinClass();
    
    public abstract String getFooterFirstSkinClass();

    public abstract String getColumnFooterCellSkinClass();

    public abstract String getColumnFooterSkinClass();
    
    public abstract String getColumnFooterFirstSkinClass();
    
    public abstract String getCellSkinClass();
    
    public abstract String getNoDataClass();

    protected abstract void setupTableStartElement(FacesContext context, UIComponent component);
    
    protected void setupTableStartElement(FacesContext context, UIComponent component, String elementName) {
        put(context, component.getClientId(context) + CELL_ELEMENT_KEY, elementName);
    }

    public void encodeMetaComponent(FacesContext context, UIComponent component, String metaComponentId)
        throws IOException {

        UIDataTableBase table = (UIDataTableBase) component;
        
        
        if (UIDataTableBase.HEADER.equals(metaComponentId)) {
            setupTableStartElement(context, component);
            encodeHeaderFacet(context.getResponseWriter(), context, table, true);
        } else if (UIDataTableBase.FOOTER.equals(metaComponentId)) {
            setupTableStartElement(context, component, HTML.TD_ELEM);
            encodeFooterFacet(context.getResponseWriter(), context, table, true);
        } else if(UIDataTableBase.BODY.equals(metaComponentId)) {
            setupTableStartElement(context, component, HTML.TD_ELEM);
            encodeTableRows(context.getResponseWriter(), context, table, true);
        } else {
            throw new IllegalArgumentException("Unsupported metaComponentIdentifier: " + metaComponentId);
        }
    }
    
    protected void partialStart(FacesContext facesContext, String id) throws IOException {
        facesContext.getPartialViewContext().getPartialResponseWriter().startUpdate(id);
    }
    
    protected void partialEnd(FacesContext facesContext) throws IOException {
        facesContext.getPartialViewContext().getPartialResponseWriter().endUpdate();   
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy