/*
* � Copyright IBM Corp. 2010
*
* 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.dynamiccontent;
import java.io.IOException;
import javax.faces.FacesException;
import javax.faces.component.ContextCallback;
import javax.faces.component.UIComponent;
import javax.faces.component.UIComponentBase;
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.el.ValueBinding;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.FacesEvent;
import javax.faces.event.FacesListener;
import javax.faces.event.PhaseId;
import com.ibm.commons.util.StringUtil;
import com.ibm.xsp.extlib.stylekit.StyleKitExtLibDefault;
import com.ibm.xsp.stylekit.ThemeControl;
import com.ibm.xsp.util.FacesUtil;
/**
* This control switches the children to display between a list of facets.
* <p>
* When the control is processed, it evaluates the 'selectedValues' property and
* then process the facet which name correspond to the selectedValue.
* </p>
*/
public class UISwitchFacet extends UIComponentBase implements ThemeControl {
public static final String COMPONENT_TYPE = "com.ibm.xsp.extlib.dynamiccontent.SwitchFacet"; // $NON-NLS-1$
public static final String COMPONENT_FAMILY = "com.ibm.xsp.extlib.dynamiccontent.SwitchFacet"; // $NON-NLS-1$
public static final String RENDERER_TYPE = "com.ibm.xsp.extlib.dynamiccontent.SwitchFacet"; // $NON-NLS-1$
private String selectedFacet;
private String defaultFacet;
private transient String currentFacetName; // Current facet name
public UISwitchFacet() {
// This component is never rendered, so there is no intermediate tag
// That also prevents the switch component to be partial refreshed, but this
// can be be worked around by putting the switch component within a panel
setRendererType(RENDERER_TYPE);
}
@Override
public String getFamily() {
return COMPONENT_FAMILY;
}
public String getStyleKitFamily() {
return StyleKitExtLibDefault.CONTAINER_WIDGET;
}
public String getSelectedFacet() {
if (null != this.selectedFacet) {
return this.selectedFacet;
}
ValueBinding _vb = getValueBinding("selectedFacet"); //$NON-NLS-1$
if (_vb != null) {
return (java.lang.String) _vb.getValue(getFacesContext());
} else {
return null;
}
}
public void setSelectedFacet(String selectedValue) {
this.selectedFacet = selectedValue;
}
public String getDefaultFacet() {
if (null != this.defaultFacet) {
return this.defaultFacet;
}
ValueBinding _vb = getValueBinding("defaultFacet"); //$NON-NLS-1$
if (_vb != null) {
return (java.lang.String) _vb.getValue(getFacesContext());
} else {
return null;
}
}
public void setDefaultFacet(String defaultFacet) {
this.defaultFacet = defaultFacet;
}
public String getCurrentFacetName() {
return currentFacetName;
}
@Override
public void restoreState(FacesContext _context, Object _state) {
Object _values[] = (Object[]) _state;
super.restoreState(_context, _values[0]);
this.selectedFacet = (String)_values[1];
this.defaultFacet = (String)_values[2];
}
@Override
public Object saveState(FacesContext _context) {
Object _values[] = new Object[3];
_values[0] = super.saveState(_context);
_values[1] = selectedFacet;
_values[2] = defaultFacet;
return _values;
}
// ==============================================================================
// JSF processing
// ==============================================================================
protected UIComponent selectFacet() {
UIComponent facet = selectFacet(getSelectedFacet());
if(facet==null) {
facet = selectFacet(getDefaultFacet());
}
return facet;
}
protected UIComponent selectFacet(String facetName) {
if(StringUtil.isNotEmpty(facetName)) {
UIComponent facet = getFacet(facetName);
if(facet!=null) {
currentFacetName = facetName;
return facet;
}
}
return null;
}
protected void unselectFacet() {
currentFacetName = null;
}
public class FacetFacesEvent extends FacesEvent {
private static final long serialVersionUID = 1L;
private FacesEvent _event;
private String _facetName;
public FacetFacesEvent(UIComponent component, FacesEvent event, String facetName) {
super(component);
_event = event;
_facetName = facetName;
}
public String getFacetName() {
return _facetName;
}
public FacesEvent getEvent() {
return _event;
}
@Override
public void setPhaseId(PhaseId phaseId) {
_event.setPhaseId(phaseId);
}
@Override
public PhaseId getPhaseId() {
return _event.getPhaseId();
}
@Override
public boolean isAppropriateListener(FacesListener listener) {
return _event.isAppropriateListener(listener);
}
@Override
public void processListener(FacesListener listener) {
_event.processListener(listener);
}
}
@Override
public void queueEvent(FacesEvent event) {
super.queueEvent(new FacetFacesEvent(this, event, getCurrentFacetName()));
}
@Override
public void broadcast(FacesEvent event) throws AbortProcessingException {
if (event instanceof FacetFacesEvent) {
FacetFacesEvent fe = (FacetFacesEvent)event;
UIComponent facet = selectFacet(fe.getFacetName());
if(facet!=null) {
try {
FacesEvent wrappedEvent = fe.getEvent();
wrappedEvent.getComponent().broadcast(wrappedEvent);
} finally {
unselectFacet();
}
}
}
else {
super.broadcast(event);
}
}
@Override
public void encodeBegin(FacesContext context) throws IOException {
// no rendering for this component
}
@Override
public boolean getRendersChildren() {
return true;
}
@Override
public void encodeChildren(FacesContext context) throws IOException {
if (!isRendered()) {
return;
}
// Only render the selected facet
UIComponent facet = selectFacet();
if(facet!=null) {
try {
FacesUtil.renderComponent(context, facet);
} finally {
unselectFacet();
}
}
}
@Override
public void encodeEnd(FacesContext context) throws IOException {
// no rendering for this component
}
@Override
public void processDecodes(FacesContext context) {
if (!isRendered()) {
return;
}
UIComponent facet = selectFacet();
if(facet!=null) {
try {
facet.processDecodes(context);
} finally {
unselectFacet();
}
}
decode(context);
}
@Override
public void processUpdates(FacesContext context) {
if (!isRendered()) {
return;
}
UIComponent facet = selectFacet();
if(facet!=null) {
try {
facet.processUpdates(context);
} finally {
unselectFacet();
}
}
}
@Override
public void processValidators(FacesContext context) {
if (!isRendered()) {
return;
}
UIComponent facet = selectFacet();
if(facet!=null) {
try {
facet.processValidators(context);
} finally {
unselectFacet();
}
}
}
@Override
public boolean invokeOnComponent(FacesContext context, String clientId, ContextCallback callback) throws FacesException {
// Check for the current component
String cid = getClientId(context);
if (clientId.equals(cid)) {
try {
callback.invokeContextCallback(context, this);
return true;
} catch (Exception e) {
throw new FacesException(e);
}
}
// Or the selected facet
UIComponent facet = selectFacet();
if(facet!=null) {
try {
if(facet.invokeOnComponent(context, clientId, callback)) {
return true;
}
} finally {
unselectFacet();
}
}
return false;
}
@Override
public boolean visitTree(VisitContext context, VisitCallback callback) {
if (!isVisitable(context)) {
return false;
}
// Check for the current component
VisitResult res = context.invokeVisitCallback(this, callback);
if (res == VisitResult.COMPLETE) return true;
if (res == VisitResult.ACCEPT) {
// we should visit the children if we have ids (all or selected) to visit
boolean visitChildren = !context.getSubtreeIdsToVisit(this).isEmpty();
if (visitChildren) {
// visit the component facets
UIComponent facet = selectFacet();
if(facet!=null) {
try {
if(facet.visitTree(context, callback)) {
return true;
}
} finally {
unselectFacet();
}
}
}
}
return false;
}
}