/**
*
*/
package org.richfaces.renderkit.html;
import java.io.IOException;
import java.util.Map;
import javax.el.ValueExpression;
import javax.faces.FacesException;
import javax.faces.application.Application;
import javax.faces.component.UIComponent;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.convert.Converter;
import org.ajax4jsf.context.AjaxContext;
import org.ajax4jsf.model.DataVisitor;
import org.ajax4jsf.renderkit.RendererUtils.HTML;
import org.richfaces.component.UIScrollableDataTable;
import org.richfaces.model.selection.ClientSelection;
import org.richfaces.model.selection.Selection;
import org.richfaces.model.selection.SimpleSelection;
import org.richfaces.renderkit.CompositeRenderer;
import org.richfaces.renderkit.RendererContributor;
import org.richfaces.renderkit.ScriptOptions;
/**
* @author Maksim Kaszynski
*
*/
public class SelectionRendererContributor implements RendererContributor, HTMLEncodingContributor {
public static final String CLIENT_SELECTION = "clientSelection";
public static final String getSelectionInputName(FacesContext context,
UIScrollableDataTable grid) {
String id = grid.getBaseClientId(context) + ":s";
return id;
}
public void decode(FacesContext context, UIComponent component,
CompositeRenderer compositeRenderer) {
final UIScrollableDataTable grid = (UIScrollableDataTable) component;
ExternalContext externalContext = context.getExternalContext();
Map<String, String> requestParamMap = externalContext.getRequestParameterMap();
Application application = context.getApplication();
String id = getSelectionInputName(context, grid);
String value = (String) requestParamMap.get(id);
Converter converter = application.createConverter(ClientSelection.class);
ClientSelection _oldClientSelection =
(ClientSelection) grid.getAttributes().get(CLIENT_SELECTION);
final ClientSelection oldClientSelection =
_oldClientSelection == null ?
new ClientSelection() :
_oldClientSelection;
final ClientSelection clientSelection =
(ClientSelection) converter.getAsObject(context, grid, value);
final ScrollableDataTableRendererState state =
ScrollableDataTableRendererState.createState(context, grid);
state.setRowIndex(ScrollableDataTableUtils.getClientRowIndex(grid));
final SimpleSelection simpleSelection = grid.getSelection() == null ? new SimpleSelection()
: (SimpleSelection) grid.getSelection();
if (clientSelection.isReset() || clientSelection.isSelectAll()) {
simpleSelection.clear();
simpleSelection.setSelectAll(clientSelection.isSelectAll());
}
try {
grid.walk(context,
new DataVisitor() {
public void process(FacesContext context, Object rowKey,
Object argument) throws IOException {
int i = state.getRowIndex();
if (shouldAddToSelection(i, oldClientSelection, clientSelection)) {
simpleSelection.addKey(rowKey);
} else if (shouldRemoveFromSelection(i, oldClientSelection, clientSelection)){
simpleSelection.removeKey(rowKey);
}
if(i == clientSelection.getActiveRowIndex()) {
grid.setActiveRowKey(rowKey);
}
state.nextRow();
}
},
state);
} catch(IOException e) {
throw new FacesException(e);
}
grid.setSelection(simpleSelection);
ValueExpression selectionBinding = grid.getValueExpression("selection");
if (selectionBinding != null) {
selectionBinding.setValue(context.getELContext(), simpleSelection);
}
ScrollableDataTableRendererState.restoreState(context);
}
/*
* (non-Javadoc)
*
* @see org.richfaces.renderkit.RendererContributor#getAcceptableClass()
*/
public Class<?> getAcceptableClass() {
return UIScrollableDataTable.class;
}
/*
* (non-Javadoc)
*
* @see org.richfaces.renderkit.RendererContributor#getScriptContribution(javax.faces.context.FacesContext,
* javax.faces.component.UIComponent)
*/
public String getScriptContribution(FacesContext context,
UIComponent component) {
return null;
}
/*
* (non-Javadoc)
*
* @see org.richfaces.renderkit.RendererContributor#getScriptDependencies()
*/
public String[] getScriptDependencies() {
return null;
}
/*
* (non-Javadoc)
*
* @see org.richfaces.renderkit.RendererContributor#getStyleDependencies()
*/
public String[] getStyleDependencies() {
return null;
}
public ScriptOptions buildOptions(FacesContext context,
UIComponent component) {
ScriptOptions scriptOptions = new ScriptOptions(component);
scriptOptions.addOption("selectionInput", getSelectionInputName(
context, (UIScrollableDataTable) component));
Map<String, Object> attributes = component.getAttributes();
Object attribut = attributes.get("selectedClass");
if (attribut == null) {
attribut = "";
}
scriptOptions.addOption("selectedClass", attribut);
attribut = attributes.get("activeClass");
if (attribut == null) {
attribut = "";
}scriptOptions.addOption("activeClass", attribut);
return scriptOptions;
}
public void encode(FacesContext context, UIComponent component)
throws IOException {
UIScrollableDataTable grid = (UIScrollableDataTable) component;
encodeSelection(context, grid);
writeSelection(context, grid);
}
//Decide whether to add new row to selection based on comparison with old one
public boolean shouldAddToSelection(int i, ClientSelection oldSelection, ClientSelection newSelection) {
return newSelection.isSelectAll() ||
(newSelection.isSelected(i) && (!oldSelection.isSelected(i) || newSelection.isReset())) ;
}
//Decide whether to remove new row to selection based on comparison with old one
public boolean shouldRemoveFromSelection(int i, ClientSelection oldSelection, ClientSelection newSelection) {
return !newSelection.isReset() && (!newSelection.isSelectAll() && (!newSelection.isSelected(i) && oldSelection.isSelected(i)));
}
private void encodeSelection(FacesContext context, final UIScrollableDataTable grid) throws IOException {
final ScrollableDataTableRendererState state = ScrollableDataTableRendererState.createState(context, grid);
state.setRowIndex(ScrollableDataTableUtils.getClientRowIndex(grid));
final Selection gridSelection =
grid.getSelection() == null ?
new SimpleSelection() :
grid.getSelection();
final ClientSelection clientSelection = new ClientSelection();
grid.walk(context,
new DataVisitor() {
public void process(FacesContext context, Object rowKey,
Object argument) throws IOException {
if (gridSelection.isSelected(rowKey)) {
int i = state.getRowIndex();
clientSelection.addIndex(i);
}
if (rowKey.equals(grid.getActiveRowKey())) {
clientSelection.setActiveRowIndex(state.getRowIndex());
}
state.nextRow();
}
},
state);
ScrollableDataTableRendererState.restoreState(context);
grid.getAttributes().put(CLIENT_SELECTION, clientSelection);
}
/**
* Get client selection from the component, transform it into string form,
* and write it as hidden input
* @param context
* @param grid
* @throws IOException
*/
public void writeSelection(FacesContext context, UIScrollableDataTable grid)
throws IOException {
Application application = context.getApplication();
Converter converter =
application.createConverter(ClientSelection.class);
ClientSelection selection = (ClientSelection)grid.getAttributes().get(CLIENT_SELECTION);
String string =
converter.getAsString(context, grid, selection);
if (string == null) {
string = "";
}
string += selection.getActiveRowIndex();
String id = getSelectionInputName(context, grid);
ResponseWriter writer = context.getResponseWriter();
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, string, null);
writer.endElement(HTML.INPUT_ELEM);
AjaxContext ajaxContext = AjaxContext.getCurrentInstance(context);
if (ajaxContext.isAjaxRequest()) {
ajaxContext.addRenderedArea(id);
}
}
}