/**
* License Agreement.
*
* Rich Faces - Natural Ajax for Java Server Faces (JSF)
*
* Copyright (C) 2007 Exadel, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation.
*
* This library 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 library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package org.richfaces.renderkit.html;
import java.io.IOException;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import javax.faces.FacesException;
import javax.faces.component.UIColumn;
import javax.faces.component.UIComponent;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import org.ajax4jsf.context.AjaxContext;
import org.ajax4jsf.javascript.JSFunction;
import org.ajax4jsf.model.DataVisitor;
import org.ajax4jsf.renderkit.AjaxRendererUtils;
import org.ajax4jsf.renderkit.ComponentVariables;
import org.ajax4jsf.renderkit.ComponentsVariableResolver;
import org.ajax4jsf.renderkit.HeaderResourcesRendererBase;
import org.ajax4jsf.renderkit.RendererBase;
import org.ajax4jsf.renderkit.RendererUtils.HTML;
import org.ajax4jsf.resource.InternetResource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.richfaces.component.UIScrollableDataTable;
import org.richfaces.component.util.ColumnUtil;
import org.richfaces.event.scroll.ScrollEvent;
import org.richfaces.event.sort.SortEvent;
import org.richfaces.model.SortField;
import org.richfaces.model.SortOrder;
import org.richfaces.renderkit.CompositeRenderer;
import org.richfaces.renderkit.RendererContributor;
import org.richfaces.renderkit.ScriptOptions;
import org.richfaces.utils.TemplateLoader;
/**
* @author Anton Belevich
*
*/
public abstract class ScrollableDataTableBaseRenderer extends HeaderResourcesRendererBase {
private class CompositeRendererEnabler extends CompositeRenderer {
public CompositeRendererEnabler() {
addContributor(new SelectionRendererContributor());
}
@Override
protected Class<? extends UIComponent> getComponentClass() {
return ScrollableDataTableBaseRenderer.this.getComponentClass();
}
@Override
public void mergeScriptOptions(ScriptOptions scriptOptions,
FacesContext context, UIComponent component) {
super.mergeScriptOptions(scriptOptions, context, component);
}
@Override
public String getScriptContributions(String varString,
FacesContext context, UIComponent component) {
return super.getScriptContributions(varString, context, component);
}
@Override
public RendererContributor[] getContributors() {
return super.getContributors();
}
@Override
public InternetResource[] getScripts() {
return super.getScripts();
}
@Override
public InternetResource[] getStyles() {
return super.getStyles();
}
}
public static final String PARTIAL_UPDATE = "partialUpdate";
public static final String UPDATE_HEADER = "updateHeader";
public static final String FOOTER_PART = "footer";
public static final String HEADER_PART = "header";
private static final String COLUMN_FROZEN_TYPE = "frozen";
private static final String COLUMN_NORMAL_TYPE = "normal";
private static final String PERSENTAGE_SUPPORT_ERROR_MSG = "columnsWidth property: Percentage values are not supported";
private RendererBase cellTemplate = null;
private RendererBase headerCellTemplate = null;
private RendererBase footerCellTemplate = null;
private RendererBase headerItselfTemplate = null;
private CompositeRendererEnabler composite = new CompositeRendererEnabler();
private final Log log = LogFactory.getLog(ScrollableDataTableBaseRenderer.class);
private final ColumnVisitor columnsWidthCounter = new ColumnVisitor(){
public int visit(FacesContext context, UIComponent column, ResponseWriter writer, ScrollableDataTableRendererState state) throws IOException {
int prevWidth = 0;
int width = 0;
String widthPx = getColumnWidth(column);
widthPx = getFormattedWidth(widthPx);
prevWidth = state.getSumWidth();
width = prevWidth + Integer.parseInt(widthPx);
state.setSumWidth(width);
return 1;
}
};
private final ColumnVisitor headerCellRenderer = new ExtendedColumnVisitor(){
public void renderContent(FacesContext context, UIComponent column, ResponseWriter writer, ScrollableDataTableRendererState state) throws IOException {
int cell_index = state.getCellIndex();
String client_id = state.getClientId();
state.addId(column.getId());
headerCellTemplate = getHeaderCellTemplate();
ComponentVariables variables =
ComponentsVariableResolver.getVariables(headerCellTemplate, column);
String widthPx = getColumnWidth(column);
widthPx = getFormattedWidth(widthPx);
int width = Integer.parseInt(widthPx);
int sepOffset = 0;
if(state.isFrozenColumn()){
sepOffset = state.getSepOffset().intValue() + width;
}else{
sepOffset = state.getSepOffset().intValue() + width + 1;
state.setSepOffset(new Integer(sepOffset));
}
variables.setVariable("client_id", client_id);
variables.setVariable("cell_index", new Integer(cell_index));
variables.setVariable("sepOffset", new Integer(sepOffset));
variables.setVariable("headerColumnClass", state.getColumnClass());
Boolean sorting = getColumnSorting(state.getGrid(), column.getId());
if (sorting != null) {
if (sorting.booleanValue()) {
variables.setVariable("headerColumnSortClass", "rich-sdt-header-sort-up");
} else {
variables.setVariable("headerColumnSortClass", "rich-sdt-header-sort-down");
}
}
//variables.setVariable("headerCellClass", state.get);
headerCellTemplate.encodeBegin(context, column);
headerRenderer.visit(context, column, writer, state);
headerCellTemplate.encodeEnd(context, column);
}
};
private final ColumnVisitor styleRenderer = new ColumnVisitor(){
public int visit(FacesContext context, UIComponent column, ResponseWriter writer, ScrollableDataTableRendererState state) throws IOException {
int cell_index = state.getCellIndex();
String widthPx = getColumnWidth(column);
widthPx = getFormattedWidth(widthPx);
int width = Integer.parseInt(widthPx);
writer.writeText("#" + getNormalizedId(context, state.getGrid())+ " .dr-sdt-c-" + cell_index + " {", "width");
writer.writeText("width: " + width + "px;", "width");
writer.writeText("}", "width");
return 0;
}
};
private final ColumnVisitor headerRenderer = new ColumnVisitor() {
public int visit(FacesContext context, UIComponent column,
ResponseWriter writer, ScrollableDataTableRendererState state)
throws IOException {
ComponentVariables variables =
ComponentsVariableResolver.getVariables(getHeaderItselfTemplate(), column);
int cell_index = state.getCellIndex();
String client_id = state.getClientId();
Boolean sorting = getColumnSorting(state.getGrid(), column.getId());
if (sorting != null) {
if (sorting.booleanValue()) {
variables.setVariable("sortAscending", Boolean.TRUE);
} else {
variables.setVariable("sortDescending", Boolean.TRUE);
}
}
variables.setVariable("client_id", client_id);
variables.setVariable("cell_index", new Integer(cell_index));
getHeaderItselfTemplate().encodeBegin(context, column);
UIComponent header = column.getFacet(HEADER_PART);
if(header != null){
renderChild(context, header);
}
getHeaderItselfTemplate().encodeEnd(context, column);
return 0;
}
};
private final ColumnVisitor footerCellRenderer = new ExtendedColumnVisitor(){
public void renderContent(FacesContext context, UIComponent column, ResponseWriter writer, ScrollableDataTableRendererState state) throws IOException {
int cell_index = state.getCellIndex();
String client_id = state.getClientId();
footerCellTemplate = getFooterCellTemplate();
ComponentVariables variables = ComponentsVariableResolver.getVariables(footerCellTemplate, column);
variables.setVariable("client_id", client_id);
variables.setVariable("cell_index", new Integer(cell_index));
variables.setVariable("footerColumnClass", state.getColumnClass());
Boolean sorting = getColumnSorting(state.getGrid(), column.getId());
if (sorting != null) {
if (sorting.booleanValue()) {
variables.setVariable("footerColumnSortClass", "rich-sdt-footer-sort-up");
} else {
variables.setVariable("footerColumnSortClass", "rich-sdt-footer-sort-down");
}
}
UIComponent component = column.getFacet(FOOTER_PART);
if(component != null){
footerCellTemplate.encodeBegin(context, column);
renderChild(context, component);
footerCellTemplate.encodeEnd(context, column);
}
}
};
private final ColumnVisitor cellRenderer = new ExtendedColumnVisitor(){
public void renderContent(FacesContext context, UIComponent column, ResponseWriter writer, ScrollableDataTableRendererState state) throws IOException {
String cell_id = state.getRowIndex()+ "_" + state.getCellIndex();
if (log.isTraceEnabled()) {
log.trace("cell_index: " + cell_id);
}
String client_id = state.getClientId();
int cell_index = state.getCellIndex();
cellTemplate = getCellTemplate();
ComponentVariables variables = ComponentsVariableResolver.getVariables(cellTemplate, column);
variables.setVariable("cell_id",cell_id);
variables.setVariable("client_id", client_id);
variables.setVariable("cell_index", new Integer(cell_index));
variables.setVariable("columnClass", state.getColumnClass());
Boolean sorting = getColumnSorting(state.getGrid(), column.getId());
if (sorting != null) {
if (sorting.booleanValue()) {
variables.setVariable("columnSortClass", "rich-sdt-column-sort-up");
} else {
variables.setVariable("columnSortClass", "rich-sdt-column-sort-down");
}
}
cellTemplate.encodeBegin(context, column);
if(!state.isFake()) {
renderChildren(context, column);
}
cellTemplate.encodeEnd(context, column);
}
};
private final DataVisitor rowsRenderer = new DataVisitor(){
public void process(FacesContext context, Object rowKey, Object argument) throws IOException {
ScrollableDataTableRendererState state = (ScrollableDataTableRendererState)argument;
UIScrollableDataTable grid = state.getGrid();
grid.setRowKey(rowKey);
if(grid.isRowAvailable() || state.isFake()){
String row_id;
int index = state.getRowIndex();
//state.setRowIndex(index);
String baseClientId = grid.getBaseClientId(context);
if(state.isFrozenPart()){
row_id = baseClientId + ":f:" + index;
}else{
row_id = baseClientId + ":n:" + index;
}
ResponseWriter writer = context.getResponseWriter();
writer.startElement(HTML.TR_ELEMENT, grid);
state.setFrozenColumnCount(ScrollableDataTableUtils.getFrozenColumnsCount(grid));
getUtils().writeAttribute(writer, "id",row_id);
getUtils().writeAttribute(writer, "class","dr-sdt-rb rich-sdt-row " + state.getRowClass());
addRowJavascriptEvents(writer, grid);
if (log.isDebugEnabled()) {
log.debug("rowIndex : " + index);
}
ColumnWalker.iterateOverColumns(context, grid, cellRenderer, writer, state);
if(!state.isFrozenPart()){
writer.startElement("td", grid);
getUtils().writeAttribute(writer, "class","dr-sdt-bc dr-sdt-c-f rich-sdt-column-cell " + state.getColumnClass(state.getCellIndex()));
writer.startElement(HTML.DIV_ELEM, grid);
getUtils().writeAttribute(writer, "class","dr-sdt-cbody");
writer.endElement(HTML.DIV_ELEM);
writer.endElement("td");
}
writer.endElement(HTML.TR_ELEMENT);
state.nextRow();
state.setCellIndex(0);
}
}
};
private final DataVisitor ajaxRowsRenderer = new DataVisitor(){
public void process(FacesContext context, Object rowKey, Object argument) throws IOException {
int columnsCount = 0;
boolean frozenTRRendered = false;
boolean normalTRRendered = false;
ScrollableDataTableRendererState state = (ScrollableDataTableRendererState)argument;
AjaxContext ajaxContext = state.getAjaxContext();
ajaxContext.getResponseData();
UIScrollableDataTable grid = state.getGrid();
Collection<String> collection = grid.getResponseData();
grid.setRowKey(rowKey);
ResponseWriter writer = context.getResponseWriter();
state.setFrozenColumnCount(ScrollableDataTableUtils.getFrozenColumnsCount(grid));
String row_id = null;
String baseClientId = grid.getBaseClientId(context);
for (Iterator<UIComponent> iter = grid.getChildren().iterator(); iter.hasNext(); ) {
UIComponent kid = (UIComponent) iter.next();
if (kid.isRendered()) {
if (kid instanceof UIColumn){
if(state.isFrozenColumn() && !frozenTRRendered && state.getFrozenColumnCount() > 0){
state.setFrozenPart(true);
frozenTRRendered = true;
row_id = baseClientId + ":f:" + state.getRowIndex();
writer.startElement("tr", grid);
getUtils().writeAttribute(writer, "class","dr-sdt-rb rich-sdt-row " + state.getRowClass());
getUtils().writeAttribute(writer,"id",row_id);
addRowJavascriptEvents(writer, grid);
collection.add(row_id);
}else if(!state.isFrozenColumn() && !normalTRRendered){
writeNormalTr(frozenTRRendered, state, grid, collection,
writer, baseClientId);
normalTRRendered = true;
}
columnsCount += cellRenderer.visit(context, kid, writer, state);
// columnsCount += cellRenderer.visit(context, column, writer, state);
state.nextCell();
}
}
}
if(!normalTRRendered){
writeNormalTr(frozenTRRendered, state, grid, collection,
writer, baseClientId);
}
writer.startElement("td", grid);
getUtils().writeAttribute(writer, "class","dr-sdt-bc dr-sdt-c-f rich-sdt-column-cell " + state.getColumnClass(state.getCellIndex()));
writer.startElement(HTML.DIV_ELEM, grid);
getUtils().writeAttribute(writer, "class","dr-sdt-cbody");
writer.endElement(HTML.DIV_ELEM);
writer.endElement("td");
writer.endElement("tr");
state.setCellIndex(0);
state.nextRow();
}
private void writeNormalTr(boolean frozenTRRendered,
ScrollableDataTableRendererState state,
UIScrollableDataTable grid, Collection<String> collection,
ResponseWriter writer, String baseClientId) throws IOException {
String row_id;
if(frozenTRRendered){
writer.endElement("tr");
}
state.setFrozenPart(false);
row_id = baseClientId + ":n:" + state.getRowIndex();
writer.startElement("tr", grid);
getUtils().writeAttribute(writer,"id",row_id);
getUtils().writeAttribute(writer, "class","dr-sdt-rb rich-sdt-row " + state.getRowClass());
addRowJavascriptEvents(writer, grid);
collection.add(row_id);
}
};
@Override
protected InternetResource[] getScripts() {
return composite.getScripts();
}
@Override
protected InternetResource[] getStyles() {
return composite.getStyles();
}
// temporary solution RF-957
public String getFormattedWidth(String receivedWidth ) throws IOException{
String formattedWidth = receivedWidth;
if(formattedWidth.endsWith("%")){
throw new FacesException(PERSENTAGE_SUPPORT_ERROR_MSG);
}else if(formattedWidth.endsWith("px")){
formattedWidth = formattedWidth.substring(0,formattedWidth.indexOf("px"));
}
return formattedWidth;
}
@Override
protected Class<? extends UIComponent> getComponentClass() {
return UIScrollableDataTable.class;
}
public static String getJavaScriptVarName(FacesContext context, UIScrollableDataTable grid) {
String name = grid.getScriptVar();
if (name == null) {
String id = grid.getBaseClientId(context);
name = "Richfaces_ScrollableGrid_" + id.replaceAll("[^A-Za-z0-9_]", "_");
}
return "window." + name;
}
public static String getNormalizedId(FacesContext context, UIScrollableDataTable grid) {
return grid.getBaseClientId(context).replaceAll("[^A-Za-z0-9_]", "_");
}
public String createClientScrollableGrid(FacesContext context, UIScrollableDataTable grid) {
ScrollableDataTableOptions options = new ScrollableDataTableOptions(grid);
options.addOption("normalizedId", getNormalizedId(context, grid));
composite.mergeScriptOptions(options, context, grid);
JSFunction function = new JSFunction("new ClientUI.controls.grid.ScrollableGrid");
function.addParameter(options);
return function.toScript();
}
protected String getScriptContributions(FacesContext context, UIScrollableDataTable grid) {
return composite.getScriptContributions(getJavaScriptVarName(context, grid), context, grid);
}
public boolean getRendersChildren() {
return true;
}
public void renderGridBody(FacesContext context, UIScrollableDataTable grid, boolean isFrozen) throws IOException{
final ScrollableDataTableRendererState state = ScrollableDataTableRendererState.getRendererState(context);
if(isFrozen){
state.setColumType(COLUMN_FROZEN_TYPE);
}else{
state.setColumType(COLUMN_NORMAL_TYPE);
}
if (log.isTraceEnabled()) {
log.trace("ScrollableDataTableBaseRenderer.renderGridBody(context, grid, isFrozen)");
}
state.setFrozenColumnCount(ScrollableDataTableUtils.getFrozenColumnsCount(grid));
state.setFrozenPart(isFrozen);
state.setClientId(grid.getClientId(context));
if (!isFrozen || state.getFrozenColumnCount() > 0) {
grid.walk(context, rowsRenderer, state);
int fakeRowsCount = grid.getRows() - grid.getRowCount();
state.setFake(true);
for (int i = 0; i < fakeRowsCount; i++) {
rowsRenderer.process(context, null, state);
}
state.setFake(false);
}
state.setRowIndex(ScrollableDataTableUtils.getClientRowIndex(grid));
grid.setRowKey(null);
}
public void renderHeaders(FacesContext context, UIScrollableDataTable grid, boolean isFrozen)throws IOException{
ResponseWriter writer = context.getResponseWriter();
final ScrollableDataTableRendererState state = ScrollableDataTableRendererState.getRendererState(context);
if(isFrozen){
state.setColumType(COLUMN_FROZEN_TYPE);
}else{
state.setColumType(COLUMN_NORMAL_TYPE);
}
state.setClientId(grid.getClientId(context));
state.setPart(HEADER_PART);
state.setFrozenColumnCount(ScrollableDataTableUtils.getFrozenColumnsCount(grid));
state.setFrozenPart(isFrozen);
state.setClientId(grid.getClientId(context));
state.setSepOffset(new Integer(0));
ColumnWalker.iterateOverColumns(context, grid, headerCellRenderer, writer, state);
}
public void renderStyle(FacesContext context, UIScrollableDataTable grid) throws IOException {
ScrollableDataTableRendererState state = ScrollableDataTableRendererState.getRendererState(context);
ColumnWalker.iterateOverColumns(context, grid, styleRenderer, context.getResponseWriter(), state);
ResponseWriter writer = context.getResponseWriter();
writer.writeText("#" + getNormalizedId(context, state.getGrid()) + " .dr-sdt-c-f {", "width");
writer.writeText("width: 0px;", "width");
writer.writeText("}", "width");
}
public void renderFooters(FacesContext context, UIScrollableDataTable grid, boolean isFrozen) throws IOException{
ResponseWriter writer = context.getResponseWriter();
final ScrollableDataTableRendererState state = ScrollableDataTableRendererState.getRendererState(context);
if(isFrozen){
state.setColumType(COLUMN_FROZEN_TYPE);
}else{
state.setColumType(COLUMN_NORMAL_TYPE);
}
state.setClientId(grid.getClientId(context));
state.setFrozenColumnCount(ScrollableDataTableUtils.getFrozenColumnsCount(grid));
state.setFrozenPart(isFrozen);
int colsCount = ColumnWalker.iterateOverColumns(context, grid, footerCellRenderer, writer, state);
int rowsCount = grid.getRowCount();
ComponentVariables variables = ComponentsVariableResolver.getVariables(this, grid);
variables.setVariable("rows_count", new Integer(rowsCount));
variables.setVariable("columns_count", new Integer(colsCount));
}
public void setUpState(FacesContext context, UIScrollableDataTable grid) {
ScrollableDataTableRendererState state = ScrollableDataTableRendererState.createState(context, grid);
state.setRowIndex(ScrollableDataTableUtils.getClientRowIndex(grid));
}
public void tearDownState(FacesContext context, UIScrollableDataTable grid){
ScrollableDataTableRendererState.restoreState(context);
}
public String getRowsAjaxUpdate(FacesContext context, UIScrollableDataTable grid){
JSFunction function = AjaxRendererUtils.buildAjaxFunction(grid, context);
Map<String, Object> options = AjaxRendererUtils.buildEventOptions(context, grid);
options.put("oncomplete", AjaxFunctionBuilder.getOnComplete(context, grid, AjaxFunctionBuilder.SCROLL));
@SuppressWarnings("unchecked")
Map<String, Object> parametersMap = (Map<String, Object>) options.get("parameters");
parametersMap.put(grid.getBaseClientId(context) + ":scroll", "");
function.addParameter(options);
String completeFunction = function.toScript()+"; return false;";
return completeFunction;
}
@Override
protected void doDecode(FacesContext context, UIComponent component) {
super.doDecode(context, component);
AjaxContext ajaxContext = AjaxContext.getCurrentInstance(context);
if(component instanceof UIScrollableDataTable){
UIScrollableDataTable grid = (UIScrollableDataTable)component;
ExternalContext externalContext = context.getExternalContext();
String clientId = grid.getClientId(context);
boolean sorted = false;
Map<String, String> parameters = externalContext.getRequestParameterMap();
String s_id = clientId + ":si";
grid.resetReqRowsCount();
String firstString = null;
if(parameters.containsKey(s_id)){
String options = (String)parameters.get(s_id);
grid.setScrollPos(options);
if(options.length() > 0){
String[] si = options.split(",");
firstString = si[1];
if (si.length >= 5) {
grid.setFirst(Integer.parseInt(si[4]));
} else {
grid.setFirst(Integer.parseInt(firstString));
}
component.getAttributes().put(ScrollableDataTableUtils.CLIENT_ROW_KEY, Integer.parseInt(si[3]));
}
}
composite.decode(context, component);
if (firstString != null) {
grid.setFirst(Integer.parseInt(firstString));
}
if(parameters.containsKey(clientId + ":sortColumn") &&
parameters.containsKey(clientId + ":sortStartRow") &&
parameters.containsKey(clientId + ":sortIndex")){
String sortColumn = (String)parameters.get(clientId + ":sortColumn");
int sortDataIndex = Integer.parseInt((String)parameters.get(clientId + ":sortIndex"));
Integer sortStartRow = Integer.valueOf((String)parameters.get(clientId + ":sortStartRow"));
String sortOrderString =
(String) parameters.get(clientId + ":sortOrder");
Boolean so = null;
if (sortOrderString != null && sortOrderString.length() > 0 ) {
sortOrderString = sortOrderString.toLowerCase();
if (sortOrderString.startsWith("a")) {
so = Boolean.TRUE;
} else if (sortOrderString.startsWith("d")){
so = Boolean.FALSE;
}
}
UIComponent column = grid.findComponent(sortColumn);
if(ColumnUtil.isSortable(column)){
sorted = true;
SortEvent sortEvent = new SortEvent(grid,sortColumn, grid.getRows(), sortDataIndex);
sortEvent.setProposedOrder(so);
sortEvent.setAttribute(ScrollableDataTableUtils.CLIENT_ROW_KEY,sortStartRow);
if (ajaxContext.isAjaxRequest()) {
sortEvent.setAttribute(PARTIAL_UPDATE, Boolean.TRUE);
sortEvent.setAttribute(UPDATE_HEADER, Boolean.TRUE);
}
sortEvent.queue();
}
}
if(parameters.containsKey(clientId + ":scroll") && !sorted){
String submitedState = (String)parameters.get(clientId + "_state_input");
if (submitedState != null) {
boolean isEmpty = true;
String [] values = submitedState.split(",");
for (int i = 0; i < values.length; i++) {
isEmpty = isEmpty && values[i].equals("");
}
int rows = 0;
int first = 0;
if(!isEmpty){
rows = Integer.parseInt(values[0]);
first = Integer.parseInt(values[1]);
ScrollEvent scrollEvent = new ScrollEvent(grid,rows,first);
scrollEvent.setAttribute(ScrollableDataTableUtils.CLIENT_ROW_KEY,Integer.valueOf(values[2]));
if (ajaxContext.isAjaxRequest()) {
scrollEvent.setAttribute(PARTIAL_UPDATE, Boolean.TRUE);
}
scrollEvent.queue();
}
}
}
}
}
public void renderAjaxChildren(FacesContext context, UIComponent component)throws IOException{
UIScrollableDataTable grid = (UIScrollableDataTable)component;
ScrollableDataTableRendererState state = ScrollableDataTableRendererState.createState(context, grid);
AjaxContext ajaxContext = AjaxContext.getCurrentInstance(context);
String client_id = grid.getClientId(context);
state.setClientId(client_id);
state.setAjaxContext(ajaxContext);
state.setRowIndex(ScrollableDataTableUtils.getClientRowIndex(grid));
if (log.isDebugEnabled()) {
log.debug("ScrollableDataTableBaseRenderer.renderAjaxChildren()");
}
grid.getResponseData().clear();
ResponseWriter writer = context.getResponseWriter();
writer.startElement("table", grid);
writer.startElement("tbody", grid);
grid.walk(context, ajaxRowsRenderer, state);
int fakeRowsCount = grid.getRows() - grid.getRowCount();
ScrollableDataTableRendererState.restoreState(context);
grid.setRowKey(null);
state.setFake(true);
for (int i = 0; i < fakeRowsCount; i++) {
ajaxRowsRenderer.process(context, null, state);
}
state.setFake(false);
writer.endElement("tbody");
writer.endElement("table");
String id = client_id+"_rows_input";
writer.startElement(HTML.INPUT_ELEM, grid);
writer.writeAttribute(HTML.TYPE_ATTR, "hidden", null);
writer.writeAttribute(HTML.id_ATTRIBUTE, id, null);
writer.writeAttribute(HTML.NAME_ATTRIBUTE, id, null);
writer.writeAttribute(HTML.value_ATTRIBUTE, grid.getRowCount(), null);
writer.endElement(HTML.INPUT_ELEM);
ajaxContext.addRenderedArea(id);
renderHiddenScrollInput(context, grid);
ajaxContext.addRenderedArea(client_id+":si");
ajaxContext.setResponseData(grid.getResponseData());
ajaxContext.getAjaxRenderedAreas().remove(grid.getClientId(context));
ScrollableDataTableScrollData options = createOptions(grid);
ajaxContext.getResponseDataMap().put("options", options);
//Then call contributors to write additional HTML content
contributorsEncodeHere(context, grid);
if (shouldUpdateHeader(component)) {
ColumnWalker.iterateOverColumns(context, component, headerRenderer, writer, new ScrollableDataTableRendererState(context, null, grid));
}
}
private ScrollableDataTableScrollData createOptions(UIScrollableDataTable grid){
int index = grid.getFirst();
int startRow = ScrollableDataTableUtils.getClientRowIndex(grid);
int count = grid.getRows( )== 0 ? grid.getRowCount() : grid.getRows();
ScrollableDataTableScrollData options = new ScrollableDataTableScrollData(index, startRow, count);
return options;
}
private boolean onlyPartialUpdateNeeded(UIComponent grid) {
Boolean b = (Boolean) grid.getAttributes().get(PARTIAL_UPDATE);
return b != null && b.booleanValue() && AjaxContext.getCurrentInstance().isAjaxRequest();
}
private boolean shouldUpdateHeader(UIComponent grid) {
Boolean b = (Boolean) grid.getAttributes().get(UPDATE_HEADER);
return b != null && b.booleanValue() && AjaxContext.getCurrentInstance().isAjaxRequest();
}
@Override
public void encodeChildren(FacesContext context, UIComponent component
) throws IOException {
if(onlyPartialUpdateNeeded(component)){
renderAjaxChildren(context, component);
}else{
super.encodeChildren(context, component);
}
}
@Override
public void encodeBegin(FacesContext context, UIComponent component) throws IOException {
if(component instanceof UIScrollableDataTable){
UIScrollableDataTable grid = (UIScrollableDataTable)component;
setUpState(context, grid);
}
if(!onlyPartialUpdateNeeded(component)){
super.encodeBegin(context, component);
}
}
@Override
public void encodeEnd(FacesContext context, UIComponent component) throws IOException {
if(component instanceof UIScrollableDataTable){
UIScrollableDataTable table = (UIScrollableDataTable)component;
if(!onlyPartialUpdateNeeded(table)){
Object rowKey = table.getRowKey();
table.setRowKey(context, null);
super.encodeEnd(context, table);
table.setRowKey(context, rowKey);
}
component.getAttributes().remove(PARTIAL_UPDATE);
component.getAttributes().remove(UPDATE_HEADER);
}
}
public void setUpColumnsWidth(FacesContext context, UIScrollableDataTable grid) throws IOException{
ScrollableDataTableRendererState state = ScrollableDataTableRendererState.getRendererState(context);
state.setFrozenColumnCount(ScrollableDataTableUtils.getFrozenColumnsCount(grid));
ColumnWalker.iterateOverColumns(context, grid, columnsWidthCounter, null, state);
ComponentVariables variables = ComponentsVariableResolver.getVariables(this, grid);
int sumWidth = state.getSumWidth() + 200;
variables.setVariable("sumWidth", new Integer(sumWidth));
}
private RendererBase getCellTemplate() {
if (cellTemplate == null) {
cellTemplate = TemplateLoader.loadTemplate("org.richfaces.renderkit.html.ScrollableDataTableCellRenderer");
}
return cellTemplate;
}
private RendererBase getHeaderCellTemplate() {
if (headerCellTemplate == null) {
headerCellTemplate = TemplateLoader.loadTemplate("org.richfaces.renderkit.html.ScrollableDataTableHeaderCellRenderer");
}
return headerCellTemplate;
}
private RendererBase getFooterCellTemplate() {
if (footerCellTemplate == null) {
footerCellTemplate = TemplateLoader.loadTemplate("org.richfaces.renderkit.html.ScrollableDataTableFooterCellRenderer");
}
return footerCellTemplate;
}
private RendererBase getHeaderItselfTemplate() {
if (headerItselfTemplate == null) {
headerItselfTemplate = TemplateLoader.loadTemplate("org.richfaces.renderkit.html.ScrollableDataTableHeaderItselfRenderer");
}
return headerItselfTemplate;
}
public void renderHiddenScrollInput(FacesContext context, UIScrollableDataTable grid) throws IOException{
ResponseWriter writer = context.getResponseWriter();
String id = grid.getClientId(context) + ":si";
writer.startElement("input", grid);
getUtils().writeAttribute(writer, "type", "hidden");
getUtils().writeAttribute(writer, "name", id);
getUtils().writeAttribute(writer, "id", id);
getUtils().writeAttribute(writer, "value", grid.getScrollPos());
writer.endElement("input");
}
public void contributorsEncodeHere(FacesContext context, UIScrollableDataTable grid) throws IOException {
RendererContributor [] contribs = composite.getContributors();
if (contribs != null) {
for (int i = 0; i < contribs.length; i++) {
RendererContributor rendererContributor = contribs[i];
if (rendererContributor instanceof HTMLEncodingContributor) {
((HTMLEncodingContributor) rendererContributor).encode(context, grid);
}
}
}
}
private void addRowJavascriptEvents(ResponseWriter writer, UIComponent component) {
String attribute = (String)component.getAttributes().get("onRowClick");
if (attribute != null) {
try {
getUtils().writeAttribute(writer, "onclick", attribute);
} catch (IOException e) {
e.printStackTrace();
}
}
attribute = (String)component.getAttributes().get("onRowMouseDown");
if (attribute != null) {
try {
getUtils().writeAttribute(writer, "onmousedown", attribute);
} catch (IOException e) {
e.printStackTrace();
}
}
attribute = (String)component.getAttributes().get("onRowMouseUp");
if (attribute != null) {
try {
getUtils().writeAttribute(writer, "onmouseup", attribute);
} catch (IOException e) {
e.printStackTrace();
}
}
attribute = (String)component.getAttributes().get("onRowDblClick");
if (attribute != null) {
try {
getUtils().writeAttribute(writer, "ondblclick", attribute);
} catch (IOException e) {
e.printStackTrace();
}
}
}
private Boolean getColumnSorting(UIScrollableDataTable grid, String sortColumn) {
Boolean sorting = null;
UIComponent column = grid.findComponent(sortColumn);
String name = ColumnUtil.getColumnSorting(column);
SortOrder sortOrder = grid.getSortOrder();
if (sortOrder != null) {
SortField[] sortFields = sortOrder.getFields();
if (sortFields != null) {
for (int i = 0; i < sortFields.length && sorting == null; i++) {
SortField sortField = sortFields[i];
if (name != null && name.equals(sortField.getName())) {
sorting = sortField.getAscending();
}
}
}
}
return sorting;
}
private String getColumnWidth(UIComponent column) {
String width = (String) column.getAttributes().get("width");
if (width == null) {
width = "100px";
}
return width;
}
}