org.zkoss.zk.ui.metainfo.ShadowInfo Maven / Gradle / Ivy
/** ShadowInfo.java.
Purpose:
Description:
History:
3:04:11 PM Oct 23, 2014, Created by jumperchen
Copyright (C) 2014 Potix Corporation. All Rights Reserved.
*/
package org.zkoss.zk.ui.metainfo;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.zkoss.util.resource.Location;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Page;
import org.zkoss.zk.ui.UiException;
import org.zkoss.zk.ui.ext.DynamicTag;
import org.zkoss.zk.ui.sys.ComponentsCtrl;
import org.zkoss.zk.ui.util.ConditionImpl;
/**
* Represent a shadow element.
* @author jumperchen
* @since 8.0.0
*/
public class ShadowInfo extends BranchInfo {
private ComponentDefinition _compdef;
/** A list of {@link Property}, or null if no property at all. */
private List _props;
private final String _tag;
/** the annotation map. Note: it doesn't include what are defined in _compdef. */
private AnnotationMap _annots;
//F80 - store subtree's binder annotation count
private boolean _hasBindingAnnotation = false;
private boolean _isAnnotationNamespacedRoot = false;
/** Creates a shadow.
*
* @param parent the parent node (never null)
* @param compdef the component definition; never null
* @param tag the tag name; Note: if component implements
* {@link DynamicTag}, this argument must be specified.
* If {@link DynamicTag} is not implemented, this argument is optional.
*/
public ShadowInfo(NodeInfo parent, ComponentDefinition compdef, String tag, ConditionImpl cond) {
super(parent, cond);
_tag = tag;
if (compdef == null)
throw new IllegalArgumentException();
_compdef = compdef;
}
/** Returns the annotation map defined in this info, or null
* if no annotation is ever defined.
*/
public AnnotationMap getAnnotationMap() {
return _annots;
}
/** Applies the event handlers and properties to the specified component.
*
* It also invokes {@link ComponentDefinition#applyProperties}.
*
*
Note: annotations are applied to the component when a component
* is created. So, this method doesn't and need not to copy them.
* See also {@link org.zkoss.zk.ui.AbstractComponent#AbstractComponent}.
*
*/
public void applyProperties(Component comp) {
_compdef.applyProperties(comp);
}
/** Adds an annotation to the specified property of this component
* info.
*
* @param propName the property name.
* If null, the annotation is associated with the whole component rather than
* a particular property.
* @param annotName the annotation name (never null, nor empty).
* @param annotAttrs a map of attributes, or null if no attribute at all.
* The attribute must be in a pair of strings (String name, String value),
* or (String name, String[] value).
* @param loc the location information of the annotation in
* the document, or null if not available.
*/
public void addAnnotation(String propName, String annotName, Map annotAttrs, Location loc) {
if (_annots == null)
_annots = new AnnotationMap();
_annots.addAnnotation(propName, annotName, annotAttrs, loc);
}
/** Applies the custom attributes.
* Note: this method does nothing if {@link #isEffective} returns false.
*/
public void apply(Component comp) {
if (_props != null && isEffective(comp)) {
for (Property prop : _props) {
prop.assign(comp);
}
}
}
/** Creates a shadow element based on this info (never null).
* It is the same as newInstance(page, null).
*
*
If the implementation class doesn't have any EL expression,
* or its EL expression doesn't have reference to the self variable,
* the result is the same.
*
*
This method is preserved for backward compatibility.
* It is better to use {@link #newInstance(Page, Component)}.
*/
public Component newInstance(Page page) {
return newInstance(page, null);
}
/** Creates an component based on this info (never null).
*
*
Like {@link ComponentDefinition#newInstance},
* this method doesn't invoke {@link #applyProperties}.
* It is caller's job to invoke them if necessary.
* Since the value of properties might depend on the component tree,
* it is better to assign the component with a proper parent
* before calling {@link #applyProperties}.
*
*/
public Component newInstance(Page page, Component parent) {
ComponentsCtrl.setCurrentInfo(this);
final Component comp;
try {
comp = _compdef.newInstance(page, null); // use the default one
} catch (Exception ex) {
throw UiException.Aide.wrap(ex);
} finally {
ComponentsCtrl.setCurrentInfo((ComponentInfo) null);
}
return comp;
}
/** Returns the language definition that {@link #getComponentDefinition}
* belongs to, or null if the component definition is temporary.
*/
public LanguageDefinition getLanguageDefinition() {
return _compdef.getLanguageDefinition();
}
/** Returns the component definition, or null if it is PageDefinition.
*/
public ComponentDefinition getComponentDefinition() {
return _compdef;
}
/** Returns a readonly list of properties ({@link Property}) (never null).
*/
public List getProperties() {
if (_props != null)
return _props;
return Collections.emptyList();
//it is better to protect with Collections.unmodifiableList
//but for better performance...
}
/** Adds a property initializer.
* It will initialize a component when created with this info.
* @param name the member name. The component must have a valid setter
* for it.
* @param value the value. It might contain expressions (${}).
*/
public void addProperty(String name, String value, ConditionImpl cond) {
if (name == null || name.length() == 0)
throw new IllegalArgumentException("name cannot be empty");
if (_props == null)
_props = new LinkedList();
_props.add(new Property(_evalr, name, value, cond));
}
/** Adds a child.
*
* @exception IllegalStateException if this is not an instance of
* {@link TemplateInfo} and {@link ShadowInfo}.
*/
public void appendChild(NodeInfo child) {
if (!((child instanceof ShadowInfo) || (child instanceof TemplateInfo)))
throw new IllegalStateException("Only accept template and shadow element to be a child of " + this);
super.appendChild(child);
}
//Object//
public String toString() {
final StringBuffer sb = new StringBuffer(40).append("[shadow element(").append(_tag).append(")");
if (_props != null)
for (Property name : _props)
sb.append(' ').append(name.getName());
return sb.append(']').toString();
}
//F80 - store subtree's binder annotation count
public boolean hasBindingAnnotation() {
return _hasBindingAnnotation;
}
public void enableBindingAnnotation() {
this._hasBindingAnnotation = true;
}
public void disableBindingAnnotation() {
this._hasBindingAnnotation = false;
}
/**
* @return whether this ShadowInfo is the first ShadowInfo that has annotation namespace or binding annotation.
* @since 8.5.2
*/
public boolean isAnnotationNamespacedRoot() {
return _isAnnotationNamespacedRoot;
}
/**
* Sets whether this ShadowInfo is the first ShadowInfo that has annotation namespace or binding annotation.
* @param annotationNamespacedRoot
* @since 8.5.2
*/
public void setAnnotationNamespacedRoot(boolean annotationNamespacedRoot) {
_isAnnotationNamespacedRoot = annotationNamespacedRoot;
}
}