/*
* 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.event;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.el.ValueExpression;
import javax.faces.component.UIComponent;
import javax.faces.component.UIData;
import javax.faces.context.FacesContext;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.SystemEvent;
import javax.faces.event.SystemEventListener;
import org.ajax4jsf.Messages;
import org.richfaces.DataScrollerUtils;
import org.richfaces.component.AbstractDataScroller;
import org.richfaces.component.AbstractTree;
import org.richfaces.component.DataComponentsContextUtil;
import org.richfaces.component.UIDataAdaptor;
import org.richfaces.component.util.MessageUtil;
import org.richfaces.log.Logger;
import org.richfaces.log.RichfacesLogger;
public class DataTablePreRenderListener implements SystemEventListener {
private static final Logger LOG = RichfacesLogger.COMPONENTS.getLogger();
public boolean isListenerForSource(Object source) {
return ((source instanceof AbstractDataScroller) || (source instanceof UIDataAdaptor) || (source instanceof UIData));
}
public AbstractDataScroller processActiveDatascroller(FacesContext facesContext, List<AbstractDataScroller> dataScrollers,
UIComponent dataTable) {
AbstractDataScroller activeComponent = null;
List<Object> values = new ArrayList<Object>(dataScrollers.size());
String stateKey = dataTable.getClientId(facesContext) + AbstractDataScroller.SCROLLER_STATE_ATTRIBUTE;
Map<String, Object> attributes = dataTable.getAttributes();
Object pageValue = attributes.get(stateKey);
boolean valid = true;
if (pageValue == null) {
for (AbstractDataScroller datascroller : dataScrollers) {
Object nextPageValue = null;
if (datascroller.isLocalPageSet()) {
nextPageValue = datascroller.getPage();
attributes.put(stateKey, nextPageValue);
datascroller.resetLocalPage();
} else {
nextPageValue = datascroller.getValueExpression("page");
}
if (!values.isEmpty() && !same(values.get(values.size() - 1), nextPageValue)) {
valid = false;
}
values.add(nextPageValue);
if (nextPageValue != null) {
activeComponent = datascroller;
}
}
}
if (activeComponent == null) {
activeComponent = dataScrollers.get(dataScrollers.size() - 1);
}
if (!valid) {
String formattedMessage = getPageDifferentMessage(facesContext, activeComponent, dataScrollers, values);
LOG.error(formattedMessage);
}
return activeComponent;
}
public void processEvent(SystemEvent event) throws AbortProcessingException {
AbstractDataScroller activeDataScroller = null;
UIComponent dataTable = null;
FacesContext facesContext = FacesContext.getCurrentInstance();
UIComponent source = (UIComponent) event.getSource();
if (((source instanceof UIDataAdaptor) || (source instanceof UIData)) &&
!(source instanceof AbstractTree)) {
dataTable = source;
List<AbstractDataScroller> dataScrollers = DataScrollerUtils.findDataScrollers(dataTable);
if (!dataScrollers.isEmpty()) {
activeDataScroller = processActiveDatascroller(facesContext, dataScrollers, dataTable);
}
} else if (source instanceof AbstractDataScroller) {
activeDataScroller = (AbstractDataScroller) source;
dataTable = activeDataScroller.getDataTable();
}
if ((activeDataScroller != null) && (dataTable != null)) {
DataComponentsContextUtil.resetDataModelOncePerPhase(facesContext, dataTable);
String scrollerStateKey = dataTable.getClientId(facesContext) + AbstractDataScroller.SCROLLER_STATE_ATTRIBUTE;
int rowCount = DataScrollerUtils.getRowCount(dataTable);
int rows = DataScrollerUtils.getRows(dataTable);
int pageCount = DataScrollerUtils.getPageCount(dataTable, rowCount, rows);
int page = activeDataScroller.getPage();
int newPage = -1;
if (page < 1) {
newPage = 1;
} else if (page > pageCount) {
newPage = (pageCount != 0 ? pageCount : 1);
}
if (newPage != -1) {
Object label = MessageUtil.getLabel(facesContext, activeDataScroller);
String formattedMessage = Messages.getMessage(Messages.DATASCROLLER_PAGE_MISSING, new Object[] { label, page,
pageCount, newPage });
LOG.warn(formattedMessage);
page = newPage;
dataTable.getAttributes().put(scrollerStateKey, page);
}
int first;
String lastPageMode = activeDataScroller.getLastPageMode();
if (lastPageMode == null) {
lastPageMode = AbstractDataScroller.PAGEMODE_SHORT;
} else if (!AbstractDataScroller.PAGEMODE_SHORT.equals(lastPageMode)
&& !AbstractDataScroller.PAGEMODE_FULL.equals(lastPageMode)) {
throw new IllegalArgumentException("Illegal value of 'lastPageMode' attribute: '" + lastPageMode + "'");
}
if (page != pageCount || AbstractDataScroller.PAGEMODE_SHORT.equals(lastPageMode)) {
first = (page - 1) * rows;
} else {
first = rowCount - rows;
if (first < 0) {
first = 0;
}
}
dataTable.getAttributes().put("first", first);
}
}
private String getPageDifferentMessage(FacesContext facesContext, AbstractDataScroller activeComponent,
List<AbstractDataScroller> dataScrollers, List<Object> values) {
StringBuilder builder = new StringBuilder("\n[");
Iterator<AbstractDataScroller> scrollerItr = dataScrollers.iterator();
Iterator<Object> valueItr = values.iterator();
while (scrollerItr.hasNext()) {
AbstractDataScroller next = scrollerItr.next();
builder.append(MessageUtil.getLabel(facesContext, next));
builder.append(": ");
Object value = valueItr.next();
if (value instanceof ValueExpression) {
builder.append(((ValueExpression) value).getExpressionString());
} else {
builder.append(value);
}
builder.append(scrollerItr.hasNext() ? ",\n" : "]");
}
return Messages.getMessage(Messages.DATASCROLLER_PAGES_DIFFERENT,
new Object[] { MessageUtil.getLabel(facesContext, activeComponent), builder });
}
private static boolean same(Object o1, Object o2) {
if (o1 instanceof ValueExpression && o2 instanceof ValueExpression) {
ValueExpression ve1 = (ValueExpression) o1;
ValueExpression ve2 = (ValueExpression) o2;
if (same(ve1.getExpressionString(), ve2.getExpressionString())
&& same(ve1.getExpectedType(), ve2.getExpectedType())) {
return true;
}
}
return (o1 != null && o1.equals(o2)) || (o1 == null && o2 == null);
}
}