/*
* � Copyright IBM Corp. 2010, 2011
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package com.ibm.xsp.extlib.component.data;
import javax.faces.FacesException;
import javax.faces.component.UIComponent;
import javax.faces.component.UIForm;
import javax.faces.component.UIPanel;
import javax.faces.context.FacesContext;
import javax.faces.el.ValueBinding;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.FacesEvent;
import javax.faces.event.PhaseId;
import com.ibm.xsp.application.ApplicationEx;
import com.ibm.xsp.component.FacesComponent;
import com.ibm.xsp.component.FacesDataIterator;
import com.ibm.xsp.component.UIDataEx;
import com.ibm.xsp.event.PagerEvent;
import com.ibm.xsp.extlib.event.ExtlibPagerEvent;
import com.ibm.xsp.extlib.stylekit.StyleKitExtLibDefault;
import com.ibm.xsp.page.FacesComponentBuilder;
import com.ibm.xsp.stylekit.ThemeControl;
import com.ibm.xsp.util.FacesUtil;
import com.ibm.xsp.util.HtmlUtil;
/**
* Abstract base class for developing pagers.
* <p>
* Pagers are used to present options that drive a data iterator (views...), for example
* to change the current page or the number of rows being displayed.<br>
* This class contains convenient method that help writting pagers.
* </p>
*/
public class AbstractPager extends UIPanel implements FacesComponent, ThemeControl {
public static final String COMPONENT_TYPE = "com.ibm.xsp.extlib.data.AbstractPager"; //$NON-NLS-1$
public static final String COMPONENT_FAMILY = "com.ibm.xsp.extlib.data.Pager"; //$NON-NLS-1$
public static final String PAGER_ADDROWS_DEFAULT_ROWCOUNT_PROPERTY = "xsp.pager.addrows.defaultRowCount"; //$NON-NLS-1$
public static final String PAGER_ADDROWS_DEFAULT_ROWCOUNT_DEFVAL = String.valueOf(UIDataEx.DEFAULT_ROWS_PER_PAGE); //$NON-NLS-1$
//>tmg:a11y
/**
* This is the key of a value stored in the attributes map and not a clientId suffix,
* nor is it an actual clientId. It is used to maintain the currently focused pager
* link during partial paging interactions.
*/
public static final String PAGER_CLIENT_ID = "__pagerClientId__"; //$NON-NLS-1$
//<tmg:a11y
protected int defaultRowCount;
private String _for;
private Boolean partialExecute;
private Boolean partialRefresh;
private String refreshId;
private String style;
private String styleClass;
private String title;
private String ariaLabel;
private transient FacesDataIterator dataIterator;
public AbstractPager() {
super();
ApplicationEx app = ApplicationEx.getInstance();
defaultRowCount = Integer.parseInt(app.getApplicationProperty(PAGER_ADDROWS_DEFAULT_ROWCOUNT_PROPERTY, PAGER_ADDROWS_DEFAULT_ROWCOUNT_DEFVAL));
}
public String getStyleKitFamily() {
return StyleKitExtLibDefault.PAGER;
}
@Override
public String getFamily() {
return COMPONENT_FAMILY;
}
public String getFor() {
if(_for!=null) {
return _for;
}
ValueBinding vb = getValueBinding("for"); //$NON-NLS-1$
if(vb!=null) {
return (String)vb.getValue(getFacesContext());
}
return null;
}
public void setFor(String _for) {
this._for = _for;
}
public boolean isPartialExecute() {
if(partialExecute!=null) {
return partialExecute;
}
ValueBinding vb = getValueBinding("partialExecute"); //$NON-NLS-1$
if(vb!=null) {
Boolean b = (Boolean)vb.getValue(getFacesContext());
if(b!=null) {
return b;
}
}
return true;
}
public void setPartialExecute(boolean partialExecute) {
this.partialExecute = partialExecute;
}
public boolean isPartialRefresh() {
if(partialRefresh!=null) {
return partialRefresh;
}
ValueBinding vb = getValueBinding("partialRefresh"); //$NON-NLS-1$
if(vb!=null) {
Boolean b = (Boolean)vb.getValue(getFacesContext());
if(b!=null) {
return b;
}
}
return true;
}
public void setPartialRefresh(boolean partialRefresh) {
this.partialRefresh = partialRefresh;
}
public String getRefreshId() {
if(refreshId!=null) {
return refreshId;
}
ValueBinding vb = getValueBinding("refreshId"); //$NON-NLS-1$
if(vb!=null) {
return (String)vb.getValue(getFacesContext());
}
return null;
}
public void setRefreshId(String partialRefreshId) {
this.refreshId = partialRefreshId;
}
public String getStyle() {
if (null != this.style) {
return this.style;
}
ValueBinding vb = getValueBinding("style"); //$NON-NLS-1$
if (vb != null) {
return (String) vb.getValue(getFacesContext());
} else {
return null;
}
}
public void setStyle(String style) {
this.style = style;
}
public String getStyleClass() {
if (null != this.styleClass) {
return this.styleClass;
}
ValueBinding vb = getValueBinding("styleClass"); //$NON-NLS-1$
if (vb != null) {
return (String) vb.getValue(getFacesContext());
} else {
return null;
}
}
public void setStyleClass(String styleClass) {
this.styleClass = styleClass;
}
public java.lang.String getAriaLabel() {
if (null != this.ariaLabel) {
return this.ariaLabel;
}
ValueBinding _vb = getValueBinding("ariaLabel"); //$NON-NLS-1$
if (_vb != null) {
return (java.lang.String) _vb.getValue(getFacesContext());
} else {
return null;
}
}
public String getTitle() {
if (null != this.title) {
return this.title;
}
ValueBinding _vb = getValueBinding("title"); //$NON-NLS-1$
if (_vb != null) {
return (java.lang.String) _vb.getValue(FacesContext.getCurrentInstance());
} else {
return null;
}
}
public void setTitle(String title) {
this.title = title;
}
public void setAriaLabel(java.lang.String ariaLabel) {
this.ariaLabel = ariaLabel;
}
// Should this be factor out to another class?
public FacesDataIterator findDataIterator() {
if (dataIterator != null) {
return dataIterator;
}
String dataId = (String) getAttributes().get("for"); //$NON-NLS-1$
if (dataId != null) {
UIComponent data = findComponent(dataId);
if (null == data) {
// Scenario where a pager inside a custom control is
// attached to a data iterator outside that control
data = FacesUtil.getComponentFor(this, dataId);
}
if (data instanceof FacesDataIterator) {
dataIterator = (FacesDataIterator) data;
return dataIterator;
}
return null;
}
dataIterator = findDataParent(getParent());
return dataIterator;
}
private FacesDataIterator findDataParent(UIComponent component) {
if (component == null) {
return null;
}
if (component instanceof FacesDataIterator) {
return (FacesDataIterator) component;
}
return findDataParent(component.getParent());
}
public UIComponent findSharedDataPagerParent() {
String dataId = getFor();
if (dataId != null) {
UIComponent data = findComponent(dataId);
if (data instanceof FacesDataIterator) {
UIComponent dataParent = data;
while (dataParent != null) {
UIComponent pagerParent = getParent();
while (pagerParent != null) {
if (pagerParent == dataParent) {
// Need to check that the shared parent has a user set Id as components
// with autogenerated Id's are not guaranteed to generate output
// that is capable of being partially refreshed.
while (dataParent!=null) {
if(HtmlUtil.isUserId(dataParent.getId())) {
break;
}
if(dataParent instanceof UIForm) {
// Form always generate an ID, even when it is auto-generated.
break;
}
dataParent = dataParent.getParent();
}
return dataParent;
}
pagerParent = pagerParent.getParent();
}
dataParent = dataParent.getParent();
}
}
}
return null;
}
@Override
public void broadcast(FacesEvent event) throws AbortProcessingException {
super.broadcast(event);
if (event instanceof PagerEvent) {
//>tmg:a11y
PagerEvent pe = (PagerEvent) event;
FacesContext context = getFacesContext();
if( pe instanceof ExtlibPagerEvent ){
String focusClientId = ((ExtlibPagerEvent)pe).getClientId();
if( null != focusClientId ){
HtmlUtil.storeEncodeParameter(context, this, PAGER_CLIENT_ID, focusClientId);
}
}
//<tmg:a11y
context.renderResponse();
}
}
@Override
public void queueEvent(FacesEvent e) {
if (e instanceof PagerEvent) {
if (isPartialExecute()) {
e.setPhaseId(PhaseId.APPLY_REQUEST_VALUES);
} else {
e.setPhaseId(PhaseId.INVOKE_APPLICATION);
}
}
super.queueEvent(e);
}
@Override
public void restoreState(FacesContext context, Object state) {
Object values[] = (Object[]) state;
super.restoreState(context, values[0]);
this._for = (String)values[1];
this.partialExecute = (Boolean)values[2];
this.partialRefresh = (Boolean)values[3];
this.refreshId = (String)values[4];
this.style = (String)values[5];
this.styleClass = (String)values[6];
this.ariaLabel = (String)values[7];
this.title = (String)values[8];
}
@Override
public Object saveState(FacesContext context) {
Object values[] = new Object[9];
values[0] = super.saveState(context);
values[1] = _for;
values[2] = partialExecute;
values[3] = partialRefresh;
values[4] = refreshId;
values[5] = style;
values[6] = styleClass;
values[7] = ariaLabel;
values[8] = title;
return values;
}
// ===================================================================
// Faces Component Methods
// ===================================================================
public void initBeforeContents(FacesContext context) throws FacesException {
// Nothing
}
public void buildContents(FacesContext context, FacesComponentBuilder builder) throws FacesException {
// Standard stuff
builder.buildAll(context, this, true);
}
public void initAfterContents(FacesContext context) throws FacesException {
//Do nothing, the default implementation
}
}