/**
* 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.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;
if (grid.isSelectionEnabled()) {
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) {
UIScrollableDataTable table = (UIScrollableDataTable) component;
ScriptOptions scriptOptions = new ScriptOptions(component);
if (table.isSelectionEnabled()) {
scriptOptions.addOption("selectionInput", getSelectionInputName(
context, table));
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);
scriptOptions.addOption("selectionMode", table.getSelectionMode());
}
return scriptOptions;
}
public void encode(FacesContext context, UIComponent component)
throws IOException {
UIScrollableDataTable grid = (UIScrollableDataTable) component;
if (grid.isSelectionEnabled()) {
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);
}
}
}