Created
September 18, 2012 20:28
-
-
Save bleathem/3745648 to your computer and use it in GitHub Desktop.
AbstractTogglePanel - naive visitor impl
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 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.component; | |
import java.io.IOException; | |
import java.util.Iterator; | |
import javax.el.ELException; | |
import javax.el.MethodExpression; | |
import javax.el.ValueExpression; | |
import javax.faces.FacesException; | |
import javax.faces.application.Application; | |
import javax.faces.application.FacesMessage; | |
import javax.faces.component.UIComponent; | |
import javax.faces.component.UIOutput; | |
import javax.faces.component.UpdateModelException; | |
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.ExceptionQueuedEvent; | |
import javax.faces.event.ExceptionQueuedEventContext; | |
import javax.faces.event.FacesEvent; | |
import javax.faces.event.PhaseId; | |
import javax.faces.event.PostValidateEvent; | |
import javax.faces.event.PreValidateEvent; | |
import org.ajax4jsf.model.DataVisitResult; | |
import org.ajax4jsf.model.DataVisitor; | |
import org.richfaces.application.FacesMessages; | |
import org.richfaces.application.MessageFactory; | |
import org.richfaces.application.ServiceTracker; | |
import org.richfaces.cdk.annotations.Attribute; | |
import org.richfaces.cdk.annotations.EventName; | |
import org.richfaces.cdk.annotations.JsfComponent; | |
import org.richfaces.cdk.annotations.JsfRenderer; | |
import org.richfaces.cdk.annotations.Tag; | |
import org.richfaces.cdk.annotations.TagType; | |
import org.richfaces.component.util.MessageUtil; | |
import org.richfaces.context.ExtendedVisitContext; | |
import org.richfaces.context.ExtendedVisitContextMode; | |
import org.richfaces.event.ItemChangeEvent; | |
import org.richfaces.event.ItemChangeListener; | |
import org.richfaces.event.ItemChangeSource; | |
import org.richfaces.log.Logger; | |
import org.richfaces.log.RichfacesLogger; | |
import org.richfaces.renderkit.MetaComponentRenderer; | |
import org.richfaces.renderkit.html.TabRenderer; | |
import org.richfaces.renderkit.util.RendererUtils; | |
import com.google.common.base.Strings; | |
/** | |
* <p>The <rich:togglePanel> component is used as a base for the other switchable components, the | |
* <rich:accordion> component and the <rich:tabPanel> component. It provides an abstract switchable | |
* component without any associated markup. As such, the <rich:togglePanel> component could be customized to | |
* provide a switchable component when neither an accordion component or a tab panel component is appropriate.</p> | |
* | |
* @author akolonitsky | |
*/ | |
@JsfComponent(tag = @Tag(type = TagType.Facelets, handler = "org.richfaces.view.facelets.html.TogglePanelTagHandler"), renderer = @JsfRenderer(type = "org.richfaces.TogglePanelRenderer"), attributes = { | |
"core-props.xml", "events-mouse-props.xml", "i18n-props.xml" }) | |
public abstract class AbstractTogglePanel extends UIOutput implements AbstractDivPanel, ItemChangeSource, | |
MetaComponentResolver, MetaComponentEncoder { | |
public static final String ACTIVE_ITEM_META_COMPONENT = "activeItem"; | |
public static final String COMPONENT_TYPE = "org.richfaces.TogglePanel"; | |
public static final String COMPONENT_FAMILY = "org.richfaces.TogglePanel"; | |
public static final String META_NAME_FIRST = "@first"; | |
public static final String META_NAME_PREV = "@prev"; | |
public static final String META_NAME_NEXT = "@next"; | |
public static final String META_NAME_LAST = "@last"; | |
// TODO What is MessageId ? | |
public static final String UPDATE_MESSAGE_ID = "javax.faces.component.UIInput.UPDATE"; | |
private static final Logger LOG = RichfacesLogger.RENDERKIT.getLogger(); | |
private static final RendererUtils UTILS = RendererUtils.getInstance(); | |
private String submittedActiveItem = null; | |
private enum PropertyKeys { | |
localValueSet, required, valid, immediate, switchType | |
} | |
protected AbstractTogglePanel() { | |
setRendererType("org.richfaces.TogglePanelRenderer"); | |
} | |
// -------------------------------------------------- Editable Value Holder | |
public Object getSubmittedValue() { | |
return this.submittedActiveItem; | |
} | |
public void resetValue() { | |
this.setValue(null); | |
this.setSubmittedValue(null); | |
this.setLocalValueSet(false); | |
this.setValid(true); | |
} | |
public void setSubmittedValue(Object submittedValue) { | |
this.submittedActiveItem = String.valueOf(submittedValue); | |
} | |
public boolean isLocalValueSet() { | |
return (Boolean) getStateHelper().eval(PropertyKeys.localValueSet, false); | |
} | |
public void setLocalValueSet(boolean localValueSet) { | |
getStateHelper().put(PropertyKeys.localValueSet, localValueSet); | |
} | |
public boolean isValid() { | |
return (Boolean) getStateHelper().eval(PropertyKeys.valid, true); | |
} | |
public void setValid(boolean valid) { | |
getStateHelper().put(PropertyKeys.valid, valid); | |
} | |
public boolean isRequired() { | |
return (Boolean) getStateHelper().eval(PropertyKeys.required, false); | |
} | |
/** | |
* <p> | |
* Set the "required field" state for this component. | |
* </p> | |
* | |
* @param required The new "required field" state | |
*/ | |
public void setRequired(boolean required) { | |
getStateHelper().put(PropertyKeys.required, required); | |
} | |
/** | |
* Flag indicating that this component's value must be converted and validated immediately (that is, during Apply Request | |
* Values phase), rather than waiting until Process Validations phase. | |
*/ | |
@Attribute | |
public boolean isImmediate() { | |
return (Boolean) getStateHelper().eval(PropertyKeys.immediate, false); | |
} | |
public void setImmediate(boolean immediate) { | |
getStateHelper().put(PropertyKeys.immediate, immediate); | |
} | |
// ----------------------------------------------------- UIComponent Methods | |
@Override | |
public void encodeBegin(FacesContext context) throws IOException { | |
updateActiveName(getActiveItem()); | |
super.encodeBegin(context); | |
} | |
public String updateActiveName(String activeItemName) { | |
int itemIndex = -1; | |
if (!Strings.isNullOrEmpty(activeItemName)) { | |
itemIndex = getIndexByName(activeItemName); | |
} | |
if (itemIndex < 0) { | |
String firstItemName = getNameByIndex(0); | |
if (firstItemName != null) { | |
setActiveItem(firstItemName); | |
return firstItemName; | |
} | |
} | |
return activeItemName; | |
} | |
/** | |
* <p> | |
* Specialized decode behavior on top of that provided by the superclass. In addition to the standard | |
* <code>processDecodes</code> behavior inherited from {@link javax.faces.component.UIComponentBase}, calls | |
* <code>processValue()</code> if the the <code>immediate</code> property is true; if the component is invalid afterwards or | |
* a <code>RuntimeException</code> is thrown, calls {@link FacesContext#renderResponse}. | |
* </p> | |
* | |
* @throws NullPointerException {@inheritDoc} | |
*/ | |
@Override | |
public void processDecodes(FacesContext context) { | |
if (context == null) { | |
throw new NullPointerException(); | |
} | |
// Skip processing if our rendered flag is false | |
if (!isRendered()) { | |
return; | |
} | |
pushComponentToEL(context, null); | |
final String activeItem = getActiveItemValue(); | |
this.visit(this, new TogglePanelCallback() { | |
@Override | |
public DataVisitResult callback(FacesContext context, TogglePanelCoordinates coords) { | |
AbstractTogglePanelItemInterface item = coords.getItem(); | |
if (item instanceof AbstractTab && (isActiveItem(item, activeItem) || getSwitchType() == SwitchType.client)) { | |
((UIComponent) item).processDecodes(context); | |
} | |
return DataVisitResult.CONTINUE; | |
} | |
}); | |
// Process this component itself | |
try { | |
decode(context); | |
} catch (RuntimeException e) { | |
context.renderResponse(); | |
throw e; | |
} finally { | |
popComponentFromEL(context); | |
} | |
ItemChangeEvent event = createItemChangeEvent(context); | |
if (event != null) { | |
event.queue(); | |
} | |
} | |
/** | |
* <p> | |
* In addition to the standard <code>processValidators</code> behavior inherited from | |
* {@link javax.faces.component.UIComponentBase}, calls <code>processValue()</code> if the <code>immediate</code> property | |
* is false (which is the default); if the component is invalid afterwards, calls {@link FacesContext#renderResponse}. If a | |
* <code>RuntimeException</code> is thrown during validation processing, calls {@link FacesContext#renderResponse} and | |
* re-throw the exception. | |
* </p> | |
* | |
* @throws NullPointerException {@inheritDoc} | |
*/ | |
@Override | |
public void processValidators(FacesContext context) { | |
if (context == null) { | |
throw new NullPointerException(); | |
} | |
// Skip processing if our rendered flag is false | |
if (!isRendered()) { | |
return; | |
} | |
pushComponentToEL(context, null); | |
Application app = context.getApplication(); | |
app.publishEvent(context, PreValidateEvent.class, this); | |
final String activeItem = getActiveItemValue(); | |
this.visit(this, new TogglePanelCallback() { | |
@Override | |
public DataVisitResult callback(FacesContext context, TogglePanelCoordinates coords) { | |
AbstractTogglePanelItemInterface item = coords.getItem(); | |
if (item instanceof AbstractTab && (isActiveItem(item, activeItem) || getSwitchType() == SwitchType.client)) { | |
((UIComponent) item).processValidators(context); | |
} | |
return DataVisitResult.CONTINUE; | |
} | |
}); | |
app.publishEvent(context, PostValidateEvent.class, this); | |
popComponentFromEL(context); | |
} | |
/** | |
* <p> | |
* In addition to the standard <code>processUpdates</code> behavior inherited from | |
* {@link javax.faces.component.UIComponentBase}, calls <code>updateModel()</code>. If the component is invalid afterwards, | |
* calls {@link FacesContext#renderResponse}. If a <code>RuntimeException</code> is thrown during update processing, calls | |
* {@link FacesContext#renderResponse} and re-throw the exception. | |
* </p> | |
* | |
* @throws NullPointerException {@inheritDoc} | |
*/ | |
@Override | |
public void processUpdates(FacesContext context) { | |
if (context == null) { | |
throw new NullPointerException(); | |
} | |
// Skip processing if our rendered flag is false | |
if (!isRendered()) { | |
return; | |
} | |
pushComponentToEL(context, null); | |
final String activeItem = getActiveItemValue(); | |
this.visit(this, new TogglePanelCallback() { | |
@Override | |
public DataVisitResult callback(FacesContext context, TogglePanelCoordinates coords) { | |
AbstractTogglePanelItemInterface item = coords.getItem(); | |
if (item instanceof AbstractTab && (isActiveItem(item, activeItem) || getSwitchType() == SwitchType.client)) { | |
((UIComponent) item).processUpdates(context); | |
} | |
return DataVisitResult.CONTINUE; | |
} | |
}); | |
popComponentFromEL(context); | |
if (!isValid()) { | |
context.renderResponse(); | |
} | |
} | |
/** | |
* @throws NullPointerException {@inheritDoc} | |
*/ | |
@Override | |
public void decode(FacesContext context) { | |
if (context == null) { | |
throw new NullPointerException(); | |
} | |
// Force validity back to "true" | |
setValid(true); | |
super.decode(context); | |
} | |
public void updateModel(FacesContext context) { | |
if (context == null) { | |
throw new NullPointerException(); | |
} | |
if (!isValid() || !isLocalValueSet()) { | |
return; | |
} | |
ValueExpression ve = getValueExpression("value"); | |
if (ve == null) { | |
return; | |
} | |
Throwable caught = null; | |
FacesMessage message = null; | |
try { | |
ve.setValue(context.getELContext(), getLocalValue()); | |
setValue(null); | |
setLocalValueSet(false); | |
} catch (ELException e) { | |
caught = e; | |
String messageStr = e.getMessage(); | |
Throwable result = e.getCause(); | |
while (null != result && result.getClass().isAssignableFrom(ELException.class)) { | |
messageStr = result.getMessage(); | |
result = result.getCause(); | |
} | |
if (messageStr == null) { | |
message = ServiceTracker.getService(MessageFactory.class).createMessage(context, FacesMessage.SEVERITY_ERROR, | |
FacesMessages.UIINPUT_UPDATE, MessageUtil.getLabel(context, this)); | |
} else { | |
message = new FacesMessage(FacesMessage.SEVERITY_ERROR, messageStr, messageStr); | |
} | |
setValid(false); | |
} catch (Exception e) { | |
caught = e; | |
// message = MessageFactory.getMessage(context, UPDATE_MESSAGE_ID, | |
// MessageFactory.getHeader(context, this)); | |
setValid(false); | |
} | |
if (caught != null) { | |
assert message != null; | |
@SuppressWarnings({ "ThrowableInstanceNeverThrown" }) | |
UpdateModelException toQueue = new UpdateModelException(message, caught); | |
ExceptionQueuedEventContext eventContext = new ExceptionQueuedEventContext(context, toQueue, this, | |
PhaseId.UPDATE_MODEL_VALUES); | |
context.getApplication().publishEvent(context, ExceptionQueuedEvent.class, eventContext); | |
} | |
} | |
private ItemChangeEvent createItemChangeEvent(FacesContext context) { | |
if (context == null) { | |
throw new NullPointerException(); | |
} | |
// Submitted value == null means "the component was not submitted at all". | |
String activeItem = getSubmittedActiveItem(); | |
if (activeItem == null) { | |
return null; | |
} | |
String previous = (String) getValue(); | |
if (previous == null || !previous.equalsIgnoreCase(activeItem)) { | |
UIComponent prevComp = null; | |
UIComponent actvComp = null; | |
if (previous != null) { | |
prevComp = (UIComponent) getItem(previous); | |
} | |
if (activeItem != null) { | |
actvComp = (UIComponent) getItem(activeItem); | |
} | |
return new ItemChangeEvent(this, previous, prevComp, activeItem, actvComp); | |
} | |
return null; | |
} | |
@Override | |
public void queueEvent(FacesEvent event) { | |
if ((event instanceof ItemChangeEvent) && (event.getComponent() == this)) { | |
setEventPhase((ItemChangeEvent) event); | |
} | |
super.queueEvent(event); | |
} | |
protected void setEventPhase(ItemChangeEvent event) { | |
if (isImmediate() | |
|| (event.getNewItem() != null && RendererUtils.getInstance().isBooleanAttribute(event.getNewItem(), | |
"immediate"))) { | |
event.setPhaseId(PhaseId.APPLY_REQUEST_VALUES); | |
} else { | |
event.setPhaseId(PhaseId.UPDATE_MODEL_VALUES); | |
} | |
} | |
protected void setEventPhase(FacesEvent event) { | |
if (isImmediate()) { | |
event.setPhaseId(PhaseId.APPLY_REQUEST_VALUES); | |
} else { | |
event.setPhaseId(PhaseId.INVOKE_APPLICATION); | |
} | |
} | |
@Override | |
public void broadcast(FacesEvent event) throws AbortProcessingException { | |
FacesContext context = FacesContext.getCurrentInstance(); | |
if (event instanceof ItemChangeEvent) { | |
setValue(((ItemChangeEvent) event).getNewItemName()); | |
setSubmittedActiveItem(null); | |
if (event.getPhaseId() == PhaseId.UPDATE_MODEL_VALUES) { | |
try { | |
updateModel(context); | |
} catch (RuntimeException e) { | |
context.renderResponse(); | |
throw e; | |
} | |
} else { | |
context.renderResponse(); | |
} | |
} | |
super.broadcast(event); | |
} | |
// -------------------------------------------------- Panel Items Managing | |
@Override | |
public String getFamily() { | |
return COMPONENT_FAMILY; | |
} | |
@Override | |
public boolean getRendersChildren() { | |
return true; | |
} | |
private String getActiveItemValue() { | |
String value = getActiveItem(); | |
if (value == null) { | |
value = getSubmittedActiveItem(); | |
} | |
return value; | |
} | |
protected boolean isActiveItem(UIComponent kid) { | |
return isActiveItem(kid, getActiveItemValue()); | |
} | |
protected boolean isActiveItem(UIComponent kid, String value) { | |
if (kid == null || ! (kid instanceof AbstractTogglePanelItemInterface)) { | |
return false; | |
} | |
return isActiveItem((AbstractTogglePanelItemInterface) kid, value); | |
} | |
protected boolean isActiveItem(AbstractTogglePanelItemInterface item, String value) { | |
if (item == null || value == null) { | |
return false; | |
} | |
return item.getName().equals(value); | |
} | |
public TogglePanelCoordinates visit(final AbstractTogglePanel panel, final TogglePanelCallback callback) { | |
int count = 0; | |
for (UIComponent child : panel.getChildren()) { | |
if (child.isRendered()) { | |
if (child instanceof AbstractTogglePanelItemInterface) { | |
AbstractTogglePanelItemInterface item = (AbstractTogglePanelItemInterface) child; | |
TogglePanelCoordinates coords = new TogglePanelCoordinates(item.getName(), count, item, true); | |
if (callback.callback(getFacesContext(), coords) == DataVisitResult.STOP) { | |
return coords; | |
} else { | |
count++; | |
} | |
} else if (child instanceof UISequence) { | |
final UISequence sequence = (UISequence) child; | |
final int[] countBox = {count}; | |
final TogglePanelCoordinates[] coordBox = new TogglePanelCoordinates[1]; | |
final String[] nameBox = {""}; | |
DataVisitor visitor = new DataVisitor() { | |
public DataVisitResult process(FacesContext context, Object rowKey, Object argument) { | |
sequence.setRowKey(context, rowKey); | |
if (sequence.isRowAvailable()) { | |
if (sequence.getChildCount() > 0) { | |
for (UIComponent child : sequence.getChildren()) { | |
if ((child.isRendered()) && child instanceof AbstractTogglePanelItemInterface) { | |
AbstractTogglePanelItemInterface item = (AbstractTogglePanelItemInterface) child; | |
TogglePanelCoordinates coords = new TogglePanelCoordinates(item.getName(), countBox[0], item, false); | |
if (callback.callback(context, coords) == DataVisitResult.STOP) { | |
coordBox[0] = coords; | |
return DataVisitResult.STOP; | |
} else { | |
countBox[0]++; | |
} | |
} | |
} | |
} | |
} | |
return DataVisitResult.CONTINUE; | |
} | |
}; | |
FacesContext context = getFacesContext(); | |
try { | |
sequence.walk(context, visitor, null); | |
} finally { | |
sequence.setRowKey(context, null); | |
} | |
if (coordBox[0] != null) { | |
return coordBox[0]; | |
} | |
count = countBox[0]; | |
} | |
} | |
} | |
return new TogglePanelCoordinates(null, count, null, false); | |
} | |
private TogglePanelCoordinates getCoordsByIndex(final int index) { | |
TogglePanelCoordinates coords = visit(this, new TogglePanelCallback() { | |
@Override | |
public DataVisitResult callback(FacesContext context, TogglePanelCoordinates coords) { | |
if (index == coords.getCount()) { | |
return DataVisitResult.STOP; | |
} | |
else { | |
return DataVisitResult.CONTINUE; | |
} | |
} | |
}); | |
return coords; | |
} | |
public TogglePanelCoordinates getCoordsByName(final String name) { | |
TogglePanelCoordinates coords = visit(this, new TogglePanelCallback() { | |
@Override | |
public DataVisitResult callback(FacesContext context, TogglePanelCoordinates coords) { | |
if (name.equals(coords.getName())) { | |
return DataVisitResult.STOP; | |
} | |
else { | |
return DataVisitResult.CONTINUE; | |
} | |
} | |
}); | |
return coords; | |
} | |
public AbstractTogglePanelItemInterface getItemByIndex(final int index) { | |
TogglePanelCoordinates coords = getCoordsByIndex(index); | |
if (! coords.isConcrete()) { | |
LOG.warn("Warning, calling getItemByIndex on a dynamically generated TogglePanel can result in unpredictable behavior"); | |
} | |
return coords.getItem(); | |
} | |
public String getNameByIndex(final int index) { | |
if (! this.isRendered()) { | |
return null; | |
} | |
return getCoordsByIndex(index).getName(); | |
} | |
public int getIndexByName(final String name) { | |
if (! this.isRendered()) { | |
return -1; | |
} | |
TogglePanelCoordinates coords = getCoordsByName(name); | |
if (coords.getName() != null) { | |
return coords.getCount(); | |
} else { | |
return -1; | |
} | |
} | |
public int getItemCount() { | |
if (! this.isRendered()) { | |
return 0; | |
} | |
TogglePanelCoordinates coords = visit(this, new TogglePanelCallback() { | |
@Override | |
public DataVisitResult callback(FacesContext context, TogglePanelCoordinates coords) { | |
return DataVisitResult.CONTINUE; | |
} | |
}); | |
return coords.getCount(); | |
} | |
public AbstractTogglePanelItemInterface getItem(String name) { | |
if (META_NAME_FIRST.equals(name)) { | |
return getFirstItem(); | |
} else if (META_NAME_PREV.equals(name)) { | |
return getPrevItem(); | |
} else if (META_NAME_NEXT.equals(name)) { | |
return getNextItem(); | |
} else if (META_NAME_LAST.equals(name)) { | |
return getLastItem(); | |
} else { | |
return getItemByIndex(getChildIndex(name)); | |
} | |
} | |
public AbstractTogglePanelItemInterface getFirstItem() { | |
return getItemByIndex(0); | |
} | |
public AbstractTogglePanelItemInterface getPrevItem() { | |
return getPrevItem(getActiveItem()); | |
} | |
public AbstractTogglePanelItemInterface getPrevItem(String name) { | |
return getItemByIndex(getIndexByName(name) - 1); | |
} | |
public AbstractTogglePanelItemInterface getNextItem() { | |
return getNextItem(getActiveItem()); | |
} | |
public AbstractTogglePanelItemInterface getNextItem(String name) { | |
return getItemByIndex(getIndexByName(name) + 1); | |
} | |
public AbstractTogglePanelItemInterface getLastItem() { | |
return getItemByIndex(getItemCount()); | |
} | |
@Deprecated | |
public int getChildIndex(String name) { | |
if (name == null) { | |
throw new IllegalArgumentException("Name is required parameter."); | |
} | |
return getIndexByName(name); | |
} | |
// ------------------------------------------------ | |
public String getSubmittedActiveItem() { | |
return submittedActiveItem; | |
} | |
public void setSubmittedActiveItem(String submittedActiveItem) { | |
this.submittedActiveItem = submittedActiveItem; | |
} | |
// ------------------------------------------------ Properties | |
@Override | |
@Attribute(hidden = true) | |
public void setValue(Object value) { | |
super.setValue(value); | |
setLocalValueSet(true); | |
} | |
/** | |
* Holds the active panel name. This name is a reference to the name identifier of the active child | |
* <rich:togglePanelItem> component. | |
*/ | |
@Attribute | |
public String getActiveItem() { | |
return (String) getValue(); | |
} | |
public void setActiveItem(String value) { | |
setValue(value); | |
} | |
@Override | |
public void setValueExpression(String name, ValueExpression binding) { | |
if ("activeItem".equals(name)) { | |
super.setValueExpression("value", binding); | |
} else { | |
super.setValueExpression(name, binding); | |
} | |
} | |
/** | |
* The switch mode when a panel is activated. One of: "client", "server", "ajax". Default: "ajax" | |
*/ | |
@Attribute(generate = false) | |
public SwitchType getSwitchType() { | |
SwitchType switchType = (SwitchType) getStateHelper().eval(PropertyKeys.switchType); | |
if (switchType == null) { | |
switchType = SwitchType.DEFAULT; | |
} | |
return switchType; | |
} | |
public void setSwitchType(SwitchType switchType) { | |
getStateHelper().put(PropertyKeys.switchType, switchType); | |
} | |
@Attribute(hidden = true) | |
public abstract boolean isLimitRender(); | |
/** | |
* Applicable when cycling through the tabs. If "true", then when the last tab is active, cycling to next will activate the | |
* first tab, if "false", cycling to next will have not effect. The inverse applies for the first tab, and cycling to | |
* previous. Whether to Default: false | |
*/ | |
@Attribute | |
public abstract boolean isCycledSwitching(); | |
@Attribute(hidden = true) | |
public abstract Object getData(); | |
@Attribute(hidden = true) | |
public abstract String getStatus(); | |
@Attribute(hidden = true) | |
public abstract Object getExecute(); | |
@Attribute(hidden = true) | |
public abstract Object getRender(); | |
/** | |
* Occurs on the server side when an item is changed through Ajax using the server mode | |
*/ | |
@Attribute | |
public abstract MethodExpression getItemChangeListener(); | |
/** | |
* The client-side script method to be called after the item is changed. | |
*/ | |
@Attribute(events = @EventName("itemchange")) | |
public abstract String getOnitemchange(); | |
/** | |
* The client-side script method to be called before the item is changed. | |
*/ | |
@Attribute(events = @EventName("beforeitemchange")) | |
public abstract String getOnbeforeitemchange(); | |
// ------------------------------------------------ Event Processing Methods | |
public void addItemChangeListener(ItemChangeListener listener) { | |
addFacesListener(listener); | |
} | |
public ItemChangeListener[] getItemChangeListeners() { | |
return (ItemChangeListener[]) getFacesListeners(ItemChangeListener.class); | |
} | |
public void removeItemChangeListener(ItemChangeListener listener) { | |
removeFacesListener(listener); | |
} | |
public String resolveClientId(FacesContext facesContext, UIComponent contextComponent, String metaComponentId) { | |
if (ACTIVE_ITEM_META_COMPONENT.equals(metaComponentId)) { | |
return getClientId(facesContext) + MetaComponentResolver.META_COMPONENT_SEPARATOR_CHAR + metaComponentId; | |
} | |
return null; | |
} | |
public String substituteUnresolvedClientId(FacesContext facesContext, UIComponent contextComponent, String metaComponentId) { | |
return null; | |
} | |
public void encodeMetaComponent(FacesContext context, String metaComponentId) throws IOException { | |
((MetaComponentRenderer) getRenderer(context)).encodeMetaComponent(context, this, metaComponentId); | |
} | |
@Override | |
public boolean visitTree(VisitContext context, VisitCallback callback) { | |
if (!isVisitable(context)) { | |
return false; | |
} | |
FacesContext facesContext = context.getFacesContext(); | |
pushComponentToEL(facesContext, null); | |
try { | |
VisitResult result = context.invokeVisitCallback(this, callback); | |
if (result == VisitResult.COMPLETE) { | |
return true; | |
} | |
if (result == VisitResult.ACCEPT) { | |
if (context instanceof ExtendedVisitContext) { | |
ExtendedVisitContext extendedVisitContext = (ExtendedVisitContext) context; | |
if (extendedVisitContext.getVisitMode() == ExtendedVisitContextMode.RENDER) { | |
result = extendedVisitContext.invokeMetaComponentVisitCallback(this, callback, | |
ACTIVE_ITEM_META_COMPONENT); | |
if (result == VisitResult.COMPLETE) { | |
return true; | |
} | |
} | |
} | |
} | |
if (result == VisitResult.ACCEPT) { | |
Iterator<UIComponent> kids = this.getFacetsAndChildren(); | |
while (kids.hasNext()) { | |
boolean done = kids.next().visitTree(context, callback); | |
if (done) { | |
return true; | |
} | |
} | |
} | |
} finally { | |
popComponentFromEL(facesContext); | |
} | |
return false; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment