/* ComponentCtrl.java
Purpose:
Description:
History:
Mon May 30 21:06:56 2005, Created by tomyeh
Copyright (C) 2005 Potix Corporation. All Rights Reserved.
{{IS_RIGHT
This program is distributed under LGPL Version 2.1 in the hope that
it will be useful, but WITHOUT ANY WARRANTY.
}}IS_RIGHT
*/
package org.zkoss.zk.ui.sys;
import java.io.IOException;
import java.io.Writer;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.zkoss.zk.au.AuRequest;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Page;
import org.zkoss.zk.ui.ShadowElement;
import org.zkoss.zk.ui.WrongValueException;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.ext.Scope;
import org.zkoss.zk.ui.metainfo.Annotation;
import org.zkoss.zk.ui.metainfo.ComponentDefinition;
import org.zkoss.zk.ui.metainfo.DefinitionNotFoundException;
import org.zkoss.zk.ui.metainfo.EventHandler;
import org.zkoss.zk.ui.metainfo.EventHandlerMap;
import org.zkoss.zk.ui.metainfo.ZScript;
import org.zkoss.zk.ui.util.Callback;
/**
* An addition interface to {@link Component}
* that is used for implementation or tools.
*
* <p>Application developers rarely need to access methods in this interface.
*
* @author tomyeh
*/
public interface ComponentCtrl {
/** Sets the component definition.
*
* <p>The component definition affects how a component behaves.
* Developers rarely need to call this method. If a wrong definition
* is assigned,
* the result is unpredictable (and hard to debug). It is mainly designed
* for developing tools.
*
* @exception IllegalArgumentException if compdef is null
*/
public void setDefinition(ComponentDefinition compdef);
/** Sets the component definition by specifying the name.
*
* @param defname the name of the component definition
* @exception IllegalArgumentException if defname is null
* @exception DefinitionNotFoundException if the component definition not found
* @since 5.0.0
*/
public void setDefinition(String defname);
/** Called before adding a child.
* If a component accepts only certain types of children, it shall
* override this method and throw an exception for an illegal child.
*
* @param child the child to be added (never null).
* @param insertBefore another child component that the new child
* will be inserted before it. If null, the new child will be the
* last child.
* @since 3.6.2
*/
public void beforeChildAdded(Component child, Component insertBefore);
/** Called before removing a child.
* If a component denies a certain child to be removed, it shall
* override this method to avoid it.
*
* @param child the child to be removed (never null)
* @since 3.6.2
*/
public void beforeChildRemoved(Component child);
/** Called before changing the parent.
* If a component can be a child of certain parents, it shall override
* this method and throws an exception for an illegal parent.
*
* @param parent the new parent. If null, it means detachment.
* @since 3.6.2
*/
public void beforeParentChanged(Component parent);
/** Called when a child is added.
* If a component want to optimize the update, it might do something
* different. Otherwise, it does nothing.
*
* <p>Note: {@link #onChildAdded} is called in the request-processing
* phase.
*
* <p>It is not a good idea to throw an exception in this method, since
* it is in the middle of modifying the component tree.
* @since 3.5.0
*/
public void onChildAdded(Component child);
/** Called when a child is removed.
* If a component want to optimize the update, it might do something
* different. Otherwise, it simply does nothing.
*
* <p>It is not a good idea to throw an exception in this method, since
* it is in the middle of modifying the component tree.
* @since 3.5.0
*/
public void onChildRemoved(Component child);
/** Called when this component is attached to a page.
*
* <p>If a component is moved from one page to another,
* {@link #onPageAttached} is called with both pages.
* Note: {@link #onPageDetached} is not called in this case.
*
* <p>Note: this method is called even if the component is attached
* to a page implicitly thru, say, {@link Component#setParent}.
*
* <p>It is not a good idea to throw an exception in this method, since
* it is in the middle of modifying the component tree.
*
* @param newpage the new page (never null).
* @param oldpage the previous page, if any, or null if it didn't
* belong to any page.
* @since 3.5.0
*/
public void onPageAttached(Page newpage, Page oldpage);
/** Called when this component is detached from a page.
*
* <p>If a component is moved from one page to another,
* {@link #onPageAttached} is called with both pages.
* Note: {@link #onPageDetached} is not called in this case.
* In other words, {@link #onPageDetached} is called only if a component
* is detached from a page (not belong to any other page).
*
* <p>Note: this method is called even if the component is detached
* to a page implicitly thru, say, {@link Component#setParent}.
*
* <p>It is not a good idea to throw an exception in this method, since
* it is in the middle of modifying the component tree.
*
* @param page the previous page (never null)
* @since 3.5.0
*/
public void onPageDetached(Page page);
/** Returns the event listener of the specified name, or null
* if not found.
* @see Component#getWidgetListener
*/
public ZScript getEventHandler(String evtnm);
/** Adds an event handler.
* Note: it is OK to add multiple event handlers to the same event.
* They are evaluated one-by-one.
* On the other hand, {@link Component#setWidgetListener} will
* overwrite the previous listener if the event name is the same.
* @see Component#setWidgetListener
*/
public void addEventHandler(String name, EventHandler evthd);
/** Adds a map of event handlers which is shared by other components.
* In other words, this component shall have all event handlers
* defined in the specified map, evthds. Meanwhile, this component
* shall not modify evthds, since it is shared.
* The caller shall not change annots after the invocation, too
*
* @param evthds a map of event handler
* @see Component#setWidgetListener
*/
public void addSharedEventHandlerMap(EventHandlerMap evthds);
/** Returns a readonly collection of event names (String), or
* an empty collection if no event name is registered.
*
* @see Component#getWidgetListenerNames
* @since 3.0.2
*/
public Set<String> getEventHandlerNames();
/** Returned by {@link #getClientEvents} to indicate the event is important
* and the client must send it back even if no listener is registered.
*/
public static final int CE_IMPORTANT = 0x0001;
/** Returned by {@link #getClientEvents} to indicate the event is
* no deferrable, i.e., the event has to be sent back immediately.
* It is meaningful only used with {@link #CE_IMPORTANT}
*/
public static final int CE_NON_DEFERRABLE = 0x0002;
/** Returned by {@link #getClientEvents} to indicate the event
* can be ignored by the server when the server is busy.
*/
public static final int CE_BUSY_IGNORE = 0x1000;
/** Returned by {@link #getClientEvents} to indicate the event
* can be ignored by the server when the server receives the same AU
* requests but not processed yet.
* In other words, the server will remove the duplicate AU requests
* if it was queued.
*/
public static final int CE_DUPLICATE_IGNORE = 0x2000;
/** Returned by {@link #getClientEvents} to indicate the event
* an be ignored by the server when the server receives consecutive
* AU requests. In other words, the server will remove the first request
* if it receives an event listed in this map consecutively.
*/
public static final int CE_REPEAT_IGNORE = 0x4000;
/** Returns a map of event information that the client might send to this component.
* The key of the returned map is a String instance representing the event name,
* and the value an integer representing the flags
* (a combination of {@link #CE_IMPORTANT}, {@link #CE_BUSY_IGNORE},
* {@link #CE_DUPLICATE_IGNORE} and {@link #CE_REPEAT_IGNORE}).
* <p>Default: return the collection of events
* added by {@link #getClientEvents}.
*
* @since 5.0.0
*/
public Map<String, Integer> getClientEvents();
/** @deprecated As of release 6.0.0, replaced with
* {@link #getAnnotation(String, String)}.
*/
public Annotation getAnnotation(String annotName);
/** Returns the annotation associated with the definition of the specified
* property, or null if not available.
*
* <p>If there are multiple annotation with the given name,
* this method will merge them before return. If you prefer to get all
* of them without merging, please use {@link #getAnnotations(String, String)} instead.
* For example,
* <pre><code><textbox value="@bind(abc, param1=foo1) @bind(xyz, param2=foo2)"></code></pre>
*
* <p>This method will return a single annotation with three attributes:
* value=xyz, param1=foo1 and param2=foo2. On the other hand,
* {@link #getAnnotations(String, String)} will return a two-element
* collections.
*
* <p>Notice that the property is <t>not</t> limited the 'real' property.
* For example, the following statement is correct though
* <code>button</code> doesn't have <code>setFoo</code> method.
* And, you can retrieve it by use of this method (<code>getAnnotation("foo", "bind")</code>)
*
* <pre><code><button foo="@bind(whatever=123)"/></code></pre>
*
* <p>Furthermore, you can declare it as <code>custom-attribute</code>.
* For example, the following is equivalent to the above.
*
* <pre><code><button>
* <custom-attribute foo="@bind(whatever=123}">
*</button></code></pre>
*
* @param propName the property name, e.g., "value".
* If null, this method returns the annotation(s) associated with this
* component (rather than a particular property).
* @param annotName the annotation name
* @see #getAnnotations(String, String)
*/
public Annotation getAnnotation(String propName, String annotName);
/** Returns the annotations associated with the definition of the specified
* property. It never returns null.
*
* <p>Notice that the property is <t>not</t> limited the 'real' property.
* For example, the following statement is correct though
* <code>button</code> doesn't have <code>setFoo</code> method.
* And, you can retrieve it by use of this method (<code>getAnnotation("foo", "bind")</code>)
*
* <pre><code><button foo="@bind(whatever=123)"/></code></pre>
*
* <p>Furthermore, you can declare it as <code>custom-attribute</code>.
* For example, the following is equivalent to the above.
*
* <pre><code><button>
* <custom-attribute foo="@bind(whatever=123}">
*</button></code></pre>
*
* @param propName the property name, e.g., "value".
* If null, this method returns the annotation(s) associated with this
* component (rather than a particular property).
* @param annotName the annotation name
* @see #getAnnotation(String, String)
* @since 6.0.0
*/
public Collection<Annotation> getAnnotations(String propName, String annotName);
/** @deprecated As of release 6.0.0, replaced with {@link #getAnnotations(String)}.
*/
public Collection<Annotation> getAnnotations();
/** Returns a read-only collection of all annotations ({@link Annotation})
* associated with the specified property. It never returns null.
*
* @param propName the property name, e.g., "value".
* If null, this method returns the annotation(s) associated with this
* component (rather than a particular property).
*/
public Collection<Annotation> getAnnotations(String propName);
/** Returns a read-only list of the names of the properties
* that are associated with the specified annotation (never null).
*/
public List<String> getAnnotatedPropertiesBy(String annotName);
/** Returns a read-only list of the name of properties that
* are associated at least one annotation (never null).
*/
public List<String> getAnnotatedProperties();
/** @deprecated As of release 6.0.0, replaced with
* {@link #addAnnotation(String, String, Map)}
*/
public void addAnnotation(String annotName, Map<String, String[]> annotAttrs);
/** Adds an annotation to the specified property of this component.
*
* <p>If the given property is null, the annotation is associated
* to this component, rather than a particular property.
*
* <p>Unlike Java, you can add annotations dynamically, and each component
* has its own annotations.
*
* @param propName the property name.
* If null, the annotation is associated with the 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.
* This method will make a copy of <code>annotAttrs</code>, so the caller
* can use it after the invocation.
*/
public void addAnnotation(String propName, String annotName, Map<String, String[]> annotAttrs);
/** Notification that the session, which owns this component,
* is about to be passivated (a.k.a., serialized).
*
* <p>Note: only root components are notified by this method.
*/
public void sessionWillPassivate(Page page);
/** Notification that the session, which owns this component,
* has just been activated (a.k.a., deserialized).
*
* <p>Note: only root components are notified by this method.
*/
public void sessionDidActivate(Page page);
/** Returns the extra controls that tell ZK how to handle this component
* specially.
*
* <p>Application developers need NOT to access this method.
*
* <p>There are a set of extra controls: org.zkoss.zk.ui.ext.render.
*
* <p>The first package is used if the content of a component can be changed
* by the user at the client. It is so-called the client controls.
*
* <p>The second package is used to control how to render a component
* specially.
*
* <p>Override this method only if you want to return the extra
* controls.
*
* @return null if no special handling required. If the component
* requires some special controls, it could return an object that
* implements one or several interfaces in the org.zkoss.zk.ui.ext.render
* package.
* For example, {@link org.zkoss.zk.ui.ext.render.Cropper}.
*/
public Object getExtraCtrl();
/**
* Returns the corresponding property access object from the given property
* name, if any.
* @param prop the name of the property
* @return null it means not to support for the property name.
* @since 8.0.0
*/
public PropertyAccess getPropertyAccess(String prop);
/** Notifies that an {@link WrongValueException} instance is thrown,
* and {@link WrongValueException#getComponent} is the component
* causing the exception.
* It is a callback and the component can store the error message,
* show up the custom information, or even 'eat' the exception.
*
* @param ex the exception being thrown (never null)
* @return the exception to throw, or null to ignore the exception
* In most cases, just return ex
* @since 2.4.0
*/
public WrongValueException onWrongValue(WrongValueException ex);
/** Render (a.k.a., redraw) this component and all its descendants.
*
* <p>It is called in the redrawing phase by the kernel, so it is too late
* to call {@link Component#invalidate()},
* {@link org.zkoss.zk.ui.AbstractComponent#smartUpdate}
* or {@link org.zkoss.zk.ui.AbstractComponent#response} in this method.
* @since 5.0.0
*/
public void redraw(Writer out) throws IOException;
/** Handles an AU request.
*
* <p>Notice: don't invoke this method directly. Rather, invoke
* {@link DesktopCtrl#service(AuRequest, boolean)} instead.
* This method is designed to be overridden.
*
* <p>To send responses to the client, use
* {@link org.zkoss.zk.ui.AbstractComponent#smartUpdate},
* {@link org.zkoss.zk.ui.AbstractComponent#response}
* or {@link Component#invalidate()}.
* To handle the AU requests sent from the client, override this
* method.
*
* <p>Application developer can plug the custom service to handle
* the AU request by calling {@link Component#setAuService}.
*
* @param everError whether any error ever occurred before
* processing this request.
* @since 5.0.0
* @see Component#setAuService
*/
public void service(AuRequest request, boolean everError);
/** Handles an event.
* This method will invoke the event handlers registered in a ZUML page,
* the event listeners registered in Java, and the event handlers
* declared as part of the component.
*
* @param event the event to handle
* @param scope the scope to evaluate the zscript, if any.
* (see also {@link Page#interpret}.
* @since 6.0.0
*/
public void service(Event event, Scope scope) throws Exception;
/** Sets whether to disable the update of the client widgets of
* this component and its descendants.
* <p>By default, if a component is attached to a page, modifications that
* change the visual representation will be sent to the client to
* ensure the consistency.
* <p>Though rarely needed, you can disable the synchronization of
* the visual representation, if you prefer to update the client in a batch
*or the modification is caused by the client.
* <p><b>Notice</b>:
* <ul>
* <li>Once disabled, it not only affects the synchronization of
* this component but also all its descendants.</li>
* <li>The disable remains until the end of this execution
* (or the invocation of this method with false). In other words,
* it is enabled automatically in the next execution.</li>
* <li>The updates, if any, before calling this method will still be sent
* to the client.</li>
* <li>It does nothing, if there is no current execution.</li>
* </ul>
*
* <p>Also notice that, with {@link Component#invalidate},
* it is easy to synchronize the content of a component
* (and its descendants) to the client.
*
* @return whether it has been disabled before this invocation, i.e.,
* the previous disable status
* @since 3.6.2
*/
public boolean disableClientUpdate(boolean disable);
/** Returns the map of event handlers and listeners defined in this component.
* This method is rarely used, but it is useful if you'd like to retrieve
* the behavior of the event handling of this component (and if you don't
* have the reference to the component)
* @since 6.0.0
*/
public EventListenerMap getEventListenerMap();
/**
* Returns a set of shadow elements, if any.
* @since 8.0.0
*/
public <T extends ShadowElement> List<T> getShadowRoots();
/**
* Removes the given shadow root from this host. (Shadow developer use only)
* @param shadow a shadow element
* @return true if child is removed successfully; false if it doesn't
* have the specified child
* @since 8.0.0
*/
public boolean removeShadowRoot(ShadowElement shadow);
/**
* Adds the given shadow root from this host. (Shadow developer use only)
* @param shadow a shadow element
* @return true if child is added successfully
* @since 8.0.0
*/
public boolean addShadowRoot(ShadowElement shadow);
/**
* Adds the given shadow root from this host. (Shadow developer use only)
* @param shadow a shadow element
* @param insertBefore the shadow before which you want the new child
* @return true if child is added successfully
* @since 8.0.0
*/
public boolean addShadowRootBefore(ShadowElement shadow, ShadowElement insertBefore);
/**
* Set to enable the component with binding annotation. (Internal or component developer use only.)
* @since 8.0.0
*/
public void enableBindingAnnotation();
/**
* Set to disable the component with binding annotation. (Internal or component developer use only.)
* @since 8.0.0
*/
public void disableBindingAnnotation();
/**
* Returns whether the component itself has binding annotation or not. (Internal or component developer use only.)
* @return true if the component itself has binding annotation
* @since 8.0.0
*/
public boolean hasBindingAnnotation();
/**
* Returns whether the component and its children have binding annotation or not. (Internal or component developer use only.)
* @return true if the component and its children have binding annotation
* @since 8.0.0
*/
public boolean hasSubBindingAnnotation();
/**
* Returns the count of the component's subtree binding annotation. (Internal or component developer use only.)
* @return 0 if the component and its children have no binding annotation , more than 0 if they have binding annotation
* @since 8.0.0
*/
public int getSubBindingAnnotationCount();
/**
* Adds a callback at component redraw phase.
* @param callback
* @since 8.0.0
* @deprecated as of release 8.0.2, use {@link #addCallback} with specific name "redraw"
*/
public boolean addRedrawCallback(Callback<ContentRenderer> callback);
/**
* Removes a callback for component redraw phase.
* @param callback
* @since 8.0.0
* @deprecated as of release 8.0.2, use {@link #removeCallback} with specific name "redraw"
*/
public boolean removeRedrawCallback(Callback<ContentRenderer> callback);
/**
* Returns all of callbacks for component redraw phase
* @since 8.0.0
* @deprecated as of release 8.0.2, use {@link #getCallback} with specific name "redraw"
*/
public Collection<Callback<ContentRenderer>> getRedrawCallback();
/**
* Adds a callback at component in specific name
* @param name
* @param callback
* @since 8.0.2
*/
public boolean addCallback(String name, Callback callback);
/**
* Removes a callback for component by specific name.
* @param name
* @param callback
* @since 8.0.2
*/
public boolean removeCallback(String name, Callback callback);
/**
* Returns all of callbacks by specific name
* @param name
* @since 8.0.2
*/
public Collection<Callback> getCallback(String name);
/**
* Returns the shadow element under this shadow host.
* @param id
* @return ShadowElement or null
* @since 8.0.1
*/
public ShadowElement getShadowFellowIfAny(String id);
}