Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.primefaces.component.api.UITabPanel Maven / Gradle / Ivy
/*
* Copyright 2009-2014 PrimeTek.
*
* 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 org.primefaces.component.api;
import java.io.IOException;
import java.io.Serializable;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.el.ValueExpression;
import javax.faces.FacesException;
import javax.faces.application.Application;
import javax.faces.application.FacesMessage;
import javax.faces.component.ContextCallback;
import javax.faces.component.EditableValueHolder;
import javax.faces.component.NamingContainer;
import javax.faces.component.UIComponent;
import javax.faces.component.UINamingContainer;
import javax.faces.component.UIPanel;
import javax.faces.component.visit.VisitCallback;
import javax.faces.component.visit.VisitContext;
import javax.faces.component.visit.VisitResult;
import javax.faces.context.FacesContext;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.FacesEvent;
import javax.faces.event.FacesListener;
import javax.faces.event.PhaseId;
import javax.faces.event.PostValidateEvent;
import javax.faces.event.PreValidateEvent;
import javax.faces.model.ArrayDataModel;
import javax.faces.model.DataModel;
import javax.faces.model.ListDataModel;
import javax.faces.model.ResultSetDataModel;
import javax.faces.model.ScalarDataModel;
import javax.faces.render.Renderer;
import org.primefaces.component.tabview.Tab;
import org.primefaces.util.ComponentUtils;
import org.primefaces.util.Constants;
/**
* UITabPanel is a specialized version of UIRepeat focusing on components that repeat tabs like tabView and accordionPanel. Most of the code is
* copied from MyFaces.
*/
public class UITabPanel extends UIPanel implements NamingContainer {
private final static DataModel EMPTY_MODEL = new ListDataModel(Collections.emptyList());
private static final Class OBJECT_ARRAY_CLASS = Object[].class;
private static final Object[] LEAF_NO_STATE = new Object[]{null, null};
protected enum PropertyKeys {
value,
var,
size,
varStatus,
offset,
step,
dynamic,
prependId
}
private Object _initialDescendantComponentState = null;
// Holds for each row the states of the child components of this UIData.
// Note that only "partial" component state is saved: the component fields
// that are expected to vary between rows.
private Map> _rowStates = new HashMap>();
/**
* Handle case where this table is nested inside another table. See method getDataModel for more details.
*
* Key: parentClientId (aka rowId when nested within a parent table) Value: DataModel
*/
private Map _dataModelMap = new HashMap();
// will be set to false if the data should not be refreshed at the beginning of the encode phase
private boolean _isValidChilds = true;
private int _end = -1;
private int _count;
private int _index = -1;
private transient StringBuilder _clientIdBuffer;
private transient Object _origValue;
private transient Object _origVarStatus;
private transient FacesContext _facesContext;
public int getOffset() {
return (Integer) getStateHelper().eval(PropertyKeys.offset, 0);
}
public void setOffset(int offset) {
getStateHelper().put(PropertyKeys.offset, offset);
}
public int getSize() {
return (Integer) getStateHelper().eval(PropertyKeys.size, -1);
}
public void setSize(int size) {
getStateHelper().put(PropertyKeys.size, size);
}
public int getStep() {
return (Integer) getStateHelper().eval(PropertyKeys.step, 1);
}
public void setStep(int step) {
getStateHelper().put(PropertyKeys.step, step);
}
public String getVar() {
return (String) getStateHelper().get(PropertyKeys.var);
}
public void setVar(String var) {
getStateHelper().put(PropertyKeys.var, var);
}
public String getVarStatus() {
return (String) getStateHelper().get(PropertyKeys.varStatus);
}
public void setVarStatus(String varStatus) {
getStateHelper().put(PropertyKeys.varStatus, varStatus);
}
public boolean isDynamic() {
return (java.lang.Boolean) getStateHelper().eval(PropertyKeys.dynamic, false);
}
public void setDynamic(boolean _dynamic) {
getStateHelper().put(PropertyKeys.dynamic, _dynamic);
}
public boolean isPrependId() {
return (java.lang.Boolean) getStateHelper().eval(PropertyKeys.prependId, true);
}
public void setPrependId(boolean _prependId) {
getStateHelper().put(PropertyKeys.prependId, _prependId);
}
protected DataModel getDataModel() {
DataModel dataModel;
String clientID = "";
UIComponent parent = getParent();
if (parent != null) {
clientID = parent.getContainerClientId(getFacesContext());
}
dataModel = _dataModelMap.get(clientID);
if (dataModel == null) {
dataModel = createDataModel();
_dataModelMap.put(clientID, dataModel);
}
return dataModel;
}
private DataModel createDataModel() {
Object value = getValue();
if (value == null) {
return EMPTY_MODEL;
} else if (value instanceof DataModel) {
return (DataModel) value;
} else if (value instanceof List) {
return new ListDataModel((List) value);
} else if (OBJECT_ARRAY_CLASS.isAssignableFrom(value.getClass())) {
return new ArrayDataModel((Object[]) value);
} else if (value instanceof ResultSet) {
return new ResultSetDataModel((ResultSet) value);
} else {
return new ScalarDataModel(value);
}
}
@Override
public void setValueExpression(String name, ValueExpression binding) {
if (name == null) {
throw new NullPointerException("name");
} else if (name.equals("value")) {
_dataModelMap.clear();
} else if (name.equals("rowIndex")) {
throw new IllegalArgumentException("name " + name);
}
super.setValueExpression(name, binding);
}
public Object getValue() {
return getStateHelper().eval(PropertyKeys.value);
}
public void setValue(Object value) {
getStateHelper().put(PropertyKeys.value, value);
_dataModelMap.clear();
_rowStates.clear();
_isValidChilds = true;
}
@Override
public String getContainerClientId(FacesContext context) {
if(this.isPrependId() || this.isRepeating()) {
String clientId = super.getContainerClientId(context);
int index = getIndex();
if (index == -1) {
return clientId;
}
StringBuilder bld = _getBuffer(); //SharedStringBuilder(context);
return bld.append(clientId).append(UINamingContainer.getSeparatorChar(context)).append(index).toString();
}
else {
UIComponent parent = this.getParent();
while (parent != null) {
if (parent instanceof NamingContainer) {
return parent.getContainerClientId(context);
}
parent = parent.getParent();
}
return null;
}
}
private RepeatStatus _getRepeatStatus() {
return new RepeatStatus(_count == 0, _index + getStep() >= getDataModel().getRowCount(),
_count, _index, getOffset(), _end, getStep());
}
private void _captureScopeValues() {
String var = getVar();
if (var != null) {
_origValue = getFacesContext().getExternalContext().getRequestMap().get(var);
}
String varStatus = getVarStatus();
if (varStatus != null) {
_origVarStatus = getFacesContext().getExternalContext().getRequestMap().get(varStatus);
}
}
private StringBuilder _getBuffer() {
if (_clientIdBuffer == null) {
_clientIdBuffer = new StringBuilder();
}
_clientIdBuffer.setLength(0);
return _clientIdBuffer;
}
private boolean _isIndexAvailable() {
return getDataModel().isRowAvailable();
}
private void _restoreScopeValues() {
String var = getVar();
if (var != null) {
Map attrs = getFacesContext().getExternalContext().getRequestMap();
if (_origValue != null) {
attrs.put(var, _origValue);
_origValue = null;
} else {
attrs.remove(var);
}
}
String varStatus = getVarStatus();
if (getVarStatus() != null) {
Map attrs = getFacesContext().getExternalContext().getRequestMap();
if (_origVarStatus != null) {
attrs.put(varStatus, _origVarStatus);
_origVarStatus = null;
} else {
attrs.remove(varStatus);
}
}
}
/**
* Overwrite the state of the child components of this component with data previously saved by method saveDescendantComponentStates.
*
* The saved state info only covers those fields that are expected to vary between rows of a table. Other fields are not modified.
*/
@SuppressWarnings("unchecked")
private void restoreDescendantComponentStates(UIComponent parent, boolean iterateFacets, Object state,
boolean restoreChildFacets) {
int descendantStateIndex = -1;
List stateCollection = null;
if (iterateFacets && parent.getFacetCount() > 0) {
Iterator childIterator = parent.getFacets().values().iterator();
while (childIterator.hasNext()) {
UIComponent component = childIterator.next();
// reset the client id (see spec 3.1.6)
component.setId(component.getId());
if (!component.isTransient()) {
if (descendantStateIndex == -1) {
stateCollection = ((List) state);
descendantStateIndex = stateCollection.isEmpty() ? -1 : 0;
}
if (descendantStateIndex != -1 && descendantStateIndex < stateCollection.size()) {
Object[] object = stateCollection.get(descendantStateIndex);
if (object[0] != null && component instanceof EditableValueHolder) {
((SavedState) object[0]).restoreState((EditableValueHolder) component);
}
// If there is descendant state to restore, call it recursively, otherwise
// it is safe to skip iteration.
if (object[1] != null) {
restoreDescendantComponentStates(component, restoreChildFacets, object[1], true);
} else {
restoreDescendantComponentWithoutRestoreState(component, restoreChildFacets, true);
}
} else {
restoreDescendantComponentWithoutRestoreState(component, restoreChildFacets, true);
}
descendantStateIndex++;
}
}
}
if (parent.getChildCount() > 0) {
for (int i = 0; i < parent.getChildCount(); i++) {
UIComponent component = parent.getChildren().get(i);
// reset the client id (see spec 3.1.6)
component.setId(component.getId());
if (!component.isTransient()) {
if (descendantStateIndex == -1) {
stateCollection = ((List) state);
descendantStateIndex = stateCollection.isEmpty() ? -1 : 0;
}
if (descendantStateIndex != -1 && descendantStateIndex < stateCollection.size()) {
Object[] object = stateCollection.get(descendantStateIndex);
if (object[0] != null && component instanceof EditableValueHolder) {
((SavedState) object[0]).restoreState((EditableValueHolder) component);
}
// If there is descendant state to restore, call it recursively, otherwise
// it is safe to skip iteration.
if (object[1] != null) {
restoreDescendantComponentStates(component, restoreChildFacets, object[1], true);
} else {
restoreDescendantComponentWithoutRestoreState(component, restoreChildFacets, true);
}
} else {
restoreDescendantComponentWithoutRestoreState(component, restoreChildFacets, true);
}
descendantStateIndex++;
}
}
}
}
/**
* Just call component.setId(component.getId()) to reset all client ids and ensure they will be calculated for the current row, but do not waste time
* dealing with row state code.
*
* @param parent
* @param iterateFacets
* @param restoreChildFacets
*/
private void restoreDescendantComponentWithoutRestoreState(UIComponent parent, boolean iterateFacets,
boolean restoreChildFacets) {
if (iterateFacets && parent.getFacetCount() > 0) {
Iterator childIterator = parent.getFacets().values().iterator();
while (childIterator.hasNext()) {
UIComponent component = childIterator.next();
// reset the client id (see spec 3.1.6)
component.setId(component.getId());
if (!component.isTransient()) {
restoreDescendantComponentWithoutRestoreState(component, restoreChildFacets, true);
}
}
}
if (parent.getChildCount() > 0) {
for (int i = 0; i < parent.getChildCount(); i++) {
UIComponent component = parent.getChildren().get(i);
// reset the client id (see spec 3.1.6)
component.setId(component.getId());
if (!component.isTransient()) {
restoreDescendantComponentWithoutRestoreState(component, restoreChildFacets, true);
}
}
}
}
/**
* Walk the tree of child components of this UIData, saving the parts of their state that can vary between rows.
*
* This is very similar to the process that occurs for normal components when the view is serialized. Transient components are skipped (no state is saved
* for them).
*
* If there are no children then null is returned. If there are one or more children, and all children are transient then an empty collection is returned;
* this will happen whenever a table contains only read-only components.
*
* Otherwise a collection is returned which contains an object for every non-transient child component; that object may itself contain a collection of the
* state of that child's child components.
*/
private Collection saveDescendantComponentStates(UIComponent parent, boolean iterateFacets,
boolean saveChildFacets) {
Collection childStates = null;
// Index to indicate how many components has been passed without state to save.
int childEmptyIndex = 0;
int totalChildCount = 0;
if (iterateFacets && parent.getFacetCount() > 0) {
Iterator childIterator = parent.getFacets().values().iterator();
while (childIterator.hasNext()) {
UIComponent child = childIterator.next();
if (!child.isTransient()) {
// Add an entry to the collection, being an array of two
// elements. The first element is the state of the children
// of this component; the second is the state of the current
// child itself.
if (child instanceof EditableValueHolder) {
if (childStates == null) {
childStates = new ArrayList(
parent.getFacetCount()
+ parent.getChildCount()
- totalChildCount
+ childEmptyIndex);
for (int ci = 0; ci < childEmptyIndex; ci++) {
childStates.add(LEAF_NO_STATE);
}
}
childStates.add(child.getChildCount() > 0
? new Object[]{new SavedState((EditableValueHolder) child),
saveDescendantComponentStates(child, saveChildFacets, true)}
: new Object[]{new SavedState((EditableValueHolder) child),
null});
} else if (child.getChildCount() > 0 || (saveChildFacets && child.getFacetCount() > 0)) {
Object descendantSavedState = saveDescendantComponentStates(child, saveChildFacets, true);
if (descendantSavedState == null) {
if (childStates == null) {
childEmptyIndex++;
} else {
childStates.add(LEAF_NO_STATE);
}
} else {
if (childStates == null) {
childStates = new ArrayList(
parent.getFacetCount()
+ parent.getChildCount()
- totalChildCount
+ childEmptyIndex);
for (int ci = 0; ci < childEmptyIndex; ci++) {
childStates.add(LEAF_NO_STATE);
}
}
childStates.add(new Object[]{null, descendantSavedState});
}
} else {
if (childStates == null) {
childEmptyIndex++;
} else {
childStates.add(LEAF_NO_STATE);
}
}
}
totalChildCount++;
}
}
if (parent.getChildCount() > 0) {
for (int i = 0; i < parent.getChildCount(); i++) {
UIComponent child = parent.getChildren().get(i);
if (!child.isTransient()) {
// Add an entry to the collection, being an array of two
// elements. The first element is the state of the children
// of this component; the second is the state of the current
// child itself.
if (child instanceof EditableValueHolder) {
if (childStates == null) {
childStates = new ArrayList(
parent.getFacetCount()
+ parent.getChildCount()
- totalChildCount
+ childEmptyIndex);
for (int ci = 0; ci < childEmptyIndex; ci++) {
childStates.add(LEAF_NO_STATE);
}
}
childStates.add(child.getChildCount() > 0
? new Object[]{new SavedState((EditableValueHolder) child),
saveDescendantComponentStates(child, saveChildFacets, true)}
: new Object[]{new SavedState((EditableValueHolder) child),
null});
} else if (child.getChildCount() > 0 || (saveChildFacets && child.getFacetCount() > 0)) {
Object descendantSavedState = saveDescendantComponentStates(child, saveChildFacets, true);
if (descendantSavedState == null) {
if (childStates == null) {
childEmptyIndex++;
} else {
childStates.add(LEAF_NO_STATE);
}
} else {
if (childStates == null) {
childStates = new ArrayList(
parent.getFacetCount()
+ parent.getChildCount()
- totalChildCount
+ childEmptyIndex);
for (int ci = 0; ci < childEmptyIndex; ci++) {
childStates.add(LEAF_NO_STATE);
}
}
childStates.add(new Object[]{null, descendantSavedState});
}
} else {
if (childStates == null) {
childEmptyIndex++;
} else {
childStates.add(LEAF_NO_STATE);
}
}
}
totalChildCount++;
}
}
return childStates;
}
/**
* Returns the rowCount of the underlying DataModel.
*
* @return
*/
public int getRowCount() {
return getDataModel().getRowCount();
}
/**
* Returns the rowCount of the underlying DataModel.
*
* @return
*/
public Object getIndexData() {
if (!getDataModel().isRowAvailable())
{
return null;
}
return getDataModel().getRowData();
}
/**
* Returns the current index.
*/
public int getIndex() {
return _index;
}
public void setIndex(int index) {
// save child state
//_saveChildState();
if (index < -1) {
throw new IllegalArgumentException("rowIndex is less than -1");
}
if (_index == index) {
return;
}
FacesContext facesContext = getFacesContext();
if (_index == -1) {
if (_initialDescendantComponentState == null) {
// Create a template that can be used to initialise any row
// that we haven't visited before, ie a "saved state" that can
// be pushed to the "restoreState" method of all the child
// components to set them up to represent a clean row.
_initialDescendantComponentState = saveDescendantComponentStates(this, true, true);
}
} else {
// If no initial component state, there are no EditableValueHolder instances,
// and that means there is no state to be saved for the current row, so we can
// skip row state saving code safely.
if (_initialDescendantComponentState != null) {
// We are currently positioned on some row, and are about to
// move off it, so save the (partial) state of the components
// representing the current row. Later if this row is revisited
// then we can restore this state.
Collection savedRowState = saveDescendantComponentStates(this, true, true);
if (savedRowState != null) {
_rowStates.put(getContainerClientId(facesContext), savedRowState);
}
}
}
_index = index;
DataModel localModel = getDataModel();
localModel.setRowIndex(index);
if (_index != -1) {
String var = getVar();
if (var != null && localModel.isRowAvailable()) {
getFacesContext().getExternalContext().getRequestMap()
.put(var, localModel.getRowData());
}
String varStatus = getVarStatus();
if (varStatus != null) {
getFacesContext().getExternalContext().getRequestMap()
.put(varStatus, _getRepeatStatus());
}
}
// restore child state
//_restoreChildState();
if (_index == -1) {
// reset components to initial state
// If no initial state, skip row restore state code
if (_initialDescendantComponentState != null) {
restoreDescendantComponentStates(this, true, _initialDescendantComponentState, true);
} else {
restoreDescendantComponentWithoutRestoreState(this, true, true);
}
} else {
Object rowState = _rowStates.get(getContainerClientId(facesContext));
if (rowState == null) {
// We haven't been positioned on this row before, so just
// configure the child components of this component with
// the standard "initial" state
// If no initial state, skip row restore state code
if (_initialDescendantComponentState != null) {
restoreDescendantComponentStates(this, true, _initialDescendantComponentState, true);
} else {
restoreDescendantComponentWithoutRestoreState(this, true, true);
}
} else {
// We have been positioned on this row before, so configure
// the child components of this component with the (partial)
// state that was previously saved. Fields not in the
// partial saved state are left with their original values.
restoreDescendantComponentStates(this, true, rowState, true);
}
}
}
/**
* Calculates the count value for the given index.
*
* @param index
* @return
*/
private int _calculateCountForIndex(int index) {
return (index - getOffset()) / getStep();
}
private void _validateAttributes() throws FacesException {
int begin = getOffset();
int end = getDataModel().getRowCount();
int size = getSize();
int step = getStep();
boolean sizeIsEnd = false;
if (size == -1) {
size = end;
sizeIsEnd = true;
}
if (end >= 0) {
if (size < 0) {
throw new FacesException("iteration size cannot be less "
+ "than zero");
} else if (!sizeIsEnd && (begin + size) > end) {
throw new FacesException("iteration size cannot be greater "
+ "than collection size");
}
}
if ((size > -1) && (begin > end)) {
throw new FacesException("iteration offset cannot be greater "
+ "than collection size");
}
if (step == -1) {
setStep(1);
}
if (step < 0) {
throw new FacesException("iteration step size cannot be less "
+ "than zero");
} else if (step == 0) {
throw new FacesException("iteration step size cannot be equal "
+ "to zero");
}
_end = size;
//_step = step;
}
public void process(FacesContext faces, PhaseId phase) {
// stop if not rendered
if (!isRendered()) {
return;
}
// validate attributes
_validateAttributes();
// reset index
_captureScopeValues();
setIndex(-1);
try {
// has children
if (getChildCount() > 0) {
int i = getOffset();
int end = getSize();
int step = getStep();
end = (end >= 0) ? i + end : Integer.MAX_VALUE - 1;
// grab renderer
String rendererType = getRendererType();
Renderer renderer = null;
if (rendererType != null) {
renderer = getRenderer(faces);
}
_count = 0;
setIndex(i);
while (i <= end && _isIndexAvailable()) {
if (PhaseId.RENDER_RESPONSE.equals(phase) && renderer != null) {
renderer.encodeChildren(faces, this);
} else {
for (int j = 0, childCount = getChildCount(); j < childCount; j++) {
UIComponent child = getChildren().get(j);
if (PhaseId.APPLY_REQUEST_VALUES.equals(phase)) {
child.processDecodes(faces);
} else if (PhaseId.PROCESS_VALIDATIONS.equals(phase)) {
child.processValidators(faces);
} else if (PhaseId.UPDATE_MODEL_VALUES.equals(phase)) {
child.processUpdates(faces);
} else if (PhaseId.RENDER_RESPONSE.equals(phase)) {
child.encodeAll(faces);
}
}
}
++_count;
i += step;
setIndex(i);
}
}
} catch (IOException e) {
throw new FacesException(e);
} finally {
setIndex(-1);
_restoreScopeValues();
}
}
@Override
public boolean invokeOnComponent(FacesContext context, String clientId, ContextCallback callback) throws FacesException {
if(!this.isRepeating()) {
return super.invokeOnComponent(context, clientId, callback);
}
else {
if (context == null || clientId == null || callback == null) {
throw new NullPointerException();
}
final String baseClientId = getClientId(context);
// searching for this component?
boolean returnValue = baseClientId.equals(clientId);
boolean isCachedFacesContext = isTemporalFacesContext();
if (!isCachedFacesContext) {
setTemporalFacesContext(context);
}
pushComponentToEL(context, this);
try {
if (returnValue) {
try {
callback.invokeContextCallback(context, this);
return true;
} catch (Exception e) {
throw new FacesException(e);
}
}
// Now Look throught facets on this UIComponent
if (this.getFacetCount() > 0) {
for (Iterator it = this.getFacets().values().iterator(); !returnValue && it.hasNext();) {
returnValue = it.next().invokeOnComponent(context, clientId, callback);
}
}
if (returnValue) {
return returnValue;
}
// is the component an inner component?
if (clientId.startsWith(baseClientId)) {
// Check if the clientId for the component, which we
// are looking for, has a rowIndex attached
char separator = UINamingContainer.getSeparatorChar(context);
String subId = clientId.substring(baseClientId.length() + 1);
//If the char next to baseClientId is the separator one and
//the subId matches the regular expression
if (clientId.charAt(baseClientId.length()) == separator
&& subId.matches("[0-9]+" + separator + ".*")) {
String clientRow = subId.substring(0, subId.indexOf(separator));
// safe the current index, count aside
final int prevIndex = _index;
final int prevCount = _count;
try {
int invokeIndex = Integer.parseInt(clientRow);
// save the current scope values and set the right index
_captureScopeValues();
if (invokeIndex != -1) {
// calculate count for RepeatStatus
_count = _calculateCountForIndex(invokeIndex);
}
setIndex(invokeIndex);
if (!_isIndexAvailable()) {
return false;
}
for (Iterator it1 = getChildren().iterator();
!returnValue && it1.hasNext();) {
//recursive call to find the component
returnValue = it1.next().invokeOnComponent(context, clientId, callback);
}
} finally {
// restore the previous count, index and scope values
_count = prevCount;
setIndex(prevIndex);
_restoreScopeValues();
}
} else {
// Searching for this component's children
if (this.getChildCount() > 0) {
// Searching for this component's children/facets
for (Iterator it = this.getChildren().iterator(); !returnValue && it.hasNext();) {
returnValue = it.next().invokeOnComponent(context, clientId, callback);
}
}
}
}
} finally {
//all components must call popComponentFromEl after visiting is finished
popComponentFromEL(context);
if (!isCachedFacesContext) {
setTemporalFacesContext(null);
}
}
return returnValue;
}
}
@Override
protected FacesContext getFacesContext() {
if (_facesContext == null) {
return super.getFacesContext();
} else {
return _facesContext;
}
}
private boolean isTemporalFacesContext() {
return _facesContext != null;
}
private void setTemporalFacesContext(FacesContext facesContext) {
_facesContext = facesContext;
}
@Override
public boolean visitTree(VisitContext context, VisitCallback callback) {
if(!this.isRepeating()) {
return super.visitTree(context, callback);
}
else {
// override the behavior from UIComponent to visit
// all children once per "row"
if (ComponentUtils.isSkipIteration(context)) {
return super.visitTree(context, callback);
}
if (!isVisitable(context)) {
return false;
}
// save the current index, count aside
final int prevIndex = _index;
final int prevCount = _count;
// validate attributes
_validateAttributes();
// reset index and save scope values
_captureScopeValues();
setIndex(-1);
// push the Component to EL
pushComponentToEL(context.getFacesContext(), this);
try {
VisitResult res = context.invokeVisitCallback(this, callback);
switch (res) {
// we are done, nothing has to be processed anymore
case COMPLETE:
return true;
case REJECT:
return false;
//accept
default:
// determine if we need to visit our children
// Note that we need to do this check because we are a NamingContainer
Collection subtreeIdsToVisit = context
.getSubtreeIdsToVisit(this);
boolean doVisitChildren = subtreeIdsToVisit != null
&& !subtreeIdsToVisit.isEmpty();
if (doVisitChildren) {
// visit the facets of the component
if (getFacetCount() > 0) {
for (UIComponent facet : getFacets().values()) {
if (facet.visitTree(context, callback)) {
return true;
}
}
}
// visit the children once per "row"
if (getChildCount() > 0) {
int i = getOffset();
int end = getSize();
int step = getStep();
end = (end >= 0) ? i + end : Integer.MAX_VALUE - 1;
_count = 0;
setIndex(i);
while (i <= end && _isIndexAvailable()) {
for (int j = 0, childCount = getChildCount(); j < childCount; j++) {
UIComponent child = getChildren().get(j);
if (child.visitTree(context, callback)) {
return true;
}
}
_count++;
i += step;
setIndex(i);
}
}
}
return false;
}
} finally {
// pop the component from EL
popComponentFromEL(context.getFacesContext());
// restore the previous count, index and scope values
_count = prevCount;
setIndex(prevIndex);
_restoreScopeValues();
}
}
}
@Override
public void processDecodes(FacesContext context) {
if (!isRendered()) {
return;
}
pushComponentToEL(context, null);
if (!this.isRequestSource(context)) {
if (this.isRepeating()) {
process(context, PhaseId.APPLY_REQUEST_VALUES);
}
else {
if (this.isDynamic()) {
for(Tab tab : getLoadedTabs()) {
tab.processDecodes(context);
}
}
else {
ComponentUtils.processDecodesOfFacetsAndChilds(this, context);
}
}
}
try {
decode(context);
} catch (RuntimeException e) {
context.renderResponse();
throw e;
} finally {
popComponentFromEL(context);
}
}
@Override
public void processValidators(FacesContext context) {
if (!isRendered()) {
return;
}
if (this.isRequestSource(context)) {
return;
}
pushComponentToEL(context, null);
Application app = context.getApplication();
app.publishEvent(context, PreValidateEvent.class, this);
if (this.isRepeating()) {
process(context, PhaseId.PROCESS_VALIDATIONS);
}
else {
if (this.isDynamic()) {
for(Tab tab : getLoadedTabs()) {
tab.processValidators(context);
}
}
else {
ComponentUtils.processValidatorsOfFacetsAndChilds(this, context);
}
}
// check if an validation error forces the render response for our data
if (context.getRenderResponse()) {
_isValidChilds = false;
}
app.publishEvent(context, PostValidateEvent.class, this);
popComponentFromEL(context);
}
@Override
public void processUpdates(FacesContext context) {
if (!isRendered()) {
return;
}
if (this.isRequestSource(context)) {
return;
}
pushComponentToEL(context, null);
if (this.isRepeating()) {
process(context, PhaseId.UPDATE_MODEL_VALUES);
}
else {
if (this.isDynamic()) {
for(Tab tab : getLoadedTabs()) {
tab.processUpdates(context);
}
}
else {
ComponentUtils.processUpdatesOfFacetsAndChilds(this, context);
}
}
if (context.getRenderResponse()) {
_isValidChilds = false;
}
popComponentFromEL(context);
}
// from RI
private final static class SavedState implements Serializable {
private boolean _localValueSet;
private Object _submittedValue;
private boolean _valid = true;
private Object _value;
private static final long serialVersionUID = 2920252657338389849L;
public SavedState(EditableValueHolder evh) {
_value = evh.getLocalValue();
_localValueSet = evh.isLocalValueSet();
_valid = evh.isValid();
_submittedValue = evh.getSubmittedValue();
}
Object getSubmittedValue() {
return (_submittedValue);
}
void setSubmittedValue(Object submittedValue) {
_submittedValue = submittedValue;
}
boolean isValid() {
return (_valid);
}
void setValid(boolean valid) {
_valid = valid;
}
Object getValue() {
return _value;
}
public void setValue(Object value) {
_value = value;
}
boolean isLocalValueSet() {
return _localValueSet;
}
public void setLocalValueSet(boolean localValueSet) {
_localValueSet = localValueSet;
}
@Override
public String toString() {
return ("submittedValue: " + _submittedValue + " value: " + _value + " localValueSet: " + _localValueSet);
}
public void restoreState(EditableValueHolder evh) {
evh.setValue(_value);
evh.setValid(_valid);
evh.setSubmittedValue(_submittedValue);
evh.setLocalValueSet(_localValueSet);
}
public void populate(EditableValueHolder evh) {
_value = evh.getLocalValue();
_valid = evh.isValid();
_submittedValue = evh.getSubmittedValue();
_localValueSet = evh.isLocalValueSet();
}
public void apply(EditableValueHolder evh) {
evh.setValue(_value);
evh.setValid(_valid);
evh.setSubmittedValue(_submittedValue);
evh.setLocalValueSet(_localValueSet);
}
}
private final class IndexedEvent extends FacesEvent {
private final FacesEvent _target;
private final int _index;
public IndexedEvent(UITabPanel owner, FacesEvent target, int index) {
super(owner);
_target = target;
_index = index;
}
@Override
public PhaseId getPhaseId() {
return _target.getPhaseId();
}
@Override
public void setPhaseId(PhaseId phaseId) {
_target.setPhaseId(phaseId);
}
public boolean isAppropriateListener(FacesListener listener) {
return _target.isAppropriateListener(listener);
}
public void processListener(FacesListener listener) {
UITabPanel owner = (UITabPanel) getComponent();
// safe the current index, count aside
final int prevIndex = owner._index;
final int prevCount = owner._count;
try {
owner._captureScopeValues();
if (this._index != -1) {
// calculate count for RepeatStatus
_count = _calculateCountForIndex(this._index);
}
owner.setIndex(this._index);
if (owner._isIndexAvailable()) {
_target.processListener(listener);
}
} finally {
// restore the previous count, index and scope values
owner._count = prevCount;
owner.setIndex(prevIndex);
owner._restoreScopeValues();
}
}
public int getIndex() {
return _index;
}
public FacesEvent getTarget() {
return _target;
}
}
@Override
public void broadcast(FacesEvent event) throws AbortProcessingException {
if(!this.isRepeating()) {
super.broadcast(event);
}
else {
if (event instanceof IndexedEvent) {
IndexedEvent idxEvent = (IndexedEvent) event;
// safe the current index, count aside
final int prevIndex = _index;
final int prevCount = _count;
try {
_captureScopeValues();
if (idxEvent.getIndex() != -1) {
// calculate count for RepeatStatus
_count = _calculateCountForIndex(idxEvent.getIndex());
}
setIndex(idxEvent.getIndex());
if (_isIndexAvailable()) {
// get the target FacesEvent
FacesEvent target = idxEvent.getTarget();
FacesContext facesContext = getFacesContext();
// get the component associated with the target event and push
// it and its composite component parent, if available, to the
// component stack to have them available while processing the
// event (see also UIViewRoot._broadcastAll()).
UIComponent targetComponent = target.getComponent();
UIComponent compositeParent = UIComponent
.getCompositeComponentParent(targetComponent);
if (compositeParent != null) {
pushComponentToEL(facesContext, compositeParent);
}
pushComponentToEL(facesContext, targetComponent);
try {
// actual event broadcasting
targetComponent.broadcast(target);
} finally {
// remove the components from the stack again
popComponentFromEL(facesContext);
if (compositeParent != null) {
popComponentFromEL(facesContext);
}
}
}
} finally {
// restore the previous count, index and scope values
_count = prevCount;
setIndex(prevIndex);
_restoreScopeValues();
}
} else {
super.broadcast(event);
}
}
}
@Override
public void queueEvent(FacesEvent event) {
if(!this.isRepeating()) {
super.queueEvent(event);
}
else {
super.queueEvent(new IndexedEvent(this, event, _index));
}
}
// -=Leonardo Uribe=- At the moment I haven't found any use case that
// require to store the rowStates in the component state, mostly
// because EditableValueHolder instances render the value into the
// client and then this value are taken back at the beginning of the
// next request. So, I just let this code in comments just in case
// somebody founds an issue with this.
/*
@SuppressWarnings("unchecked")
@Override
public void restoreState(FacesContext facesContext, Object state)
{
if (state == null)
{
return;
}
Object[] values = (Object[])state;
super.restoreState(facesContext,values[0]);
if (values[1] == null)
{
_rowStates.clear();
}
else
{
_rowStates = (Map>) restoreAttachedState(facesContext, values[1]);
}
}
@Override
public Object saveState(FacesContext facesContext)
{
if (initialStateMarked())
{
Object parentSaved = super.saveState(facesContext);
if (parentSaved == null && _rowStates.isEmpty())
{
//No values
return null;
}
return new Object[]{parentSaved, saveAttachedState(facesContext, _rowStates)};
}
else
{
Object[] values = new Object[2];
values[0] = super.saveState(facesContext);
values[1] = saveAttachedState(facesContext, _rowStates);
return values;
}
}
*/
@Override
public void encodeBegin(FacesContext context) throws IOException {
_initialDescendantComponentState = null;
if (_isValidChilds && !hasErrorMessages(context)) {
// Clear the data model so that when rendering code calls
// getDataModel a fresh model is fetched from the backing
// bean via the value-binding.
_dataModelMap.clear();
// When the data model is cleared it is also necessary to
// clear the saved row state, as there is an implicit 1:1
// relation between objects in the _rowStates and the
// corresponding DataModel element.
_rowStates.clear();
}
// TODO Auto-generated method stub
super.encodeBegin(context);
}
private boolean hasErrorMessages(FacesContext context) {
for (Iterator iter = context.getMessages(); iter.hasNext();) {
FacesMessage message = iter.next();
if (FacesMessage.SEVERITY_ERROR.compareTo(message.getSeverity()) <= 0) {
return true;
}
}
return false;
}
@Override
public void encodeChildren(FacesContext faces) throws IOException {
if (!isRendered()) {
return;
}
process(faces, PhaseId.RENDER_RESPONSE);
}
@Override
public boolean getRendersChildren() {
if (getRendererType() != null) {
Renderer renderer = getRenderer(getFacesContext());
if (renderer != null) {
return renderer.getRendersChildren();
}
}
return true;
}
public boolean isRepeating() {
return (this.getVar() != null);
}
List loadedTabs;
public List getLoadedTabs() {
if(loadedTabs == null) {
loadedTabs = new ArrayList();
for(UIComponent component : getChildren()) {
if(component instanceof Tab) {
Tab tab = (Tab) component;
if(tab.isLoaded())
loadedTabs.add(tab);
}
}
}
return loadedTabs;
}
private boolean isRequestSource(FacesContext context) {
return this.getClientId(context).equals(context.getExternalContext().getRequestParameterMap().get(Constants.RequestParams.PARTIAL_SOURCE_PARAM));
}
}