📄 abstractcomponent.java
字号:
/* AbstractComponent.java{{IS_NOTE Purpose: Description: History: Mon May 30 21:49:42 2005, Created by tomyeh}}IS_NOTECopyright (C) 2005 Potix Corporation. All Rights Reserved.{{IS_RIGHT This program is distributed under GPL Version 2.0 in the hope that it will be useful, but WITHOUT ANY WARRANTY.}}IS_RIGHT*/package org.zkoss.zk.ui;import java.util.Iterator;import java.util.ListIterator;import java.util.List;import java.util.AbstractSequentialList;import java.util.LinkedList;import java.util.Collection;import java.util.Collections;import java.util.Map;import java.util.HashMap;import java.io.Writer;import java.io.IOException;import org.zkoss.lang.D;import org.zkoss.lang.Objects;import org.zkoss.lang.Strings;import org.zkoss.util.CollectionsX;import org.zkoss.util.logging.Log;import org.zkoss.zk.mesg.MZk;import org.zkoss.zk.ui.event.EventListener;import org.zkoss.zk.ui.event.Events;import org.zkoss.zk.ui.ext.RawId;import org.zkoss.zk.ui.ext.render.Transparent;import org.zkoss.zk.ui.ext.render.ZidRequired;import org.zkoss.zk.ui.sys.ExecutionCtrl;import org.zkoss.zk.ui.sys.ExecutionsCtrl;import org.zkoss.zk.ui.sys.ComponentCtrl;import org.zkoss.zk.ui.sys.ComponentsCtrl;import org.zkoss.zk.ui.sys.PageCtrl;import org.zkoss.zk.ui.sys.DesktopCtrl;import org.zkoss.zk.ui.sys.SessionCtrl;import org.zkoss.zk.ui.sys.WebAppCtrl;import org.zkoss.zk.ui.sys.UiEngine;import org.zkoss.zk.ui.sys.Variables;import org.zkoss.zk.ui.util.Namespace;import org.zkoss.zk.ui.impl.Serializables;import org.zkoss.zk.ui.impl.bsh.BshNamespace;import org.zkoss.zk.ui.metainfo.Milieu;import org.zkoss.zk.ui.metainfo.AnnotationMap;import org.zkoss.zk.ui.metainfo.AnnotationMapImpl;import org.zkoss.zk.ui.metainfo.Annotation;import org.zkoss.zk.ui.metainfo.ComponentDefinition;import org.zkoss.zk.ui.metainfo.PageDefinition;import org.zkoss.zk.ui.metainfo.LanguageDefinition;import org.zkoss.zk.ui.metainfo.ComponentDefinitionMap;import org.zkoss.zk.ui.metainfo.DefinitionNotFoundException;import org.zkoss.zk.au.AuResponse;import org.zkoss.zk.au.AuClientInfo;/** * A skeletal implementation of {@link Component}. Though it is OK * to implement Component from scratch, this class simplifies some of * the chores. * * @author tomyeh */public class AbstractComponentimplements Component, ComponentCtrl, java.io.Serializable { private static final Log log = Log.lookup(AbstractComponent.class); private static final long serialVersionUID = 20060622L; /* Note: if _page != null, then _desktop != null, vice versa. */ private transient Desktop _desktop; private transient Page _page; private String _id; private String _uuid; private Milieu _mill; private transient Component _parent; /** The mold (default: "default"). */ private String _mold = "default"; private List _children = new LinkedList(); private transient List _modChildren; /** The info of the ID space, or null if IdSpace is NOT implemented. */ private transient SpaceInfo _spaceInfo; private transient Map _attrs; //don't create it dynamically because _ip bind it at constructor /** A map of event listener: Map(evtnm, EventListener)). */ private transient Map _listeners; /** A map of annotations. Serializable since a component might have * its own annotations. */ private AnnotationMapImpl _annots; /** The extra controls. */ private transient Object _xtrl; /** A set of children being added. It is used only to speed up * the performance when adding a new child. And, cleared after added. * <p>To save footprint, we don't use Set (since it is rare to contain * more than one) */ private transient List _newChildren; /** Used when user is modifying the children by Iterator. */ private transient boolean _modChildByIter; /** Whether this component is visible. */ private boolean _visible = true; /** Constructs a component with auto-generated ID. */ protected AbstractComponent() { final Execution exec = Executions.getCurrent(); _mill = Milieu.getCurrent(); if (_mill != null) Milieu.setCurrent(null); //to avoid mis-use else { final ComponentDefinition compdef = getDefinition(exec, getClass()); if (compdef != null) _mill = compdef.getMilieu(); else _mill = Milieu.DUMMY; } init(false); _uuid = _id = exec != null ? nextUuid(exec.getDesktop()): ComponentsCtrl.AUTO_ID_PREFIX; //though it doesn't belong to any desktop yet, we autogen uuid //it is optional but it is slightly better (of course, subjective) _spaceInfo = this instanceof IdSpace ? new SpaceInfo(this, _uuid): null; if (D.ON && log.debugable()) log.debug("Create comp: "+this); } /** Generates the next UUID for the specified desktop. */ private static final String nextUuid(Desktop desktop) { final StringBuffer sb = new StringBuffer(12) .append(ComponentsCtrl.AUTO_ID_PREFIX); Strings.encode(sb, ((DesktopCtrl)desktop).getNextId()); return sb.toString(); } private static final ComponentDefinition getDefinition(Execution exec, Class cls) { if (exec != null) { final ExecutionCtrl execCtrl = (ExecutionCtrl)exec; final PageDefinition pgdef = execCtrl.getCurrentPageDefinition(); final Page page = execCtrl.getCurrentPage(); final ComponentDefinition compdef = pgdef != null ? pgdef.getComponentDefinition(cls, true): page.getComponentDefinition(cls, true); if (compdef != null) return compdef; return getDefinitionByClientType(exec.getDesktop().getClientType(), cls); } for (Iterator it = LanguageDefinition.getClientTypes().iterator(); it.hasNext();) { final ComponentDefinition compdef = getDefinitionByClientType((String)it.next(), cls); if (compdef != null) return compdef; } return null; } private static final ComponentDefinition getDefinitionByClientType(String clientType, Class cls) { for (Iterator it = LanguageDefinition.getByClientType(clientType).iterator(); it.hasNext();) { final LanguageDefinition ld = (LanguageDefinition)it.next(); try { return ld.getComponentDefinition(cls); } catch (DefinitionNotFoundException ex) { //ignore } } return null; } /** Initialize for contructor and serialization. * @param cloning whether this method is called by clone() */ private void init(boolean cloning) { _xtrl = newExtraCtrl(); _modChildren = new AbstractSequentialList() { public int size() { return _children.size(); } public ListIterator listIterator(int index) { return new ChildIter(index); } }; _newChildren = new LinkedList(); if (!cloning) _attrs = new HashMap(7); } /** Adds to the ID spaces, if any, when ID is changed. * Caller has to make sure the uniqueness. */ private static void addToIdSpaces(final Component comp) { if (comp instanceof IdSpace) ((AbstractComponent)comp).bindToIdSpace(comp); final IdSpace is = getSpaceOwnerOfParent(comp); if (is instanceof Component) ((AbstractComponent)is).bindToIdSpace(comp); else if (is != null) ((PageCtrl)is).addFellow(comp); } private static final IdSpace getSpaceOwnerOfParent(Component comp) { final Component parent = comp.getParent(); if (parent != null) return parent.getSpaceOwner(); else return comp.getPage(); } /** Removes from the ID spaces, if any, when ID is changed. */ private static void removeFromIdSpaces(final Component comp) { final String compId = comp.getId(); if (ComponentsCtrl.isAutoId(compId)) return; //nothing to do if (comp instanceof IdSpace) ((AbstractComponent)comp).unbindFromIdSpace(compId); final IdSpace is = getSpaceOwnerOfParent(comp); if (is instanceof Component) ((AbstractComponent)is).unbindFromIdSpace(compId); else if (is != null) ((PageCtrl)is).removeFellow(comp); } /** Checks the uniqueness in ID space when changing ID. */ private static void checkIdSpaces(final Component comp, String newId) { if (comp instanceof IdSpace && ((AbstractComponent)comp)._spaceInfo.fellows.containsKey(newId)) throw new UiException("Not unique in the ID space of "+comp); final IdSpace is = getSpaceOwnerOfParent(comp); if (is instanceof Component) { if (((AbstractComponent)is)._spaceInfo.fellows.containsKey(newId)) throw new UiException("Not unique in the ID space of "+is); } else if (is != null) { if (((PageCtrl)is).hasFellow(newId)) throw new UiException("Not unique in the ID space of "+is); } } /** Adds its descendants to the ID space when parent or page is changed, * excluding comp. */ private static void addToIdSpacesDown(Component comp) { final IdSpace is = getSpaceOwnerOfParent(comp); if (is instanceof Component) addToIdSpacesDown(comp, (Component)is); else if (is != null) addToIdSpacesDown(comp, (PageCtrl)is); } private static void addToIdSpacesDown(Component comp, Component owner) { if (!ComponentsCtrl.isAutoId(comp.getId())) ((AbstractComponent)owner).bindToIdSpace(comp); if (!(comp instanceof IdSpace)) for (Iterator it = comp.getChildren().iterator(); it.hasNext();) addToIdSpacesDown((Component)it.next(), owner); //recursive } private static void addToIdSpacesDown(Component comp, PageCtrl owner) { if (!ComponentsCtrl.isAutoId(comp.getId())) owner.addFellow(comp); if (!(comp instanceof IdSpace)) for (Iterator it = comp.getChildren().iterator(); it.hasNext();) addToIdSpacesDown((Component)it.next(), owner); //recursive } /** Adds its descendants to the ID space when parent or page is changed, * excluding comp. */ private static void removeFromIdSpacesDown(Component comp) { final IdSpace is = getSpaceOwnerOfParent(comp); if (is instanceof Component) removeFromIdSpacesDown(comp, (Component)is); else if (is != null) removeFromIdSpacesDown(comp, (PageCtrl)is); } private static void removeFromIdSpacesDown(Component comp, Component owner) { final String compId = comp.getId(); if (!ComponentsCtrl.isAutoId(compId)) ((AbstractComponent)owner).unbindFromIdSpace(compId); if (!(comp instanceof IdSpace)) for (Iterator it = comp.getChildren().iterator(); it.hasNext();) removeFromIdSpacesDown((Component)it.next(), owner); //recursive } private static void removeFromIdSpacesDown(Component comp, PageCtrl owner) { if (!ComponentsCtrl.isAutoId(comp.getId())) owner.removeFellow(comp); if (!(comp instanceof IdSpace)) for (Iterator it = comp.getChildren().iterator(); it.hasNext();) removeFromIdSpacesDown((Component)it.next(), owner); //recursive } /** Checks the uniqueness in ID space when changing parent. */ private static void checkIdSpacesDown(Component comp, Component newparent) { final IdSpace is = newparent.getSpaceOwner(); if (is instanceof Component) checkIdSpacesDown(comp, ((AbstractComponent)is)._spaceInfo); else if (is != null) checkIdSpacesDown(comp, (PageCtrl)is); } /** Checks comp and its descendants for the specified SpaceInfo. */ private static void checkIdSpacesDown(Component comp, SpaceInfo si) { final String compId = comp.getId(); if (!ComponentsCtrl.isAutoId(compId) && si.fellows.containsKey(compId)) throw new UiException("Not unique in the new ID space: "+compId); if (!(comp instanceof IdSpace)) for (Iterator it = comp.getChildren().iterator(); it.hasNext();) checkIdSpacesDown((Component)it.next(), si); //recursive } /** Checks comp and its descendants for the specified page. */ private static void checkIdSpacesDown(Component comp, PageCtrl pageCtrl) { final String compId = comp.getId(); if (!ComponentsCtrl.isAutoId(compId) && pageCtrl.hasFellow(compId)) throw new UiException("Not unique in the ID space of "+pageCtrl+": "+compId); if (!(comp instanceof IdSpace)) for (Iterator it = comp.getChildren().iterator(); it.hasNext();) checkIdSpacesDown((Component)it.next(), pageCtrl); //recursive } /** Bind comp to this ID space (owned by this component). * Called only if IdSpace is implemented. */ private void bindToIdSpace(Component comp) { final String compId = comp.getId(); //assert D.OFF || !ComponentsCtrl.isAutoId(compId): "Auto ID shall be ignored: "+compId; _spaceInfo.fellows.put(compId, comp); if (Variables.isValid(compId)) _spaceInfo.ns.setVariable(compId, comp, true); } /** Unbind comp from this ID space (owned by this component). * Called only if IdSpace is implemented. */ private void unbindFromIdSpace(String compId) { _spaceInfo.fellows.remove(compId); if (Variables.isValid(compId)) _spaceInfo.ns.unsetVariable(compId); } //-- Extra utlities --// /** Returns the mold URI based on {@link #getMold} * and the molds defined in the component definition * ({@link ComponentDefinition}). * * <p>Used usually for component implementation. */ protected String getMoldURI() { return _mill.getMoldURI(this, getMold()); } /** Returns the initial parameter in int, or 0 if not found. * An initial parameter is a parameter defined with the * component's definition {@link ComponentDefinition}. * * <p>It evaluates before returning, if it is an EL expression. * * <p>Used usually for component implementation. */ protected int getIntInitParam(String name) { final Integer v; final Object o = _mill.getParameter(this, name); if (o instanceof Integer) { v = (Integer)o; } else if (o != null) { v = Integer.valueOf(Objects.toString(o)); } else { v = new Integer(0); } return v.intValue(); } /** Returns the initial parameter, or null if not found. * An initial parameter is a parameter defined with the * component's definition {@link ComponentDefinition}. * * <p>It evaluates before returning, if it is an EL expression. * * <p>Used usually for component implementation. */ protected String getInitParam(String name) { return Objects.toString(_mill.getParameter(this, name)); } /** Returns the UI engine based on {@link #_desktop}. * Don't call this method when _desktop is null. */ private final UiEngine getThisUiEngine() { return ((WebAppCtrl)_desktop.getWebApp()).getUiEngine(); } /** Returns the UI engine of the current execution, or null if no current * execution. */ private static final UiEngine getCurrentUiEngine() { final Execution exec = Executions.getCurrent(); return exec != null ? ((WebAppCtrl)exec.getDesktop().getWebApp()).getUiEngine(): null; } //-- Component --// public final Page getPage() { return _page; } public final Desktop getDesktop() { return _desktop; } /** Sets the page that this component belongs to. */ public void setPage(Page page) { if (page == _page) return; if (_parent != null) throw new UiException("Only the parent of a root component can be changed: "+this); if (page != null) { if (page.getDesktop() != _desktop && _desktop != null) throw new UiException("The new page must be in the same desktop: "+page); //Not allow developers to access two desktops simutaneously checkIdSpacesDown(this, (PageCtrl)page); } if (_page != null) removeFromIdSpacesDown(this); addMoved(this, _parent, _page, page); //Not depends on UUID setPage0(page); //UUID might be changed here if (_page != null) addToIdSpacesDown(this); checkRootEvents(null); } /** Calling getUiEngine().addMoved(). */ private static final void addMoved(Component comp, Component oldparent, Page oldpg, Page newpg) { final Desktop dt; if (oldpg != null) dt = oldpg.getDesktop(); else if (newpg != null) dt = newpg.getDesktop(); else return; ((WebAppCtrl)dt.getWebApp()) .getUiEngine().addMoved(comp, oldparent, oldpg, newpg); } /** Ses the page without fixing IdSpace */ private void setPage0(Page page) { if (page == _page) return; //nothing changed
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -