/* * 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.Map; import javax.faces.FacesException; 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.model.DataVisitResult; import org.richfaces.cdk.annotations.JsfRenderer; import org.richfaces.component.AbstractDataGrid; import org.richfaces.component.Row; import org.richfaces.component.UIDataTableBase; import org.richfaces.component.attribute.ColumnProps; import org.richfaces.component.util.HtmlUtil; /** * @author Anton Belevich * */ @JsfRenderer(type = "org.richfaces.DataGridRenderer", family = AbstractDataGrid.COMPONENT_FAMILY) @ResourceDependencies({ @ResourceDependency(library = "javax.faces", name = "jsf.js"), @ResourceDependency(library = "org.richfaces", name = "jquery.js"), @ResourceDependency(library = "org.richfaces", name = "richfaces.js"), @ResourceDependency(library = "org.richfaces", name = "richfaces-queue.reslib"), @ResourceDependency(library = "org.richfaces", name = "richfaces-base-component.js"), @ResourceDependency(library = "org.richfaces", name = "richfaces-event.js"), @ResourceDependency(library = "org.richfaces", name = "datagrid.ecss") }) public class DataGridRenderer extends AbstractRowsRenderer implements MetaComponentRenderer { private static final EncodeStrategy THEAD = new EncodeStrategy() { public void begin(ResponseWriter writer, FacesContext context, UIComponent component, Object[] params) throws IOException { String clientId = component.getClientId(context) + ":h"; boolean partial = (Boolean) (Boolean) params[0]; if (partial) { context.getPartialViewContext().getPartialResponseWriter().startUpdate(clientId); } writer.startElement(HtmlConstants.THEAD_ELEMENT, component); writer.writeAttribute(HtmlConstants.ID_ATTRIBUTE, clientId, null); writer.writeAttribute(HtmlConstants.CLASS_ATTRIBUTE, "rf-dg-thead", null); writer.startElement(HtmlConstants.TR_ELEMENT, component); writer.writeAttribute(HtmlConstants.CLASS_ATTRIBUTE, HtmlUtil.concatClasses("rf-dg-h ", ((ColumnProps) component).getHeaderClass()), null); writer.startElement(HtmlConstants.TH_ELEM, component); writer.writeAttribute(HtmlConstants.CLASS_ATTRIBUTE, "rf-dg-h-c", null); int columns = (Integer) component.getAttributes().get("columns"); if (columns > 0) { writer.writeAttribute(HtmlConstants.COLSPAN_ATTRIBUTE, columns, null); } } public void end(ResponseWriter writer, FacesContext context, UIComponent component, Object[] params) throws IOException { writer.endElement(HtmlConstants.TH_ELEM); writer.endElement(HtmlConstants.TR_ELEMENT); writer.endElement(HtmlConstants.THEAD_ELEMENT); boolean partial = (Boolean) (Boolean) params[0]; if (partial) { context.getPartialViewContext().getPartialResponseWriter().endUpdate(); } } }; private static final EncodeStrategy TFOOT = new EncodeStrategy() { public void begin(ResponseWriter writer, FacesContext context, UIComponent component, Object[] params) throws IOException { String clientId = component.getClientId(context) + ":f"; boolean partial = (Boolean) (Boolean) params[0]; if (partial) { context.getPartialViewContext().getPartialResponseWriter().startUpdate(clientId); } writer.startElement(HtmlConstants.TFOOT_ELEMENT, component); writer.writeAttribute(HtmlConstants.ID_ATTRIBUTE, clientId, null); writer.writeAttribute(HtmlConstants.CLASS_ATTRIBUTE, "rf-dg-tfoot", null); writer.startElement(HtmlConstants.TR_ELEMENT, component); writer.writeAttribute(HtmlConstants.CLASS_ATTRIBUTE, HtmlUtil.concatClasses("rf-dg-f ", ((ColumnProps) component).getFooterClass()), null); writer.startElement(HtmlConstants.TD_ELEM, component); writer.writeAttribute(HtmlConstants.CLASS_ATTRIBUTE, "rf-dg-f-c", null); int columns = (Integer) component.getAttributes().get("columns"); if (columns > 0) { writer.writeAttribute(HtmlConstants.COLSPAN_ATTRIBUTE, columns, null); } } public void end(ResponseWriter writer, FacesContext context, UIComponent component, Object[] params) throws IOException { writer.endElement(HtmlConstants.TD_ELEM); writer.endElement(HtmlConstants.TR_ELEMENT); writer.endElement(HtmlConstants.TFOOT_ELEMENT); boolean partial = (Boolean) (Boolean) params[0]; if (partial) { context.getPartialViewContext().getPartialResponseWriter().endUpdate(); } } }; private static final EncodeStrategy CAPTION = new EncodeStrategy() { public void begin(ResponseWriter writer, FacesContext context, UIComponent component, Object[] params) throws IOException { writer.startElement(HtmlConstants.CAPTION_ELEMENT, component); writer.writeAttribute(HtmlConstants.CLASS_ATTRIBUTE, "rf-dg-cap", null); } public void end(ResponseWriter writer, FacesContext context, UIComponent component, Object[] params) throws IOException { writer.endElement(HtmlConstants.CAPTION_ELEMENT); } }; private static final EncodeStrategy NODATA = new EncodeStrategy() { public void begin(ResponseWriter writer, FacesContext context, UIComponent component, Object[] params) throws IOException { writer.startElement(HtmlConstants.TR_ELEMENT, component); writer.writeAttribute(HtmlConstants.CLASS_ATTRIBUTE, "rf-dg-nd", null); writer.startElement(HtmlConstants.TD_ELEM, component); writer.writeAttribute(HtmlConstants.CLASS_ATTRIBUTE, "rf-dg-nd-c", null); int columns = (Integer) component.getAttributes().get("columns"); if (columns > 0) { writer.writeAttribute(HtmlConstants.COLSPAN_ATTRIBUTE, columns, null); } } public void end(ResponseWriter writer, FacesContext context, UIComponent component, Object[] params) throws IOException { writer.endElement(HtmlConstants.TD_ELEM); writer.endElement(HtmlConstants.TR_ELEMENT); } }; @Override public void encodeRow(ResponseWriter writer, FacesContext facesContext, RowHolderBase rowHolder) throws IOException { AbstractDataGrid dataGrid = (AbstractDataGrid) rowHolder.getRow(); int columns = dataGrid.getColumns(); int processCell = rowHolder.getProcessCell(); if (columns > 0 && (processCell % columns == 0)) { if (processCell != 0) { writer.endElement(HtmlConstants.TR_ELEMENT); rowHolder.resetProcessCell(); processCell = rowHolder.getProcessCell(); } writer.startElement(HtmlConstants.TR_ELEMENT, dataGrid); writer.writeAttribute(HtmlConstants.CLASS_ATTRIBUTE, HtmlUtil.concatClasses("rf-dg-r ", getRowClass(rowHolder)), null); rowHolder.nextRow(); } writer.startElement(HtmlConstants.TD_ELEM, dataGrid); writer.writeAttribute(HtmlConstants.CLASS_ATTRIBUTE, HtmlUtil.concatClasses("rf-dg-c ", getColumnClass(rowHolder, processCell)), null); renderChildren(facesContext, dataGrid); writer.endElement(HtmlConstants.TD_ELEM); } public void encodeHeader(ResponseWriter writer, FacesContext facesContext, AbstractDataGrid dataGrid, boolean partial) throws IOException { UIComponent headerFacet = dataGrid.getHeader(); encodeFacet(writer, facesContext, headerFacet, THEAD, dataGrid, new Object[] { partial }); } public void encodeFooter(ResponseWriter writer, FacesContext facesContext, AbstractDataGrid dataGrid, boolean partial) throws IOException { UIComponent footerFacet = dataGrid.getFooter(); encodeFacet(writer, facesContext, footerFacet, TFOOT, dataGrid, new Object[] { partial }); } public void encodeCaption(ResponseWriter writer, FacesContext facesContext, AbstractDataGrid dataGrid) throws IOException { UIComponent captionFacet = dataGrid.getCaption(); encodeFacet(writer, facesContext, captionFacet, CAPTION, dataGrid, null); } public void encodeNoData(ResponseWriter writer, FacesContext facesContext, AbstractDataGrid dataGrid) throws IOException { UIComponent noDataFacet = dataGrid.getNoData(); encodeFacet(writer, facesContext, noDataFacet, NODATA, dataGrid, null); } public void encodeFacet(ResponseWriter writer, FacesContext facesContext, UIComponent facet, EncodeStrategy strategy, AbstractDataGrid dataGrid, Object[] params) throws IOException { if (facet != null && facet.isRendered()) { strategy.begin(writer, facesContext, dataGrid, params); facet.encodeAll(facesContext); strategy.end(writer, facesContext, dataGrid, params); } } public void encodeTBody(ResponseWriter writer, FacesContext facesContext, AbstractDataGrid dataGrid, boolean partial) throws IOException { String clientId = dataGrid.getClientId(facesContext) + ":dgb"; if (partial) { facesContext.getPartialViewContext().getPartialResponseWriter().startUpdate(clientId); } writer.startElement(HtmlConstants.TBODY_ELEMENT, dataGrid); writer.writeAttribute(HtmlConstants.ID_ATTRIBUTE, clientId, null); writer.writeAttribute(HtmlConstants.CLASS_ATTRIBUTE, "rf-dg-body", null); if (dataGrid.getRowCount() > 0) { processRows(writer, facesContext, dataGrid, null); } else { encodeNoData(writer, facesContext, dataGrid); } writer.endElement(HtmlConstants.TBODY_ELEMENT); if (partial) { facesContext.getPartialViewContext().getPartialResponseWriter().endUpdate(); } } @Override protected void doEncodeChildren(ResponseWriter writer, FacesContext facesContext, UIComponent component) throws IOException { AbstractDataGrid dataGrid = (AbstractDataGrid) component; writer.startElement(HtmlConstants.TABLE_ELEMENT, dataGrid); writer.writeAttribute(HtmlConstants.ID_ATTRIBUTE, dataGrid.getClientId(facesContext), null); Map<String, Object> attributes = dataGrid.getAttributes(); String classes = concatClasses("rf-dg", attributes.get(HtmlConstants.STYLE_CLASS_ATTR)); writer.writeAttribute(HtmlConstants.CLASS_ATTRIBUTE, classes, null); RenderKitUtils.renderAttribute(facesContext, "style", attributes.get(HtmlConstants.STYLE_ATTRIBUTE)); RenderKitUtils.renderAttribute(facesContext, HtmlConstants.TITLE_ATTRIBUTE, attributes.get(HtmlConstants.TITLE_ATTRIBUTE)); encodeCaption(writer, facesContext, dataGrid); encodeHeader(writer, facesContext, dataGrid, false); encodeFooter(writer, facesContext, dataGrid, false); encodeTBody(writer, facesContext, dataGrid, false); writer.endElement(HtmlConstants.TABLE_ELEMENT); } @Override public RowHolderBase createRowHolder(FacesContext context, UIComponent component, Object[] options) { return new RowHolder(context, (AbstractDataGrid) component); } @Override protected Class<? extends UIComponent> getComponentClass() { return AbstractDataGrid.class; } public void encodeMetaComponent(FacesContext context, UIComponent component, String metaComponentId) throws IOException { AbstractDataGrid table = (AbstractDataGrid) component; if (UIDataTableBase.HEADER.equals(metaComponentId)) { encodeHeader(context.getResponseWriter(), context, table, true); } else if (UIDataTableBase.FOOTER.equals(metaComponentId)) { encodeFooter(context.getResponseWriter(), context, table, true); } else if (UIDataTableBase.BODY.equals(metaComponentId)) { encodeTBody(context.getResponseWriter(), context, table, true); } else { throw new IllegalArgumentException("Unsupported metaComponentIdentifier: " + metaComponentId); } } public void decodeMetaComponent(FacesContext context, UIComponent component, String metaComponentId) { throw new UnsupportedOperationException(); } @Override protected void doCleanup(FacesContext context, RowHolderBase rowHolder) throws IOException { ResponseWriter writer = context.getResponseWriter(); AbstractDataGrid dataGrid = (AbstractDataGrid) rowHolder.getRow(); int cell = rowHolder.getProcessCell(); int columns = dataGrid.getColumns(); int rest = columns - cell; for (int i = 0; i < rest; i++) { writer.startElement(HtmlConstants.TD_ELEM, dataGrid); writer.writeAttribute(HtmlConstants.CLASS_ATTRIBUTE, "rf-dg-c", null); writer.endElement(HtmlConstants.TD_ELEM); } writer.endElement(HtmlConstants.TR_ELEMENT); } public DataVisitResult process(FacesContext facesContext, Object rowKey, Object argument) { RowHolderBase holder = (RowHolderBase) argument; Row row = holder.getRow(); row.setRowKey(facesContext, rowKey); try { ResponseWriter writer = facesContext.getResponseWriter(); encodeRow(writer, facesContext, holder); } catch (IOException e) { throw new FacesException(e); } holder.nextCell(); return DataVisitResult.CONTINUE; } @Override public void encodeFakeRow(FacesContext facesContext, RowHolderBase rowHolder) throws IOException { UIComponent component = (UIComponent) rowHolder.getRow(); ResponseWriter writer = facesContext.getResponseWriter(); writer.startElement(HtmlConstants.TR_ELEMENT, component); writer.writeAttribute(HtmlConstants.STYLE_ATTRIBUTE, "display:none", null); writer.startElement(HtmlConstants.TD_ELEM, component); writer.endElement(HtmlConstants.TD_ELEM); writer.endElement(HtmlConstants.TR_ELEMENT); } }