/**
* License Agreement.
*
* JBoss RichFaces - Ajax4jsf Component Library
*
* Copyright (C) 2007 Exadel, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation.
*
* This library 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 library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package org.richfaces.component;
import java.io.IOException;
import java.util.Iterator;
import java.util.Map;
import javax.faces.application.Application;
import javax.faces.component.NamingContainer;
import javax.faces.component.UIComponent;
import javax.faces.component.UIOutput;
import javax.faces.context.FacesContext;
import javax.faces.el.MethodBinding;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.FacesEvent;
import javax.faces.event.FacesListener;
import javax.faces.event.PhaseId;
import javax.faces.model.DataModel;
import org.ajax4jsf.component.AjaxComponent;
import org.ajax4jsf.component.UIDataAdaptor;
import org.ajax4jsf.event.AjaxEvent;
import org.ajax4jsf.model.DataComponentState;
import org.ajax4jsf.model.DataVisitor;
import org.ajax4jsf.model.ExtendedDataModel;
import org.ajax4jsf.model.Range;
import org.ajax4jsf.renderkit.AjaxRendererUtils;
import org.ajax4jsf.renderkit.RendererUtils;
import org.apache.commons.collections.iterators.SingletonIterator;
import org.richfaces.component.events.TreeEvents;
import org.richfaces.component.state.TreeState;
import org.richfaces.component.state.events.CollapseAllCommandEvent;
import org.richfaces.component.state.events.CollapseNodeCommandEvent;
import org.richfaces.component.state.events.ExpandAllCommandEvent;
import org.richfaces.component.state.events.ExpandNodeCommandEvent;
import org.richfaces.component.state.events.TreeStateCommandEvent;
import org.richfaces.event.DragEvent;
import org.richfaces.event.DragListener;
import org.richfaces.event.DropEvent;
import org.richfaces.event.DropListener;
import org.richfaces.event.NodeExpandedEvent;
import org.richfaces.event.NodeExpandedListener;
import org.richfaces.event.NodeSelectedEvent;
import org.richfaces.event.NodeSelectedListener;
import org.richfaces.event.TreeListenerEventsProducer;
import org.richfaces.model.AbstractTreeDataModel;
import org.richfaces.model.StackingTreeModel;
import org.richfaces.model.StackingTreeModelProvider;
import org.richfaces.model.TreeDataModel;
import org.richfaces.model.TreeModelVisualComponentProvider;
import org.richfaces.model.TreeNode;
import org.richfaces.model.TreeRange;
import org.richfaces.model.TreeRowKey;
import org.richfaces.model.VisualStackingTreeModel;
/**
* @author igels Component class providing tree ADT behaviuor
*/
public abstract class UITree extends UIDataAdaptor implements
TreeListenerEventsProducer, Draggable, Dropzone, AjaxComponent {
public static final String COMPONENT_TYPE = "org.richfaces.Tree";
public static final String COMPONENT_FAMILY = "org.richfaces.Tree";
public final static String PRESERVE_MODEL_STATE = "state";
public final static String PRESERVE_MODEL_REQUEST = "request";
public final static String PRESERVE_MODEL_NONE = "none";
public final static String SWITCH_SERVER = "server";
public final static String SWITCH_CLIENT = "client";
public final static String SWITCH_AJAX = "ajax";
public final static String SELECTED_NODE_PARAMETER_NAME = NamingContainer.SEPARATOR_CHAR
+ "selectedNode";
public static final String SELECTION_INPUT_ATTRIBUTE = "_selectionInput";
public final static String DEFAULT_SELECTED_CSS_CLASS = "dr-tree-i-sel";
public final static String DEFAULT_HIGHLIGHTED_CSS_CLASS = "dr-tree-i-hl";
private UITreeNode defaultFacet;
/**
* Name of EL variable for the tree node. This reference is needed to
* let this parent class know about the attributes defined in the
* subclass
*/
private String _treeNodeVar;
/**
* Stored state of "treeNodeVar" attribute
*/
private Object treeNodeVarOrigValue = null;
public UITree() {
super();
DecodesPhaseNotifiyingListener
.registerListenerInstance(getFacesContext());
}
public boolean getRendersChildren() {
return true;
}
/**
* Get name of EL variable for the tree node.
*
* @return the varState
*/
public String getTreeNodeVar() {
return _treeNodeVar;
}
/**
* Set the name of EL variable
*
* @param treeNodeVar the varStatus to set
*/
public void setTreeNodeVar(String treeNodeVar) {
this._treeNodeVar = treeNodeVar;
}
/**
* Lazily creates default node representation that is used if there is
* no {@link UITreeNode} child for that nodeFace
*
* @return created or existing node representation component
*/
protected UITreeNode getOrCreateDefaultFacet() {
if (defaultFacet == null) {
FacesContext facesContext = FacesContext.getCurrentInstance();
Application application = facesContext.getApplication();
defaultFacet = (UITreeNode) application
.createComponent(UITreeNode.COMPONENT_TYPE);
defaultFacet.setId("_defaultNodeFace");
defaultFacet.setParent(this);
defaultFacet.getAttributes().put(
UITreeNode.DEFAULT_NODE_FACE_ATTRIBUTE_NAME, Boolean.TRUE);
defaultFacet.getChildren().add(
createDefaultNodeFaceOutput(facesContext));
}
return defaultFacet;
}
/**
* Return the data object representing the node for the currently
* selected row key, if any
*
* @return {@link TreeNode} instance corresponding to the current row key
*/
public TreeNode getTreeNode() {
return ((AbstractTreeDataModel) getExtendedDataModel()).getTreeNode();
}
public abstract boolean isImmediate();
public abstract void setImmediate(boolean immediate);
private FacesEvent wrapTreeEvent(FacesEvent facesEvent) {
if (facesEvent.getSource() == this) {
return new IndexedEvent(this, facesEvent, getRowKey());
}
return facesEvent;
}
public void queueEvent(FacesEvent event) {
FacesEvent resultEvent = event;
if (event instanceof NodeExpandedEvent) {
if (isImmediate()) {
event.setPhaseId(PhaseId.APPLY_REQUEST_VALUES);
} else {
event.setPhaseId(PhaseId.INVOKE_APPLICATION);
}
resultEvent = wrapTreeEvent(event);
} else if (event instanceof NodeSelectedEvent) {
if (isImmediate()) {
event.setPhaseId(PhaseId.APPLY_REQUEST_VALUES);
} else {
event.setPhaseId(PhaseId.UPDATE_MODEL_VALUES);
}
resultEvent = wrapTreeEvent(event);
} else if (event instanceof TreeStateCommandEvent) {
FacesContext context = FacesContext.getCurrentInstance();
boolean afterDecodesPhase = null != context
.getExternalContext()
.getRequestMap()
.get(
DecodesPhaseNotifiyingListener.DECODE_PHASE_NOTICE_NAME);
if (isImmediate() && !afterDecodesPhase) {
event.setPhaseId(PhaseId.APPLY_REQUEST_VALUES);
} else {
event.setPhaseId(PhaseId.INVOKE_APPLICATION);
}
} else if (event instanceof DragEvent || event instanceof DropEvent) {
if (isImmediate()) {
event.setPhaseId(PhaseId.APPLY_REQUEST_VALUES);
} else {
event.setPhaseId(PhaseId.INVOKE_APPLICATION);
}
}
super.queueEvent(resultEvent);
}
/**
* Locates {@link UITreeNode} instance that has type equal to current
* nodeFace. Default nodeFace is declared as #{var.type} by default where
* var is "var" attribute value Calls <code>getOrCreateDefaultFacet()</code>
* if none found.
*
* @see UITree#getOrCreateDefaultFacet()
* @return {@link UITreeNode} representing current nodeFace
*/
public UITreeNode getNodeFacet() {
String facetName = this.getNodeFace();
if (facetName != null) {
if (getChildCount() > 0) {
Iterator iterator = getChildren().iterator();
while (iterator.hasNext()) {
Object object = iterator.next();
if (object instanceof UITreeNode) {
UITreeNode treeNode = (UITreeNode) object;
if (!treeNode.isRendered()) {
continue;
}
if (facetName.equals(treeNode.getType())) {
return treeNode;
}
}
}
}
} else {
UIComponent component = null;
ExtendedDataModel dataModel = getExtendedDataModel();
if (dataModel instanceof TreeModelVisualComponentProvider) {
TreeModelVisualComponentProvider componentProvider = (TreeModelVisualComponentProvider) dataModel;
component = componentProvider.getComponent();
}
if (component == null) {
component = this;
}
if (component.isRendered() && component.getChildCount() > 0) {
Iterator iterator = component.getChildren().iterator();
while (iterator.hasNext()) {
UIComponent child = (UIComponent) iterator.next();
if (child instanceof UITreeNode) {
UITreeNode treeNode = (UITreeNode) child;
if (!treeNode.isRendered()) {
continue;
}
if (treeNode.getType() != null) {
continue;
}
return treeNode;
}
}
}
}
return getOrCreateDefaultFacet();
}
/**
* Setup EL variable for different iteration. Value of row tree node is
* put into request scope attributes with name "treeNodeVar" bean
* property. All other attributes are processed in parent
* <code>UIDataAdaptor</code> class
*
* @param faces - current faces context
* @param localModel - reference to data model
* @param rowSelected - boolean flag indicating whether the row is selected
*/
protected void setupVariable(FacesContext faces, DataModel localModel, boolean rowSelected) {
super.setupVariable(faces, localModel, rowSelected);
// get the map storing the request scope
// attributes
Map attrs = faces.getExternalContext().getRequestMap();
String treeNodeVar = getTreeNodeVar();
if (rowSelected) {
// Current row tree node.
if (treeNodeVar != null) {
attrs.put(treeNodeVar, getTreeNode());
}
} else {
if (treeNodeVar != null) {
attrs.remove(treeNodeVar);
}
}
}
/*
* (non-Javadoc)
*
* @see org.ajax4jsf.ajax.repeat.UIDataAdaptor#resetDataModel()
*/
public void resetDataModel() {
super.resetDataModel();
TreeState state = (TreeState) getComponentState();
// transfer nodes delayed to open to rendering queue
state.transferQueuedNodes();
// re-set stopInCollapsed to handle AJAX switch type change
state.setStopInCollapsed(isStopInCollapsed());
setExtendedDataModel(createDataModel(false));
}
public void walk(FacesContext faces, DataVisitor visitor)
throws IOException {
walk(faces, visitor, null);
}
/**
* Walks through model or some subset of it if rowKey is not null
*
* @param faces
* {@link FacesContext} instance
* @param visitor
* {@link UIDataAdaptor.ComponentVisitor} instance
* @param range
* {@link Range} range instance
* @param rowKey
* row key to start from or null to start
* from root
* @param argument
* implementation-specific visitor argument
* @throws IOException
*/
public void walk(FacesContext faces, DataVisitor visitor, Range range,
Object rowKey, Object argument) throws IOException {
Object savedRowKey = getRowKey();
try {
AbstractTreeDataModel dataModel = (AbstractTreeDataModel) getExtendedDataModel();
dataModel.walk(faces, visitor, range, rowKey,
argument,
false/*faces.getExternalContext().getRequestParameterMap().get(
getBaseClientId(faces) + LAST_ELEMENT_FLAG) != null*/);
} finally {
try {
setRowKey(faces, savedRowKey);
} catch (Exception e) {
faces.getExternalContext().log(e.getMessage(), e);
}
}
}
/**
* Walks through backing data model if current data model has one. Cached
* data models usually have one. This method is typically used for acquiring
* new data when some nodes has changed their state
*
* @param faces
* {@link FacesContext} instance
* @param visitor
* {@link UIDataAdaptor.ComponentVisitor} instance
* @param range
* {@link Range} range instance
* @param rowKey
* row key to start from or null to start
* from root
* @param argument
* implementation-specific visitor argument
* @throws IOException
*/
public void walkModel(FacesContext faces, DataVisitor visitor, Range range,
Object key, Object argument) throws IOException {
AbstractTreeDataModel extendedDataModel = (AbstractTreeDataModel) getExtendedDataModel();
extendedDataModel.walkModel(faces, visitor,
(TreeRange) range, key, argument,
false);
}
public String getSelectionStateInputName(FacesContext context) {
return getBaseClientId(context) + NamingContainer.SEPARATOR_CHAR
+ "input";
}
/*
* (non-Javadoc)
*
* @see org.ajax4jsf.ajax.repeat.UIDataAdaptor#processDecodes(javax.faces.context.FacesContext)
*/
public void processDecodes(FacesContext faces) {
if (!this.isRendered())
return;
Map requestParameterMap = faces.getExternalContext().getRequestParameterMap();
if (requestParameterMap.get(getBaseClientId(faces)
+ SELECTED_NODE_PARAMETER_NAME) != null) {
getAttributes().put(
SELECTED_NODE_PARAMETER_NAME,
requestParameterMap.get(getBaseClientId(faces)
+ SELECTED_NODE_PARAMETER_NAME));
}
Object selectionInputValue = requestParameterMap
.get(getSelectionStateInputName(faces));
if (selectionInputValue instanceof String) {
getAttributes().put(SELECTION_INPUT_ATTRIBUTE, selectionInputValue);
}
try {
super.processDecodes(faces, null);
if (null != getAttributes().get(SELECTION_INPUT_ATTRIBUTE)) {
TreeState state = (TreeState) getComponentState();
if (!state.isSelected(null)) {
new NodeSelectedEvent(this, state.getSelectedNode()).queue();
}
}
} finally {
getAttributes().remove(SELECTION_INPUT_ATTRIBUTE);
getAttributes().remove(SELECTED_NODE_PARAMETER_NAME);
}
// if (treePersister != null) {
// RequestUtils.setStoredPersister(this
// .getBaseClientId(getFacesContext()),
// this.getFacesContext(), treePersister);
// setExtendedDataModel(new PersistedDataModel(treePersister,
// (AbstractTreeDataModel) getExtendedDataModel()));
// }
}
protected Iterator dataChildren() {
return new SingletonIterator(getNodeFacet());
}
/**
* Returns whether current node is leaf ie. has no children
*
* @return <code>true</code> if current node is leaf else
* <code>false</code>
*/
public boolean isLeaf() {
AbstractTreeDataModel dataModel = (AbstractTreeDataModel) getExtendedDataModel();
return dataModel.isLeaf();
}
/**
* Returns whether current node is expanded
*
* @return <code>true</code> if node is expanded else <code>false</code>
*/
public boolean isExpanded() {
TreeState treeState = (TreeState) getComponentState();
return treeState.isExpanded((TreeRowKey) this.getRowKey());
}
/**
* Returns whether current node is selected
*
* @return <code>true</code> if node is selected else <code>false</code>
*/
public boolean isSelected() {
TreeState treeState = (TreeState) getComponentState();
return treeState.isSelected((TreeRowKey) this.getRowKey());
}
/**
* Sets current node as selected
*/
public void setSelected() {
TreeState treeState = (TreeState) getComponentState();
treeState.setSelected((TreeRowKey) this.getRowKey());
}
protected Iterator fixedChildren() {
return getFacets().values().iterator();
}
protected DataComponentState createComponentState() {
return new TreeState(isStopInCollapsed());
}
/**
* Returns whether switch type is set to "server"
*
* @return <code>true</code> if switch type is "server" else
* <code>false</code>
*/
protected boolean isStopInCollapsed() {
return !SWITCH_CLIENT.equals(getSwitchType());
}
public void broadcast(FacesEvent event) throws AbortProcessingException {
super.broadcast(event);
DataComponentState componentState = getComponentState();
if (componentState instanceof FacesListener) {
FacesListener facesListener = (FacesListener) componentState;
if (event.isAppropriateListener(facesListener)) {
// we can safely open/close nodes here
event.processListener(facesListener);
}
}
if (event instanceof NodeSelectedEvent) {
NodeSelectedEvent selectedEvent = (NodeSelectedEvent) event;
setSelected();
}
// fire node events
TreeEvents.invokeListenerBindings(this, event, getFacesContext());
if (event instanceof AjaxEvent) {
FacesContext facesContext = getFacesContext();
AjaxRendererUtils.addRegionsFromComponent(this, facesContext);
}
}
public boolean hasAjaxSubmitSelection() {
return isAjaxSubmitSelection();
}
/**
* Save current state of data variable. Overrides the implementation in
* the base class for the case the base implementation will be changed.
*/
public void captureOrigValue() {
this.captureOrigValue(FacesContext.getCurrentInstance());
}
/**
* Save current state of data variable.
*
* @param faces current faces context
*/
public void captureOrigValue(FacesContext faces) {
super.captureOrigValue(faces);
String treeNodeVar = getTreeNodeVar();
if (treeNodeVar != null) {
Map attrs = faces.getExternalContext().getRequestMap();
this.treeNodeVarOrigValue = attrs.get(treeNodeVar);
}
}
/**
* Restore value of data variable after processing phase. Overrides the
* implementation in the base class for the case the base implementation
* will be changed.
*/
public void restoreOrigValue() {
this.restoreOrigValue(FacesContext.getCurrentInstance());
}
/**
* Restore value of data variable after processing phase.
*
* @param faces current faces context
*/
public void restoreOrigValue(FacesContext faces) {
super.restoreOrigValue(faces);
String treeNodeVar = getTreeNodeVar();
if (treeNodeVar != null) {
Map attrs = faces.getExternalContext().getRequestMap();
if (this.treeNodeVarOrigValue != null) {
attrs.put(treeNodeVar, this.treeNodeVarOrigValue);
} else {
attrs.remove(treeNodeVar);
}
}
}
private ExtendedDataModel createDataModel(boolean allowCached) {
Object value = this.getValue();
if (value != null) {
TreeDataModel treeDataModel = new TreeDataModel();
treeDataModel.setWrappedData(this.getValue());
if (allowCached && PRESERVE_MODEL_REQUEST.equals(getPreserveModel())) {
treeDataModel = new CacheableTreeDataModel(treeDataModel);
}
return treeDataModel;
} else {
// TODO implement request caching
StackingTreeModel stackingTreeModel = new VisualStackingTreeModel(null);
if (getChildCount() > 0) {
Iterator children = getChildren().iterator();
while (children.hasNext()) {
UIComponent component = (UIComponent) children.next();
if (component instanceof StackingTreeModelProvider) {
StackingTreeModelProvider provider = (StackingTreeModelProvider) component;
stackingTreeModel.addStackingModel(provider.getStackingModel());
}
}
}
return stackingTreeModel;
}
}
public void processUpdates(FacesContext faces) {
super.processUpdates(faces);
if (getExtendedDataModel() instanceof CacheableTreeDataModel) {
setExtendedDataModel(createDataModel(false));
}
}
protected ExtendedDataModel createDataModel() {
return createDataModel(true);
}
/**
* Queues expansion command for node whose row key is equal to rowKey
* parameter
*
* @param rowKey
* of the node to expand
* @throws IOException
*/
public void queueNodeExpand(TreeRowKey rowKey) throws IOException {
new ExpandNodeCommandEvent(this, rowKey).queue();
}
/**
* Queues collapsion command for node whose row key is equal to rowKey
* parameter
*
* @param rowKey
* of the node to expand
* @throws IOException
*/
public void queueNodeCollapse(TreeRowKey rowKey) throws IOException {
new CollapseNodeCommandEvent(this, rowKey).queue();
}
/**
* Queues all node expansion command
*
* @throws IOException
*/
public void queueExpandAll() throws IOException {
new ExpandAllCommandEvent(this).queue();
}
/**
* Queues all node collapsion command
*
* @throws IOException
*/
public void queueCollapseAll() throws IOException {
new CollapseAllCommandEvent(this).queue();
}
public abstract String getSwitchType();
public abstract void setSwitchType(String switchType);
public abstract String getIcon();
public abstract void setIcon(String icon);
public abstract String getIconExpanded();
public abstract void setIconExpanded(String icon);
public abstract String getIconCollapsed();
public abstract void setIconCollapsed(String icon);
public abstract String getIconLeaf();
public abstract void setIconLeaf(String icon);
public abstract void setShowConnectingLines(boolean showConnectingLines);
public abstract boolean isShowConnectingLines();
public abstract void setAjaxSubmitSelection(boolean ajaxSubmitSelection);
public abstract boolean isAjaxSubmitSelection();
public abstract String getPreserveModel();
public abstract void setPreserveModel(String preserveModel);
public abstract void setHighlightedClass(String selectedClass);
public abstract String getHighlightedClass();
public abstract void setSelectedClass(String selectedClass);
public abstract String getSelectedClass();
public abstract void setNodeFace(String nodeFace);
public abstract String getNodeFace();
public abstract void setToggleOnClick(boolean toggleOnClick);
public abstract boolean isToggleOnClick();
public abstract void setStateAdvisor(Object nodeFace);
public abstract Object getStateAdvisor();
public abstract MethodBinding getAdviseNodeOpened();
public abstract void setAdviseNodeOpened(MethodBinding adviseNodeOpened);
public abstract MethodBinding getAdviseNodeSelected();
public abstract void setAdviseNodeSelected(MethodBinding adviseNodeSelected);
public void addChangeExpandListener(NodeExpandedListener listener) {
addFacesListener(listener);
}
public void addNodeSelectListener(NodeSelectedListener listener) {
addFacesListener(listener);
}
public void removeChangeExpandListener(NodeExpandedListener listener) {
removeFacesListener(listener);
}
public void removeNodeSelectListener(NodeSelectedListener listener) {
removeFacesListener(listener);
}
public NodeExpandedListener[] getChangeExpandListeners() {
return (NodeExpandedListener[]) getFacesListeners(NodeExpandedListener.class);
}
public NodeSelectedListener[] getNodeSelectListeners() {
return (NodeSelectedListener[]) getFacesListeners(NodeSelectedListener.class);
}
public void addDropListener(DropListener listener) {
addFacesListener(listener);
}
public DropListener[] getDropListeners() {
return (DropListener[]) getFacesListeners(DropListener.class);
}
public void removeDropListener(DropListener listener) {
removeFacesListener(listener);
}
public void addDragListener(DragListener listener) {
addFacesListener(listener);
}
public DragListener[] getDragListeners() {
return (DragListener[]) getFacesListeners(DragListener.class);
}
public void removeDragListener(DragListener listener) {
removeFacesListener(listener);
}
/**
* Return the data object representing the node data for the contextual row key
*
* @param rowKey contextual row key
* @return data corresponding to the current row key
*/
public Object getRowData(Object rowKey) {
Object storedKey = getRowKey();
FacesContext context = FacesContext.getCurrentInstance();
try {
setRowKey(context, rowKey);
return getRowData();
} finally {
try {
setRowKey(context, storedKey);
} catch (Exception e) {
context.getExternalContext().log(e.getMessage(), e);
}
}
}
/**
* Return the data object representing the node for the contextual row key
*
* @param rowKey contextual row key
* @return {@link TreeNode} instance corresponding to the current row key
*/
public TreeNode getTreeNode(Object rowKey) {
FacesContext context = FacesContext.getCurrentInstance();
Object storedKey = getRowKey();
try {
setRowKey(context, rowKey);
return getTreeNode();
} finally {
try {
setRowKey(context, storedKey);
} catch (Exception e) {
context.getExternalContext().log(e.getMessage(), e);
}
}
}
private UIOutput createDefaultNodeFaceOutput(FacesContext facesContext) {
UIOutput component = new UIOutput() {
public Object getValue() {
return getRowData();
}
public String getId() {
String id = super.getId();
if (id == null) {
//set fixed id to prevent duplicate id exception
id = "_defaultNodeFaceOutput";//FacesContext.getCurrentInstance().getViewRoot()
//.createUniqueId();
setId(id);
}
return id;
}
public void setTransient(boolean transientFlag) {
if (!transientFlag) {
throw new IllegalArgumentException(
"Default representation for node face cannot be set non-persistent!");
}
}
public boolean isTransient() {
return true;
}
};
return component;
}
public Object saveState(FacesContext faces) {
Object[] state = new Object[3];
state[0] = super.saveState(faces);
state[1] = saveAttachedState(faces, defaultFacet);
state[2] = getTreeNodeVar();
return state;
}
public void restoreState(FacesContext faces, Object object) {
Object[] state = (Object[]) object;
super.restoreState(faces, state[0]);
defaultFacet = (UITreeNode) restoreAttachedState(faces, state[1]);
if (defaultFacet != null) {
defaultFacet.getChildren().add(createDefaultNodeFaceOutput(faces));
defaultFacet.setParent(this);
}
setTreeNodeVar((String) state[2]);
}
public String getResolvedDragIndicator(FacesContext facesContext) {
String dragIndicator = getDragIndicator();
if (dragIndicator != null) {
UIComponent indicator = RendererUtils.getInstance().
findComponentFor(this, dragIndicator);
if (indicator != null) {
return indicator.getClientId(facesContext);
}
}
return null;
}
}